diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /fonts/utilities/mm |
Initial commit
Diffstat (limited to 'fonts/utilities/mm')
-rw-r--r-- | fonts/utilities/mm/makefile | 9 | ||||
-rw-r--r-- | fonts/utilities/mm/makeinstance.sh | 70 | ||||
-rw-r--r-- | fonts/utilities/mm/mmafm.c | 493 | ||||
-rw-r--r-- | fonts/utilities/mm/mmfont | 183 | ||||
-rw-r--r-- | fonts/utilities/mm/parseAFM.c | 1226 | ||||
-rw-r--r-- | fonts/utilities/mm/parseAFM.h | 321 | ||||
-rw-r--r-- | fonts/utilities/mm/parseAFMclient.c | 346 |
7 files changed, 2648 insertions, 0 deletions
diff --git a/fonts/utilities/mm/makefile b/fonts/utilities/mm/makefile new file mode 100644 index 0000000000..d05f9726cc --- /dev/null +++ b/fonts/utilities/mm/makefile @@ -0,0 +1,9 @@ +build: + gcc -o mmafm mmafm.c parseAFM.c + +clean: + -rm *.pl *.vpl *.tfm *.vf _min* + +realclean: clean + -rm z* + diff --git a/fonts/utilities/mm/makeinstance.sh b/fonts/utilities/mm/makeinstance.sh new file mode 100644 index 0000000000..8da29c3e5c --- /dev/null +++ b/fonts/utilities/mm/makeinstance.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# +# =================================================================== +# M Goossens, S Rahtz. June 10 1995. revised December 5th 1995, March 1997 +# +# Given a multiple master font, and values for up to 4 design space +# variables (how many, depends on the font), create AFM instances by +# creating normalized weight factors, and applying them to the master +# AFM files. +# +# Procedure: +# 1. create small PS file to invoke MM operators in PostScript +# with right values +# 2. run GhostScript on file to derive normalized weights +# 3. run mmafm program to read master AFM files and write new one +# 4. write map entry and .pro header file +# =================================================================== +#echo "usage makeinstance fontname instancename design-space-variables 1 to 4" +X=$2.control +cat > $$.instance <<FOOBAR +/myfile (myfile) (w) file def +/str 20 string def +/MASTERFONT findfont dup begin [ +V1 V2 V3 V4 NormalizeDesignVector ConvertDesignVector +counttomark 1 sub -1 0 { +index str cvs myfile exch writestring +myfile (\n) writestring} for +myfile closefile +] end +FOOBAR +#----------------------------------- +MASTERFONT="$1" +V1="$3" +V2="$4" +V3="$5" +V4="$6" +sed -e "s/MASTERFONT/$MASTERFONT/" \ + -e "s/V1/$V1/" \ + -e "s/V2/$V2/" \ + -e "s/V3/$V3/" \ + -e "s/V4/$V4/" \ + < $$.instance > $$.ps +rm $$.instance +gs -dNODISPLAY `kpsewhich -format=.pfa $1.PFA` $$.ps quit.ps +rm $$.ps +#---------------------------------- +# +# build control file for mmafm +# +#---------------------------------- +# number of weights +wc -l myfile | awk '{print $1}' > $X +# master AFM file names +cat $1.afmnames >> $X +# new name +echo $2 >> $X +# weights +cat myfile >> $X +#---------------------------------- +rm myfile +mmafm $X | \ + sed -e "/^FontName/s/^FontName .*$/FontName $1-$3-$4-$5-$6/" \ + -e "/^FontName/s/-*$//" > $2.afm +#---------------------------------- +echo "/$2 /$1 findfont dup begin [" > $2.pro +echo " $V1 $V2 $V3 $V4 NormalizeDesignVector ConvertDesignVector" >>$2.pro +echo " ] end makeblendedfont definefont pop " >>$2.pro +#---------------------------------- +exit + diff --git a/fonts/utilities/mm/mmafm.c b/fonts/utilities/mm/mmafm.c new file mode 100644 index 0000000000..dbdc73c8ef --- /dev/null +++ b/fonts/utilities/mm/mmafm.c @@ -0,0 +1,493 @@ +/* + +mmafm.c + +M Goossens, S Rahtz June 10th 1995 + +read multiple master AFM files, apply weight factor +and write instance AFM + +derived from parseAFMclient.c: + * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved. + * + * This file may be freely copied and redistributed as long as: + * 1) This entire notice continues to be included in the file, + * 2) If the file has been modified in any way, a notice of such + * modification is conspicuously indicated. + * + * PostScript, Display PostScript, and Adobe are registered trademarks of + * Adobe Systems Incorporated. +........ + * History: + * original: DSM Thu Oct 20 17:39:59 PDT 1988 + * modified: DSM Mon Jul 3 14:17:50 PDT 1989 + * - added 'storageProblem' check in main + */ + +#define lineterm EOL /* line terminating character */ +#define MAXMM 16 +#include <stdio.h> +#include "parseAFM.h" +static char *ident = NULL; /* storage buffer for keywords */ + + +/*************************** GLOBALS ***************************/ +FontInfo *fi, *otherfi; +FLAGS myflags = 0; + + +/*************************** printGlobals **********************/ + +printGlobals() +{ + printf("StartFontMetrics %s\n", fi->gfi->afmVersion); + printf("FontName %s\n", fi->gfi->fontName); + printf("FullName %s\n", fi->gfi->fullName); + printf("FamilyName %s\n", fi->gfi->familyName); + printf("Weight %s\n", fi->gfi->weight); + printf("ItalicAngle %f\n", fi->gfi->italicAngle); + if (fi->gfi->isFixedPitch) + printf("IsFixedPitch true\n"); + else + printf("IsFixedPitch false\n"); + printf("UnderlinePosition %d\n", fi->gfi->underlinePosition); + printf("UnderlineThickness %d\n", fi->gfi->underlineThickness); + printf("Version %s\n", fi->gfi->version); + printf("FontBBox %d %d %d %d\n", + fi->gfi->fontBBox.llx, fi->gfi->fontBBox.lly, + fi->gfi->fontBBox.urx, fi->gfi->fontBBox.ury); + printf("Notice %s\n", fi->gfi->notice); + printf("EncodingScheme %s\n", fi->gfi->encodingScheme); + printf("CapHeight %d\n", fi->gfi->capHeight); + printf("XHeight %d\n", fi->gfi->xHeight); + printf("Descender %d\n", fi->gfi->descender); + printf("Ascender %d\n", fi->gfi->ascender); + +} /* printGlobals */ + + +/*************************** printCharWidths *********************/ +printCharWidths() +{ + int i = 0; + for (i = 0; i < 256; ++i) + printf(" code: %3d width: %4d\n", i, fi->cwi[i]); + printf("\n"); + +} /* printCharWidths */ + + +/*************************** printAllCharMetrics *****************/ +printAllCharMetrics() +{ + int i = 0; + CharMetricInfo *temp = fi->cmi; + Ligature *node = temp->ligs; + printf("StartCharMetrics %d\n", fi->numOfChars); + for (i = 0; i < fi->numOfChars; ++i) + { + printf( + "C %d ; WX %d ; N %s ; B %d %d %d %d ;", + temp->code, temp->wx, temp->name, temp->charBBox.llx, + temp->charBBox.lly, temp->charBBox.urx, temp->charBBox.ury); + for (node = temp->ligs; node != NULL; node = node->next) + { + printf(" L %s %s ;", node->succ, node->lig); + } + printf("\n"); + temp++; + } /* for */ + printf("EndCharMetrics\n"); + +} /* printAllCharMetrics */ + + +/*************************** printKernPairData ******************/ +printKernPairData() +{ + int i = 0; + PairKernData *pkd = fi->pkd; + + if (fi->numOfPairs != 0) + { + printf("StartKernData\n"); + printf("StartKernPairs %d\n",fi->numOfPairs); + for (i = 0; i < fi->numOfPairs; ++i) + printf( + "KPX %s %s %d\n", + pkd[i].name1, pkd[i].name2, pkd[i].xamt); +/* "KPX %s %s %d %d\n", + pkd[i].name1, pkd[i].name2, pkd[i].xamt, pkd[i].yamt); */ + printf("EndKernPairs\n"); + printf("EndKernData\n"); + } + +} /* printKernPairData */ + + +/*************************** printKernTrackData *******************/ +printKernTrackData() +{ + int i = 0; + TrackKernData *tkd = fi->tkd; + + if (fi->numOfTracks != 0) + { + printf("StartTrackKern %d\n",fi->numOfTracks); + for (i = 0; i < fi->numOfTracks; ++i) + printf( + "TrackKern %d %d %d %d %d\n", + tkd[i].degree, tkd[i].minPtSize, tkd[i].minKernAmt, + tkd[i].maxPtSize, tkd[i].maxKernAmt); + printf("EndTrackKern\n"); + } + +} /* printKernTrackData */ + + +/*************************** printCompCharData ********************/ +printCompCharData() +{ + int i = 0, j = 0; + CompCharData *ccd = fi->ccd; + + if (fi->numOfComps != 0) + { + printf("StartComposites %d\n",fi->numOfComps); + for (i = 0; i < fi->numOfComps; ++i) + { + printf("CC %s %d ;", + ccd[i].ccName, ccd[i].numOfPieces); + for (j = 0; j < ccd[i].numOfPieces; ++j) + printf( + " PCC %s %d %d ;", ccd[i].pieces[j].pccName, + ccd[i].pieces[j].deltax, ccd[i].pieces[j].deltay); + printf("\n"); + } + printf("EndComposites\n"); + } + +} /* printCompCharData */ + + + +/*************************** freeStorage ***********************/ + +freeStorage() +{ + if (fi != NULL) + { + if (fi->gfi != NULL) + { + free(fi->gfi->afmVersion); fi->gfi->afmVersion = NULL; + free(fi->gfi->fontName); fi->gfi->fontName = NULL; + free(fi->gfi->fullName); fi->gfi->fullName = NULL; + free(fi->gfi->familyName); fi->gfi->familyName = NULL; + free(fi->gfi->weight); fi->gfi->weight = NULL; + free(fi->gfi->version); fi->gfi->version = NULL; + free(fi->gfi->notice); fi->gfi->notice = NULL; + free(fi->gfi->encodingScheme); fi->gfi->encodingScheme = NULL; + free(fi->gfi); fi->gfi = NULL; + } + + if (fi->cwi != NULL) + { free(fi->cwi); fi->cwi = NULL; } + + if (fi->cmi != NULL) + { + int i = 0; + CharMetricInfo *temp = fi->cmi; + Ligature *node = temp->ligs; + + for (i = 0; i < fi->numOfChars; ++i) + { + for (node = temp->ligs; node != NULL; node = node->next) + { + free(node->succ); node->succ = NULL; + free(node->lig); node->lig = NULL; + } + + free(temp->name); temp->name = NULL; + temp++; + } + + free(fi->cmi); fi->cmi = NULL; + } + + if (fi->tkd != NULL) + { free(fi->tkd); fi->tkd = NULL; } + + if (fi->pkd != NULL) + { + free(fi->pkd->name1); fi->pkd->name1 = NULL; + free(fi->pkd->name2); fi->pkd->name2 = NULL; + free(fi->pkd); fi->pkd = NULL; + } + + if (fi->ccd != NULL) + { + int i = 0, j = 0; + CompCharData *ccd = fi->ccd; + + for (i = 0; i < fi->numOfComps; ++i) + { + for (j = 0; j < ccd[i].numOfPieces; ++j) + { + free(ccd[i].pieces[j].pccName); + ccd[i].pieces[j].pccName = NULL; + } + + free(ccd[i].ccName); ccd[i].ccName = NULL; + } + + free(fi->ccd); fi->ccd = NULL; + } + + free(fi); + + } /* if */ + +} /* freeStorage */ + + +/*************************** printValues **************************/ + +printValues() +{ + if (fi->gfi != NULL) printGlobals(); + if (fi->cmi != NULL) printAllCharMetrics(); + if (fi->pkd != NULL) printKernPairData(); + if (fi->tkd != NULL) printKernTrackData(); + if (fi->ccd != NULL) printCompCharData(); + printf("EndFontMetrics\n"); +} /* printValues */ + + +/*************************** sumValues **************************/ + +sumValues (FACTOR) +float FACTOR; +{ +int i,j = 0; +CharMetricInfo *temp = fi->cmi; +CharMetricInfo *othertemp = otherfi->cmi; +PairKernData *pkd = fi->pkd; +PairKernData *otherpkd = otherfi->pkd; +TrackKernData *tkd = fi->tkd; +TrackKernData *othertkd = otherfi->tkd; +CompCharData *ccd = fi->ccd; +CompCharData *otherccd = otherfi->ccd; + +fi->gfi->italicAngle += otherfi->gfi->italicAngle * FACTOR; +fi->gfi->underlinePosition += otherfi->gfi->underlinePosition * FACTOR; +fi->gfi->underlineThickness += otherfi->gfi->underlineThickness * FACTOR; +fi->gfi->fontBBox.llx += otherfi->gfi->fontBBox.llx * FACTOR; +fi->gfi->fontBBox.lly += otherfi->gfi->fontBBox.lly * FACTOR; +fi->gfi->fontBBox.urx += otherfi->gfi->fontBBox.urx * FACTOR; +fi->gfi->fontBBox.ury += otherfi->gfi->fontBBox.ury * FACTOR; +fi->gfi->capHeight += otherfi->gfi->capHeight * FACTOR; +fi->gfi->xHeight += otherfi->gfi->xHeight * FACTOR; +fi->gfi->descender += otherfi->gfi->descender * FACTOR; +fi->gfi->ascender += otherfi->gfi->ascender * FACTOR; + + +for (i = 0; i < fi->numOfChars; ++i) + { + temp->wx += othertemp->wx * FACTOR; + temp->charBBox.llx += othertemp->charBBox.llx * FACTOR; + temp->charBBox.lly += othertemp->charBBox.lly * FACTOR; + temp->charBBox.urx += othertemp->charBBox.urx * FACTOR; + temp->charBBox.ury += othertemp->charBBox.ury * FACTOR; + temp++; + othertemp++; + } /* for */ + + i = 0; + + if (fi->numOfPairs != 0) + { + for (i = 0; i < fi->numOfPairs; ++i) + pkd[i].xamt += otherpkd[i].xamt * FACTOR; + } + + +i = 0; + + if (fi->numOfTracks != 0) + { + for (i = 0; i < fi->numOfTracks; ++i) + { + tkd[i].degree += othertkd[i].degree * FACTOR; + tkd[i].minPtSize += othertkd[i].minPtSize * FACTOR; + tkd[i].minKernAmt += othertkd[i].minKernAmt * FACTOR; + tkd[i].maxPtSize += othertkd[i].maxPtSize * FACTOR; + tkd[i].maxKernAmt += othertkd[i].maxKernAmt * FACTOR; + } + } + + +i = 0; +j = 0; + if (fi->numOfComps != 0) + { + for (i = 0; i < fi->numOfComps; ++i) + { + for (j = 0; j < ccd[i].numOfPieces; ++j) + { + ccd[i].pieces[j].deltax += otherccd[i].pieces[j].deltax * FACTOR; + ccd[i].pieces[j].deltay += otherccd[i].pieces[j].deltay * FACTOR; + } + } + } + +} + + +/*************************** IniValues **************************/ + +IniValues (FACTOR) +float FACTOR; +{ +int i,j = 0; +CharMetricInfo *temp = fi->cmi; +PairKernData *pkd = fi->pkd; +TrackKernData *tkd = fi->tkd; +CompCharData *ccd = fi->ccd; + +fi->gfi->italicAngle = fi->gfi->italicAngle * FACTOR; +fi->gfi->underlinePosition = fi->gfi->underlinePosition * FACTOR; +fi->gfi->underlineThickness = fi->gfi->underlineThickness * FACTOR; +fi->gfi->fontBBox.llx = fi->gfi->fontBBox.llx * FACTOR; +fi->gfi->fontBBox.lly = fi->gfi->fontBBox.lly * FACTOR; +fi->gfi->fontBBox.urx = fi->gfi->fontBBox.urx * FACTOR; +fi->gfi->fontBBox.ury = fi->gfi->fontBBox.ury * FACTOR; +fi->gfi->capHeight = fi->gfi->capHeight * FACTOR; +fi->gfi->xHeight = fi->gfi->xHeight * FACTOR; +fi->gfi->descender = fi->gfi->descender * FACTOR; +fi->gfi->ascender = fi->gfi->ascender * FACTOR; + + +for (i = 0; i < fi->numOfChars; ++i) + { + temp->wx = temp->wx * FACTOR; + temp->charBBox.llx = temp->charBBox.llx * FACTOR; + temp->charBBox.lly = temp->charBBox.lly * FACTOR; + temp->charBBox.urx = temp->charBBox.urx * FACTOR; + temp->charBBox.ury = temp->charBBox.ury * FACTOR; + temp++; + } /* for */ + + i = 0; + + if (fi->numOfPairs != 0) + { + for (i = 0; i < fi->numOfPairs; ++i) + pkd[i].xamt = pkd[i].xamt * FACTOR; + } + + +i = 0; + + if (fi->numOfTracks != 0) + { + for (i = 0; i < fi->numOfTracks; ++i) + { + tkd[i].degree = tkd[i].degree * FACTOR; + tkd[i].minPtSize = tkd[i].minPtSize * FACTOR; + tkd[i].minKernAmt = tkd[i].minKernAmt * FACTOR; + tkd[i].maxPtSize = tkd[i].maxPtSize * FACTOR; + tkd[i].maxKernAmt = tkd[i].maxKernAmt * FACTOR; + } + } + + +i = 0; +j = 0; + if (fi->numOfComps != 0) + { + for (i = 0; i < fi->numOfComps; ++i) + { + for (j = 0; j < ccd[i].numOfPieces; ++j) + { + ccd[i].pieces[j].deltax = ccd[i].pieces[j].deltax * FACTOR; + ccd[i].pieces[j].deltay = ccd[i].pieces[j].deltay * FACTOR; + } + } + } + +} + + +/*************************** main *********************************/ + +main (argc, argv) + int argc; + char **argv; +{ + + char *filename, *prog = *argv; + FILE *fp, *fpmain; + char mastafm[MAXMM][128]; + char Line[128]; + char newafm[128]; + float Weight; + int NofM, i, j, k, l; + + ++argv; --argc; myflags |= P_ALL; + + if (!argc) + { + printf(" usage: parseAFM [AFM File]\n"); + exit(0); + } + else + filename = *argv; + + if (!filename[0]) + { + printf ("*** ERROR: can't open. filename is missing.\n", + filename ); + return 0; + } + + fpmain = fopen(filename, "r" ); + if (fpmain == NULL) + { + fprintf (stderr,"*** ERROR: can't find: %s\n", filename ); + exit(1); + } + fgets(mastafm[0],128,fpmain); + NofM = atoi(mastafm[0]); + fprintf(stderr,"Now read %d lines\n",NofM); + for (j = 0; j < NofM; j++) + { + fscanf(fpmain,"%s",&mastafm[j]); + } + fscanf(fpmain,"%s",&newafm); + fprintf(stderr,"Make new AFM file: %s\n",newafm); + for (j = 0; j < NofM; j++) + { + fscanf(fpmain,"%f",&Weight); + fprintf(stderr,"Process file %d: %s with weight %f\n",j,mastafm[j],Weight); + fp = fopen(mastafm[j], "r" ); + if (fp == NULL) + { + fprintf (stderr,"*** ERROR: can't find: %s\n", mastafm[j] ); + exit(1); + } + if ( j == 0 ) + { + parseFile(fp, &fi, myflags); + IniValues(Weight); + } + else + { + parseFile(fp, &otherfi, myflags); + sumValues(Weight); + } + fclose(fp); + } + printValues(); + freeStorage(); + fclose(fpmain); +} diff --git a/fonts/utilities/mm/mmfont b/fonts/utilities/mm/mmfont new file mode 100644 index 0000000000..0b9570ce76 --- /dev/null +++ b/fonts/utilities/mm/mmfont @@ -0,0 +1,183 @@ +#!/usr/bin/bash +# +#make a Minion or Myriad font instance +#------------------------------------------------- +#there are 3 axes in Minion: +#the weight ranges from 345 to 620 +#the width ranges from 450 to 600 +#the size varies from 6 to 72 +# +#there are 2 axes in Myriad: +#the weight ranges from 215 to 830 +#the width ranges from 300 to 750 +# +TDS=/home/spqr/tds +MMHOME=/home/spqr/psfonts/mmafm +MMDEST=$TDS/dvips/mm +TFMDEST=$TDS/fonts/tfm/adobe/mm +VFDEST=$TDS/fonts/vf/adobe/mm +# +#option allows us just to generate the AFM files, not run fontinst +# +AFM= +while true; do + case $1 in + -afm) shift ; AFM=y ; break;; + *) break;; + esac +done +FNAME=$1 +FAM=`expr $FNAME : '^z\(..\).*$'` +IWEIGHT=`expr $FNAME : '^zm.\(.*\)[78]t.*$'` +WIDTH=`expr $FNAME : '^[a-z]*[78]t\([^0-9]*\).*$'` +SIZE=`expr $FNAME : '^.*[78]t[^0-9]*\([0-9]*\)$'` +ENCODING=`expr $FNAME : '^.*\([78]t\).*$'` +USESIZE=`echo $SIZE \* 1.095 | bc` +WEIGHT=`expr $IWEIGHT : '\(.\).*'` +SHAPE=`expr $IWEIGHT : '.\(.*\)'` +EXTRA= +case $FAM in + mn) FULLFAM=Minion ; EXPERT=y;; + my) FULLFAM=Myriad; EXPERT=;; + *) echo Unknown MM family $FAM >&2; exit 1;; +esac + +if test "${SHAPE}" = "i" +then + PFA=${FULLFAM}MM-It + EPFA=${FULLFAM}MM-ItEp + LSHAPE="it" +else + PFA=${FULLFAM}MM + EPFA=${FULLFAM}MM-Ep + if test "${SHAPE}" = "c" + then + LSHAPE="sc" + IWEIGHT=$WEIGHT + EXTRA="c" + else + LSHAPE="n" + fi +fi +if test "${WIDTH}x" = "x" +then + REALWIDTH="r" +else + REALWIDTH=$WIDTH +fi +case $WEIGHT in + h) LWEIGHT="ul"; MINWEIGHT=345; MYWEIGHT=215;; #hairline + j) LWEIGHT="el"; MINWEIGHT=360; MYWEIGHT=291;; #extralight + l) LWEIGHT="l"; MINWEIGHT=380; MYWEIGHT=367;; #light + k) LWEIGHT="sl"; MINWEIGHT=400; MYWEIGHT=443;; #book + m) LWEIGHT="m"; MINWEIGHT=415; MYWEIGHT=519;; #Medium + s) LWEIGHT="sb"; MINWEIGHT=500; MYWEIGHT=595;; #semibold + b) LWEIGHT="b"; MINWEIGHT=580; MYWEIGHT=671;; #bold + x) LWEIGHT="eb"; MINWEIGHT=600; MYWEIGHT=747;; #ExtraBold + u) LWEIGHT="ub"; MINWEIGHT=620; MYWEIGHT=830;; #UltraBlack + *) echo BAD WEIGHT >&2; exit 1;; +esac +case $REALWIDTH in + o) LWIDTH="uc"; MINWIDTH=450; MYWIDTH=300;; #UltraCondensed + q) LWIDTH="ec"; MINWIDTH=468; MYWIDTH=350;; #ExtraCondensed + c) LWIDTH="c"; MINWIDTH=490; MYWIDTH=400;; #Condensed + n) LWIDTH="sc"; MINWIDTH=510; MYWIDTH=450;; #Narrow + r) LWIDTH="m"; MINWIDTH=535; MYWIDTH=500;; #Regular + x) LWIDTH="sx"; MINWIDTH=550; MYWIDTH=550;; #Extended + e) LWIDTH="x"; MINWIDTH=565; MYWIDTH=600;; #Expanded + v) LWIDTH="ex"; MINWIDTH=584; MYWIDTH=650;; #Extra Expanded + w) LWIDTH="ux"; MINWIDTH=600; MYWIDTH=700;; #Wide + *) echo BAD WIDTH >&2; exit 1;; +esac +ORID=`pwd` +cd $MMHOME +if test "$LWIDTH$LWEIGHT" = "mm" +then + LSERIES="m" +else + if test "$LWIDTH" = "m" + then + LWIDTH="" + fi + if test "$LWEIGHT" = "m" + then + LWEIGHT="" + fi + LSERIES=$LWEIGHT$LWIDTH +fi +if test "$ENCODING" = "8t" +then + LATEXENC=T1 + SUFFIX=8t +else + LATEXENC=OT1 + SUFFIX=7t +fi +EFNAME=z$FAM${IWEIGHT}8x${WIDTH}${SIZE} +RNAME=z$FAM${IWEIGHT}8r${WIDTH}${SIZE} +FINALNAME=z$FAM${IWEIGHT}${EXTRA}${SUFFIX}${WIDTH}${SIZE} +RAWNAME=z$FAM${IWEIGHT}8a${WIDTH}${SIZE} +echo $RAWNAME: $EFNAME, $RNAME, $FINALNAME +#echo $FNAME: $FAM / $WEIGHT [ $IWEIGHT ] / $WIDTH / $SIZE / $SHAPE: $LSERIES / $LSHAPE >&2 +if test "${SHAPE}" != "c" +then + echo "$RNAME $RAWNAME \" TeXBase1Encoding ReEncodeFont \" <8r.enc <$PFA.PFA <$RAWNAME.pro" > $RAWNAME.map +fi +makeinstance.sh $PFA $RAWNAME $MINWEIGHT $MINWIDTH $USESIZE +if test "$EXPERT"x != "x" +then + echo "$EFNAME $EFNAME <$EPFA.PFA <$EFNAME.pro" > $EFNAME.map + makeinstance.sh $EPFA $EFNAME $MINWEIGHT $MINWIDTH $USESIZE >& /dev/null +fi +if test "$AFM"x != "x" +then + exit 0 +fi +cat > _min$$.tex <<HERE +\input fontinst.sty +\needsfontinstversion{1.5} +\installfonts +\installfamily{${LATEXENC}}{foo}{} + \transformfont{$RNAME}{\reencodefont{8r}{\fromafm{$RAWNAME}}} +HERE +if test "$EXPERT"x != "x" +then + if test "${SHAPE}" = "c" + then +echo "\\installfont{$FINALNAME}{$RNAME,$EFNAME,latin}{${LATEXENC}c}{${LATEXENC}}{foo}{$LSERIES}{$LSHAPE}{}" >> _min$$.tex + else + echo "\\installfont{$FINALNAME}{$RNAME,$EFNAME,latin}{${LATEXENC}}{${LATEXENC}}{foo}{$LSERIES}{$LSHAPE}{}" >> _min$$.tex + fi +else + if test "${SHAPE}" = "c" + then + echo " \\installfont{$FINALNAME}{$RNAME,latin}{${LATEXENC}c}{${LATEXENC}}{foo}{$LSERIES}{$LSHAPE}{}" >> _min$$.tex + else + echo "\\installfont{$FINALNAME}{$RNAME,latin}{${LATEXENC}}{${LATEXENC}}{foo}{$LSERIES}{$LSHAPE}{}" >> _min$$.tex + fi +fi +cat >> _min$$.tex <<THERE +\endinstallfonts +\bye +THERE +tex _min$$ +rm _min$$.* +pltotf $RNAME.pl $RNAME.tfm >& /dev/null +vptovf $FINALNAME.vpl $FINALNAME.vf $FINALNAME.tfm >& /dev/null +rm $RNAME.pl $FINALNAME.vpl +rm ${LATEXENC}foo.fd +rm $RAWNAME.afm +mv $RNAME.tfm $FINALNAME.tfm $TFMDEST +mv $FINALNAME.vf $VFDEST +mv $RAWNAME.pro $MMDEST +cat z$FAM${IWEIGHT}8*${WIDTH}${SIZE}.map $MMDEST/mm.map | sort | uniq > $$.map +mv $$.map $MMDEST/mm.map +rm $RAWNAME.* +if test "$EXPERT"x != "x" +then + pltotf $EFNAME.pl $EFNAME.tfm >& /dev/null + mv $EFNAME.pro $MMDEST + mv $EFNAME.tfm $TFMDEST + rm $EFNAME.* +fi +cd $ORID diff --git a/fonts/utilities/mm/parseAFM.c b/fonts/utilities/mm/parseAFM.c new file mode 100644 index 0000000000..186755beca --- /dev/null +++ b/fonts/utilities/mm/parseAFM.c @@ -0,0 +1,1226 @@ +/* + * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved. + * + * This file may be freely copied and redistributed as long as: + * 1) This entire notice continues to be included in the file, + * 2) If the file has been modified in any way, a notice of such + * modification is conspicuously indicated. + * + * PostScript, Display PostScript, and Adobe are registered trademarks of + * Adobe Systems Incorporated. + * + * ************************************************************************ + * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT + * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS + * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR + * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY + * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, + * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * ************************************************************************ + */ + +/* parseAFM.c + * + * This file is used in conjuction with the parseAFM.h header file. + * This file contains several procedures that are used to parse AFM + * files. It is intended to work with an application program that needs + * font metric information. The program can be used as is by making a + * procedure call to "parseFile" (passing in the expected parameters) + * and having it fill in a data structure with the data from the + * AFM file, or an application developer may wish to customize this + * code. + * + * There is also a file, parseAFMclient.c, that is a sample application + * showing how to call the "parseFile" procedure and how to use the data + * after "parseFile" has returned. + * + * Please read the comments in parseAFM.h and parseAFMclient.c. + * + * History: + * original: DSM Thu Oct 20 17:39:59 PDT 1988 + * modified: DSM Mon Jul 3 14:17:50 PDT 1989 + * - added 'storageProblem' return code + * - fixed bug of not allocating extra byte for string duplication + * - fixed typos + * modified: DSM Tue Apr 3 11:18:34 PDT 1990 + * - added free(ident) at end of parseFile routine + * modified: DSM Tue Jun 19 10:16:29 PDT 1990 + * - changed (width == 250) to (width = 250) in initializeArray + */ + +#include <stdio.h> +#include <errno.h> +#include <sys/file.h> +#include <math.h> +#include "parseAFM.h" + +#define lineterm EOL /* line terminating character */ +#define normalEOF 1 /* return code from parsing routines used only */ + /* in this module */ +#define Space "space" /* used in string comparison to look for the width */ + /* of the space character to init the widths array */ +#define False "false" /* used in string comparison to check the value of */ + /* boolean keys (e.g. IsFixedPitch) */ + +#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0) + + + +/*************************** GLOBALS ***********************/ + +static char *ident = NULL; /* storage buffer for keywords */ + + +/* "shorts" for fast case statement + * The values of each of these enumerated items correspond to an entry in the + * table of strings defined below. Therefore, if you add a new string as + * new keyword into the keyStrings table, you must also add a corresponding + * parseKey AND it MUST be in the same position! + * + * IMPORTANT: since the sorting algorithm is a binary search, the strings of + * keywords must be placed in lexicographical order, below. [Therefore, the + * enumerated items are not necessarily in lexicographical order, depending + * on the name chosen. BUT, they must be placed in the same position as the + * corresponding key string.] The NOPE shall remain in the last position, + * since it does not correspond to any key string, and it is used in the + * "recognize" procedure to calculate how many possible keys there are. + */ + +static enum parseKey { + ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT, + DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, + ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN, + FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH, + ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME, + NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, + STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS, + STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION, + UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT, + NOPE }; + +/* keywords for the system: + * This a table of all of the current strings that are vaild AFM keys. + * Each entry can be referenced by the appropriate parseKey value (an + * enumerated data type defined above). If you add a new keyword here, + * a corresponding parseKey MUST be added to the enumerated data type + * defined above, AND it MUST be added in the same position as the + * string is in this table. + * + * IMPORTANT: since the sorting algorithm is a binary search, the keywords + * must be placed in lexicographical order. And, NULL should remain at the + * end. + */ + +static char *keyStrings[] = { + "Ascender", "B", "C", "CC", "CapHeight", "Comment", + "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites", + "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern", + "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch", + "ItalicAngle", "KP", "KPX", "L", "N", + "Notice", "PCC", "StartCharMetrics", "StartComposites", + "StartFontMetrics", "StartKernData", "StartKernPairs", + "StartTrackKern", "TrackKern", "UnderlinePosition", + "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight", + NULL }; + +/*************************** PARSING ROUTINES **************/ + +/*************************** token *************************/ + +/* A "AFM File Conventions" tokenizer. That means that it will + * return the next token delimited by white space. See also + * the `linetoken' routine, which does a similar thing but + * reads all tokens until the next end-of-line. + */ + +static char *token(stream) + FILE *stream; +{ + int ch, idx; + + /* skip over white space */ + while ((ch = fgetc(stream)) == ' ' || ch == lineterm || + ch == ',' || ch == '\t' || ch == ';'); + + idx = 0; + while (ch != EOF && ch != ' ' && ch != lineterm + && ch != '\t' && ch != ':' && ch != ';') + { + ident[idx++] = ch; + ch = fgetc(stream); + } /* while */ + + if (ch == EOF && idx < 1) return ((char *)NULL); + if (idx >= 1 && ch != ':' ) ungetc(ch, stream); + if (idx < 1 ) ident[idx++] = ch; /* single-character token */ + ident[idx] = 0; + + return(ident); /* returns pointer to the token */ + +} /* token */ + + +/*************************** linetoken *************************/ + +/* "linetoken" will get read all tokens until the EOL character from + * the given stream. This is used to get any arguments that can be + * more than one word (like Comment lines and FullName). + */ + +static char *linetoken(stream) + FILE *stream; +{ + int ch, idx; + + while ((ch = fgetc(stream)) == ' ' || ch == '\t' ); + + idx = 0; + while (ch != EOF && ch != lineterm) + { + ident[idx++] = ch; + ch = fgetc(stream); + } /* while */ + + ungetc(ch, stream); + ident[idx] = 0; + + return(ident); /* returns pointer to the token */ + +} /* linetoken */ + + +/*************************** recognize *************************/ + +/* This function tries to match a string to a known list of + * valid AFM entries (check the keyStrings array above). + * "ident" contains everything from white space through the + * next space, tab, or ":" character. + * + * The algorithm is a standard Knuth binary search. + */ + +static enum parseKey recognize(ident) + register char *ident; +{ + int lower = 0, upper = (int) NOPE, midpoint, cmpvalue; + BOOL found = FALSE; + + while ((upper >= lower) && !found) + { + midpoint = (lower + upper)/2; + if (keyStrings[midpoint] == NULL) break; + cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME); + if (cmpvalue == 0) found = TRUE; + else if (cmpvalue < 0) upper = midpoint - 1; + else lower = midpoint + 1; + } /* while */ + + if (found) return (enum parseKey) midpoint; + else return NOPE; + +} /* recognize */ + + +/************************* parseGlobals *****************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "StartCharMetrics" keyword, which essentially marks the + * end of the Global Font Information and the beginning of the character + * metrics information. + * + * If the caller of "parseFile" specified that it wanted the Global + * Font Information (as defined by the "AFM File Specification" + * document), then that information will be stored in the returned + * data structure. + * + * Any Global Font Information entries that are not found in a + * given file, will have the usual default initialization value + * for its type (i.e. entries of type int will be 0, etc). + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static BOOL parseGlobals(fp, gfi) + FILE *fp; + register GlobalFontInfo *gfi; +{ + BOOL cont = TRUE, save = (gfi != NULL); + int error = ok; + register char *keyword; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + error = earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Global Font info section */ + /* without saving any of the data */ + switch (recognize(keyword)) + { + case STARTCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire global font info section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case STARTFONTMETRICS: + keyword = token(fp); + gfi->afmVersion = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->afmVersion, keyword); + break; + case COMMENT: + keyword = linetoken(fp); + break; + case FONTNAME: + keyword = token(fp); + gfi->fontName = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->fontName, keyword); + break; + case ENCODINGSCHEME: + keyword = token(fp); + gfi->encodingScheme = (char *) + malloc(strlen(keyword) + 1); + strcpy(gfi->encodingScheme, keyword); + break; + case FULLNAME: + keyword = linetoken(fp); + gfi->fullName = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->fullName, keyword); + break; + case FAMILYNAME: + keyword = linetoken(fp); + gfi->familyName = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->familyName, keyword); + break; + case WEIGHT: + keyword = token(fp); + gfi->weight = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->weight, keyword); + break; + case ITALICANGLE: + keyword = token(fp); + gfi->italicAngle = (float) atoi(keyword); + if (errno == ERANGE) error = parseError; + break; + case ISFIXEDPITCH: + keyword = token(fp); + if (MATCH(keyword, False)) + gfi->isFixedPitch = 0; + else + gfi->isFixedPitch = 1; + break; + case UNDERLINEPOSITION: + keyword = token(fp); + gfi->underlinePosition = atoi(keyword); + break; + case UNDERLINETHICKNESS: + keyword = token(fp); + gfi->underlineThickness = atoi(keyword); + break; + case VERSION: + keyword = token(fp); + gfi->version = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->version, keyword); + break; + case NOTICE: + keyword = linetoken(fp); + gfi->notice = (char *) malloc(strlen(keyword) + 1); + strcpy(gfi->notice, keyword); + break; + case FONTBBOX: + keyword = token(fp); + gfi->fontBBox.llx = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.lly = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.urx = atoi(keyword); + keyword = token(fp); + gfi->fontBBox.ury = atoi(keyword); + break; + case CAPHEIGHT: + keyword = token(fp); + gfi->capHeight = atoi(keyword); + break; + case XHEIGHT: + keyword = token(fp); + gfi->xHeight = atoi(keyword); + break; + case DESCENDER: + keyword = token(fp); + gfi->descender = atoi(keyword); + break; + case ASCENDER: + keyword = token(fp); + gfi->ascender = atoi(keyword); + break; + case STARTCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + return(error); + +} /* parseGlobals */ + + + +/************************* initializeArray ************************/ + +/* Unmapped character codes are (at Adobe Systems) assigned the + * width of the space character (if one exists) else they get the + * value of 250 ems. This function initializes all entries in the + * char widths array to have this value. Then any mapped character + * codes will be replaced with the width of the appropriate character + * when parsing the character metric section. + + * This function parses the Character Metrics Section looking + * for a space character (by comparing character names). If found, + * the width of the space character will be used to initialize the + * values in the array of character widths. + * + * Before returning, the position of the read/write pointer of the + * file is reset to be where it was upon entering this function. + */ + +static int initializeArray(fp, cwi) + FILE *fp; + register int *cwi; +{ + BOOL cont = TRUE, found = FALSE; + long opos = ftell(fp); + int code = 0, width = 0, i = 0, error = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case CODE: + code = atoi(token(fp)); + break; + case XWIDTH: + width = atoi(token(fp)); + break; + case CHARNAME: + keyword = token(fp); + if (MATCH(keyword, Space)) + { + cont = FALSE; + found = TRUE; + } + break; + case ENDCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if (!found) + width = 250; + + for (i = 0; i < 256; ++i) + cwi[i] = width; + + fseek(fp, opos, 0); + + return(error); + +} /* initializeArray */ + + +/************************* parseCharWidths **************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndCharMetrics" keyword. It will save the character + * width info (as opposed to all of the character metric information) + * if requested by the caller of parseFile. Otherwise, it will just + * parse through the section without saving any information. + * + * If data is to be saved, parseCharWidths is passed in a pointer + * to an array of widths that has already been initialized by the + * standard value for unmapped character codes. This function parses + * the Character Metrics section only storing the width information + * for the encoded characters into the array using the character code + * as the index into that array. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parseCharWidths(fp, cwi) + FILE *fp; + register int *cwi; +{ + BOOL cont = TRUE, save = (cwi != NULL); + int pos = 0, error = ok; + register char *keyword; + + while (cont) + { + keyword = token(fp); + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Char Metrics section without */ + /* saving any of the data*/ + switch (recognize(keyword)) + { + case ENDCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire char metrics section, saving */ + /* only the char x-width info */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case CODE: + keyword = token(fp); + pos = atoi(keyword); + break; + case XYWIDTH: + /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */ + keyword = token(fp); keyword = token(fp); /* eat values */ + error = parseError; + break; + case XWIDTH: + keyword = token(fp); + if (pos >= 0) /* ignore unmapped chars */ + cwi[pos] = atoi(keyword); + break; + case ENDCHARMETRICS: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case CHARNAME: /* eat values (so doesn't cause parseError) */ + keyword = token(fp); + break; + case CHARBBOX: + keyword = token(fp); keyword = token(fp); + keyword = token(fp); keyword = token(fp); + break; + case LIGATURE: + keyword = token(fp); keyword = token(fp); + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + return(error); + +} /* parseCharWidths */ + + +/************************* parseCharMetrics ************************/ + +/* This function is called by parseFile if the caller of parseFile + * requested that all character metric information be saved + * (as opposed to only the character width information). + * + * parseCharMetrics is passed in a pointer to an array of records + * to hold information on a per character basis. This function + * parses the Character Metrics section storing all character + * metric information for the ALL characters (mapped and unmapped) + * into the array. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parseCharMetrics(fp, fi) + FILE *fp; + register FontInfo *fi; +{ + BOOL cont = TRUE, firstTime = TRUE; + int error = ok, count = 0; + register CharMetricInfo *temp = fi->cmi; + register char *keyword; + + while (cont) + { + keyword = token(fp); + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case CODE: + if (count < fi->numOfChars) + { + if (firstTime) firstTime = FALSE; + else temp++; + temp->code = atoi(token(fp)); + count++; + } + else + { + error = parseError; + cont = FALSE; + } + break; + case XYWIDTH: + temp->wx = atoi(token(fp)); + temp->wy = atoi(token(fp)); + break; + case XWIDTH: + temp->wx = atoi(token(fp)); + break; + case CHARNAME: + keyword = token(fp); + temp->name = (char *) malloc(strlen(keyword) + 1); + strcpy(temp->name, keyword); + break; + case CHARBBOX: + temp->charBBox.llx = atoi(token(fp)); + temp->charBBox.lly = atoi(token(fp)); + temp->charBBox.urx = atoi(token(fp)); + temp->charBBox.ury = atoi(token(fp)); + break; + case LIGATURE: { + Ligature **tail = &(temp->ligs); + Ligature *node = *tail; + + if (*tail != NULL) + { + while (node->next != NULL) + node = node->next; + tail = &(node->next); + } + + *tail = (Ligature *) calloc(1, sizeof(Ligature)); + keyword = token(fp); + (*tail)->succ = (char *) malloc(strlen(keyword) + 1); + strcpy((*tail)->succ, keyword); + keyword = token(fp); + (*tail)->lig = (char *) malloc(strlen(keyword) + 1); + strcpy((*tail)->lig, keyword); + break; } + case ENDCHARMETRICS: + cont = FALSE;; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if ((error == ok) && (count != fi->numOfChars)) + error = parseError; + + return(error); + +} /* parseCharMetrics */ + + + +/************************* parseTrackKernData ***********************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndTrackKern" or "EndKernData" keywords. It will save the + * track kerning data if requested by the caller of parseFile. + * + * parseTrackKernData is passed in a pointer to the FontInfo record. + * If data is to be saved, the FontInfo record will already contain + * a valid pointer to storage for the track kerning data. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parseTrackKernData(fp, fi) + FILE *fp; + register FontInfo *fi; +{ + BOOL cont = TRUE, save = (fi->tkd != NULL); + int pos = 0, error = ok, tcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Track Kerning Data */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDTRACKKERN: + case ENDKERNDATA: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Track Kerning Data section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case TRACKKERN: + if (tcount < fi->numOfTracks) + { + keyword = token(fp); + fi->tkd[pos].degree = atoi(keyword); + keyword = token(fp); + fi->tkd[pos].minPtSize = atof(keyword); + if (errno == ERANGE) error = parseError; + keyword = token(fp); + fi->tkd[pos].minKernAmt = atof(keyword); + if (errno == ERANGE) error = parseError; + keyword = token(fp); + fi->tkd[pos].maxPtSize = atof(keyword); + if (errno == ERANGE) error = parseError; + keyword = token(fp); + fi->tkd[pos++].maxKernAmt = atof(keyword); + if (errno == ERANGE) error = parseError; + tcount++; + } + else + { + error = parseError; + cont = FALSE; + } + break; + case ENDTRACKKERN: + case ENDKERNDATA: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if (error == ok && tcount != fi->numOfTracks) + error = parseError; + + return(error); + +} /* parseTrackKernData */ + + +/************************* parsePairKernData ************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndKernPairs" or "EndKernData" keywords. It will save + * the pair kerning data if requested by the caller of parseFile. + * + * parsePairKernData is passed in a pointer to the FontInfo record. + * If data is to be saved, the FontInfo record will already contain + * a valid pointer to storage for the pair kerning data. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parsePairKernData(fp, fi) + FILE *fp; + register FontInfo *fi; +{ + BOOL cont = TRUE, save = (fi->pkd != NULL); + int pos = 0, error = ok, pcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + + if (keyword == NULL) + { + error = earlyEOF; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Pair Kerning Data */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDKERNPAIRS: + case ENDKERNDATA: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Pair Kerning Data section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case KERNPAIR: + if (pcount < fi->numOfPairs) + { + keyword = token(fp); + fi->pkd[pos].name1 = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->pkd[pos].name1, keyword); + keyword = token(fp); + fi->pkd[pos].name2 = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->pkd[pos].name2, keyword); + keyword = token(fp); + fi->pkd[pos].xamt = atoi(keyword); + keyword = token(fp); + fi->pkd[pos++].yamt = atoi(keyword); + pcount++; + } + else + { + error = parseError; + cont = FALSE; + } + break; + case KERNPAIRXAMT: + if (pcount < fi->numOfPairs) + { + keyword = token(fp); + fi->pkd[pos].name1 = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->pkd[pos].name1, keyword); + keyword = token(fp); + fi->pkd[pos].name2 = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->pkd[pos].name2, keyword); + keyword = token(fp); + fi->pkd[pos++].xamt = atoi(keyword); + pcount++; + } + else + { + error = parseError; + cont = FALSE; + } + break; + case ENDKERNPAIRS: + case ENDKERNDATA: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if (error == ok && pcount != fi->numOfPairs) + error = parseError; + + return(error); + +} /* parsePairKernData */ + + +/************************* parseCompCharData **************************/ + +/* This function is called by "parseFile". It will parse the AFM File + * up to the "EndComposites" keyword. It will save the composite + * character data if requested by the caller of parseFile. + * + * parseCompCharData is passed in a pointer to the FontInfo record, and + * a boolean representing if the data should be saved. + * + * This function will create the appropriate amount of storage for + * the composite character data and store a pointer to the storage + * in the FontInfo record. + * + * This function returns an error code specifying whether there was + * a premature EOF or a parsing error. This return value is used by + * parseFile to determine if there is more file to parse. + */ + +static parseCompCharData(fp, fi) + FILE *fp; + register FontInfo *fi; +{ + BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL); + int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0; + register char *keyword; + + while (cont) + { + keyword = token(fp); + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + error = earlyEOF; + break; /* get out of loop */ + } + if (ccount > fi->numOfComps) + { + error = parseError; + break; /* get out of loop */ + } + if (!save) + /* get tokens until the end of the Composite Character info */ + /* section without saving any of the data */ + switch(recognize(keyword)) + { + case ENDCOMPOSITES: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + default: + break; + } /* switch */ + else + /* otherwise parse entire Composite Character info section, */ + /* saving the data */ + switch(recognize(keyword)) + { + case COMMENT: + keyword = linetoken(fp); + break; + case COMPCHAR: + if (ccount < fi->numOfComps) + { + keyword = token(fp); + if (pcount != fi->ccd[pos].numOfPieces) + error = parseError; + pcount = 0; + if (firstTime) firstTime = FALSE; + else pos++; + fi->ccd[pos].ccName = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->ccd[pos].ccName, keyword); + keyword = token(fp); + fi->ccd[pos].numOfPieces = atoi(keyword); + fi->ccd[pos].pieces = (Pcc *) + calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc)); + j = 0; + ccount++; + } + else + { + error = parseError; + cont = FALSE; + } + break; + case COMPCHARPIECE: + if (pcount < fi->ccd[pos].numOfPieces) + { + keyword = token(fp); + fi->ccd[pos].pieces[j].pccName = (char *) + malloc(strlen(keyword) + 1); + strcpy(fi->ccd[pos].pieces[j].pccName, keyword); + keyword = token(fp); + fi->ccd[pos].pieces[j].deltax = atoi(keyword); + keyword = token(fp); + fi->ccd[pos].pieces[j++].deltay = atoi(keyword); + pcount++; + } + else + error = parseError; + break; + case ENDCOMPOSITES: + cont = FALSE; + break; + case ENDFONTMETRICS: + cont = FALSE; + error = normalEOF; + break; + case NOPE: + default: + error = parseError; + break; + } /* switch */ + } /* while */ + + if (error == ok && ccount != fi->numOfComps) + error = parseError; + + return(error); + +} /* parseCompCharData */ + + + + +/*************************** 'PUBLIC' FUNCTION ********************/ + + +/*************************** parseFile *****************************/ + +/* parseFile is the only 'public' procedure available. It is called + * from an application wishing to get information from an AFM file. + * The caller of this function is responsible for locating and opening + * an AFM file and handling all errors associated with that task. + * + * parseFile expects 3 parameters: a vaild file pointer, a pointer + * to a (FontInfo *) variable (for which storage will be allocated and + * the data requested filled in), and a mask specifying which + * data from the AFM File should be saved in the FontInfo structure. + * + * The file will be parsed and the requested data will be stored in + * a record of type FontInfo (refer to ParseAFM.h). + * + * parseFile returns an error code as defined in parseAFM.h. + * + * The position of the read/write pointer associated with the file + * pointer upon return of this function is undefined. + */ + +extern int parseFile (fp, fi, flags) + FILE *fp; + FontInfo **fi; + FLAGS flags; +{ + + int code = ok; /* return code from each of the parsing routines */ + int error = ok; /* used as the return code from this function */ + + register char *keyword; /* used to store a token */ + + + /* storage data for the global variable ident */ + ident = (char *) calloc(MAX_NAME, sizeof(char)); + if (ident == NULL) {error = storageProblem; return(error);} + + (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo)); + if ((*fi) == NULL) {error = storageProblem; return(error);} + + if (flags & P_G) + { + (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo)); + if ((*fi)->gfi == NULL) {error = storageProblem; return(error);} + } + + /* The AFM File begins with Global Font Information. This section */ + /* will be parsed whether or not information should be saved. */ + code = parseGlobals(fp, (*fi)->gfi); + + if (code < 0) error = code; + + /* The Global Font Information is followed by the Character Metrics */ + /* section. Which procedure is used to parse this section depends on */ + /* how much information should be saved. If all of the metrics info */ + /* is wanted, parseCharMetrics is called. If only the character widths */ + /* is wanted, parseCharWidths is called. parseCharWidths will also */ + /* be called in the case that no character data is to be saved, just */ + /* to parse through the section. */ + + if ((code != normalEOF) && (code != earlyEOF)) + { + (*fi)->numOfChars = atoi(token(fp)); + if (flags & (P_M ^ P_W)) + { + (*fi)->cmi = (CharMetricInfo *) + calloc((*fi)->numOfChars, sizeof(CharMetricInfo)); + if ((*fi)->cmi == NULL) {error = storageProblem; return(error);} + code = parseCharMetrics(fp, *fi); + } + else + { + if (flags & P_W) + { + (*fi)->cwi = (int *) calloc(256, sizeof(int)); + if ((*fi)->cwi == NULL) + { + error = storageProblem; + return(error); + } + } + /* parse section regardless */ + code = parseCharWidths(fp, (*fi)->cwi); + } /* else */ + } /* if */ + + if ((error != earlyEOF) && (code < 0)) error = code; + + /* The remaining sections of the AFM are optional. This code will */ + /* look at the next keyword in the file to determine what section */ + /* is next, and then allocate the appropriate amount of storage */ + /* for the data (if the data is to be saved) and call the */ + /* appropriate parsing routine to parse the section. */ + + while ((code != normalEOF) && (code != earlyEOF)) + { + keyword = token(fp); + if (keyword == NULL) + /* Have reached an early and unexpected EOF. */ + /* Set flag and stop parsing */ + { + code = earlyEOF; + break; /* get out of loop */ + } + switch(recognize(keyword)) + { + case STARTKERNDATA: + break; + case ENDKERNDATA: + break; + case STARTTRACKKERN: + keyword = token(fp); + if (flags & P_T) + { + (*fi)->numOfTracks = atoi(keyword); + (*fi)->tkd = (TrackKernData *) + calloc((*fi)->numOfTracks, sizeof(TrackKernData)); + if ((*fi)->tkd == NULL) + { + error = storageProblem; + return(error); + } + } /* if */ + code = parseTrackKernData(fp, *fi); + break; + case STARTKERNPAIRS: + keyword = token(fp); + if (flags & P_P) + { + (*fi)->numOfPairs = atoi(keyword); + (*fi)->pkd = (PairKernData *) + calloc((*fi)->numOfPairs, sizeof(PairKernData)); + if ((*fi)->pkd == NULL) + { + error = storageProblem; + return(error); + } + } /* if */ + code = parsePairKernData(fp, *fi); + break; + case STARTCOMPOSITES: + keyword = token(fp); + if (flags & P_C) + { + (*fi)->numOfComps = atoi(keyword); + (*fi)->ccd = (CompCharData *) + calloc((*fi)->numOfComps, sizeof(CompCharData)); + if ((*fi)->ccd == NULL) + { + error = storageProblem; + return(error); + } + } /* if */ + code = parseCompCharData(fp, *fi); + break; + case ENDFONTMETRICS: + code = normalEOF; + break; + case NOPE: + default: + code = parseError; + break; + } /* switch */ + + if ((error != earlyEOF) && (code < 0)) error = code; + + } /* while */ + + if ((error != earlyEOF) && (code < 0)) error = code; + + if (ident != NULL) { free(ident); ident = NULL; } + + return(error); + +} /* parseFile */ diff --git a/fonts/utilities/mm/parseAFM.h b/fonts/utilities/mm/parseAFM.h new file mode 100644 index 0000000000..8e35e14734 --- /dev/null +++ b/fonts/utilities/mm/parseAFM.h @@ -0,0 +1,321 @@ +/* + * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved. + * + * This file may be freely copied and redistributed as long as: + * 1) This entire notice continues to be included in the file, + * 2) If the file has been modified in any way, a notice of such + * modification is conspicuously indicated. + * + * PostScript, Display PostScript, and Adobe are registered trademarks of + * Adobe Systems Incorporated. + * + * ************************************************************************ + * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT + * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS + * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR + * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY + * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, + * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * ************************************************************************ + */ + +/* ParseAFM.h + * + * This header file is used in conjuction with the parseAFM.c file. + * Together these files provide the functionality to parse Adobe Font + * Metrics files and store the information in predefined data structures. + * It is intended to work with an application program that needs font metric + * information. The program can be used as is by making a procedure call to + * parse an AFM file and have the data stored, or an application developer + * may wish to customize the code. + * + * This header file defines the data structures used as well as the key + * strings that are currently recognized by this version of the AFM parser. + * This program is based on the document "Adobe Font Metrics Files, + * Specification Version 2.0". + * + * AFM files are separated into distinct sections of different data. Because + * of this, the parseAFM program can parse a specified file to only save + * certain sections of information based on the application's needs. A record + * containing the requested information will be returned to the application. + * + * AFM files are divided into five sections of data: + * 1) The Global Font Information + * 2) The Character Metrics Information + * 3) The Track Kerning Data + * 4) The Pair-Wise Kerning Data + * 5) The Composite Character Data + * + * Basically, the application can request any of these sections independent + * of what other sections are requested. In addition, in recognizing that + * many applications will want ONLY the x-width of characters and not all + * of the other character metrics information, there is a way to receive + * only the width information so as not to pay the storage cost for the + * unwanted data. An application should never request both the + * "quick and dirty" char metrics (widths only) and the Character Metrics + * Information since the Character Metrics Information will contain all + * of the character widths as well. + * + * There is a procedure in parseAFM.c, called parseFile, that can be + * called from any application wishing to get information from the AFM File. + * This procedure expects 3 parameters: a vaild file descriptor, a pointer + * to a (FontInfo *) variable (for which space will be allocated and then + * will be filled in with the data requested), and a mask specifying + * which data from the AFM File should be saved in the FontInfo structure. + * + * The flags that can be used to set the appropriate mask are defined below. + * In addition, several commonly used masks have already been defined. + * + * History: + * original: DSM Thu Oct 20 17:39:59 PDT 1988 + * modified: DSM Mon Jul 3 14:17:50 PDT 1989 + * - added 'storageProblem' return code + * - fixed typos + */ + +#include <stdio.h> + + + +/* your basic constants */ +#define TRUE 1 +#define FALSE 0 +#define EOL '\n' /* end-of-line indicator */ +#define MAX_NAME 4096 /* max length for identifiers */ +#define BOOL int +#define FLAGS int + + + +/* Flags that can be AND'ed together to specify exactly what + * information from the AFM file should be saved. + */ +#define P_G 0x01 /* 0000 0001 */ /* Global Font Info */ +#define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */ +#define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */ +#define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */ +#define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */ +#define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */ + + +/* Commonly used flags + */ +#define P_GW (P_G | P_W) +#define P_GM (P_G | P_M) +#define P_GMP (P_G | P_M | P_P) +#define P_GMK (P_G | P_M | P_P | P_T) +#define P_ALL (P_G | P_M | P_P | P_T | P_C) + + + +/* Possible return codes from the parseFile procedure. + * + * ok means there were no problems parsing the file. + * + * parseError means that there was some kind of parsing error, but the + * parser went on. This could include problems like the count for any given + * section does not add up to how many entries there actually were, or + * there was a key that was not recognized. The return record may contain + * vaild data or it may not. + * + * earlyEOF means that an End of File was encountered before expected. This + * may mean that the AFM file had been truncated, or improperly formed. + * + * storageProblem means that there were problems allocating storage for + * the data structures that would have contained the AFM data. + */ +#define ok 0 +#define parseError -1 +#define earlyEOF -2 +#define storageProblem -3 + + + +/************************* TYPES *********************************/ +/* Below are all of the data structure definitions. These structures + * try to map as closely as possible to grouping and naming of data + * in the AFM Files. + */ + + +/* Bounding box definition. Used for the Font BBox as well as the + * Character BBox. + */ +typedef struct +{ + int llx; /* lower left x-position */ + int lly; /* lower left y-position */ + int urx; /* upper right x-position */ + int ury; /* upper right y-position */ +} BBox; + + +/* Global Font information. + * The key that each field is associated with is in comments. For an + * explanation about each key and its value please refer to the AFM + * documentation (full title & version given above). + */ +typedef struct +{ + char *afmVersion; /* key: StartFontMetrics */ + char *fontName; /* key: FontName */ + char *fullName; /* key: FullName */ + char *familyName; /* key: FamilyName */ + char *weight; /* key: Weight */ + float italicAngle; /* key: ItalicAngle */ + BOOL isFixedPitch; /* key: IsFixedPitch */ + BBox fontBBox; /* key: FontBBox */ + int underlinePosition; /* key: UnderlinePosition */ + int underlineThickness; /* key: UnderlineThickness */ + char *version; /* key: Version */ + char *notice; /* key: Notice */ + char *encodingScheme; /* key: EncodingScheme */ + int capHeight; /* key: CapHeight */ + int xHeight; /* key: XHeight */ + int ascender; /* key: Ascender */ + int descender; /* key: Descender */ +} GlobalFontInfo; + + +/* Ligature definition is a linked list since any character can have + * any number of ligatures. + */ +typedef struct _t_ligature +{ + char *succ, *lig; + struct _t_ligature *next; +} Ligature; + + +/* Character Metric Information. This structure is used only if ALL + * character metric information is requested. If only the character + * widths is requested, then only an array of the character x-widths + * is returned. + * + * The key that each field is associated with is in comments. For an + * explanation about each key and its value please refer to the + * Character Metrics section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + int code, /* key: C */ + wx, /* key: WX */ + wy; /* together wx and wy are associated with key: W */ + char *name; /* key: N */ + BBox charBBox; /* key: B */ + Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */ +} CharMetricInfo; + + +/* Track kerning data structure. + * The fields of this record are the five values associated with every + * TrackKern entry. + * + * For an explanation about each value please refer to the + * Track Kerning section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + int degree; + float minPtSize, + minKernAmt, + maxPtSize, + maxKernAmt; +} TrackKernData; + + +/* Pair Kerning data structure. + * The fields of this record are the four values associated with every + * KP entry. For KPX entries, the yamt will be zero. + * + * For an explanation about each value please refer to the + * Pair Kerning section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + char *name1; + char *name2; + int xamt, + yamt; +} PairKernData; + + +/* PCC is a piece of a composite character. This is a sub structure of a + * compCharData described below. + * These fields will be filled in with the values from the key PCC. + * + * For an explanation about each key and its value please refer to the + * Composite Character section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + char *pccName; + int deltax, + deltay; +} Pcc; + + +/* Composite Character Information data structure. + * The fields ccName and numOfPieces are filled with the values associated + * with the key CC. The field pieces points to an array (size = numOfPieces) + * of information about each of the parts of the composite character. That + * array is filled in with the values from the key PCC. + * + * For an explanation about each key and its value please refer to the + * Composite Character section of the AFM documentation (full title + * & version given above). + */ +typedef struct +{ + char *ccName; + int numOfPieces; + Pcc *pieces; +} CompCharData; + + +/* FontInfo + * Record type containing pointers to all of the other data + * structures containing information about a font. + * A a record of this type is filled with data by the + * parseFile function. + */ +typedef struct +{ + GlobalFontInfo *gfi; /* ptr to a GlobalFontInfo record */ + int *cwi; /* ptr to 256 element array of just char widths */ + int numOfChars; /* number of entries in char metrics array */ + CharMetricInfo *cmi; /* ptr to char metrics array */ + int numOfTracks; /* number to entries in track kerning array */ + TrackKernData *tkd; /* ptr to track kerning array */ + int numOfPairs; /* number to entries in pair kerning array */ + PairKernData *pkd; /* ptr to pair kerning array */ + int numOfComps; /* number to entries in comp char array */ + CompCharData *ccd; /* ptr to comp char array */ +} FontInfo; + + + +/************************* PROCEDURES ****************************/ + +/* Call this procedure to do the grunt work of parsing an AFM file. + * + * "fp" should be a valid file pointer to an AFM file. + * + * "fi" is a pointer to a pointer to a FontInfo record sturcture + * (defined above). Storage for the FontInfo structure will be + * allocated in parseFile and the structure will be filled in + * with the requested data from the AFM File. + * + * "flags" is a mask with bits set representing what data should + * be saved. Defined above are valid flags that can be used to set + * the mask, as well as a few commonly used masks. + * + * The possible return codes from parseFile are defined above. + */ + +extern int parseFile ( /* FILE *fp; FontInfo **fi; FLAGS flags; */ ); diff --git a/fonts/utilities/mm/parseAFMclient.c b/fonts/utilities/mm/parseAFMclient.c new file mode 100644 index 0000000000..02d24a42d8 --- /dev/null +++ b/fonts/utilities/mm/parseAFMclient.c @@ -0,0 +1,346 @@ +/* + * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved. + * + * This file may be freely copied and redistributed as long as: + * 1) This entire notice continues to be included in the file, + * 2) If the file has been modified in any way, a notice of such + * modification is conspicuously indicated. + * + * PostScript, Display PostScript, and Adobe are registered trademarks of + * Adobe Systems Incorporated. + * + * ************************************************************************ + * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT + * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS + * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR + * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY + * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, + * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * ************************************************************************ + */ + +/* parseAFMclient.c + * + * This file is an example of how an application might use the provided + * AFM Parser (parseAFM.c). + * + * In a nutshell, the client of the parser (like this file) chooses + * the AFM File that it wishes to have parsed, opens the file for + * reading (and does any/all error handling associated with that task), + * and passes the resulting file pointer to the procedure "parseFile" + * (in parseAFM.c). In addition to the file pointer, the client also + * needs to pass a pointer to a FontInfo record type (for which storage + * will be allocated and data filled in), and a mask representing which + * sections of the AFM should be saved in the FontInfo record. + * + * In the procedure "main", the mask is built from command line switches, + * but your application, of course, can set that mask any way you prefer. + * "main" then calls the "parseFile" procedure (of parseAFM.c) to do the + * grunt work, and checks the error codes upon "parseFile"'s return. + * + * The rest of this sample application is a collection of print routines + * that show how to reference each of the sections of data and a + * "freeStorage" routine (that many unix programmers may feel they + * don't need but is included for portability to other systems that do + * need to manage storage). The print procedures are there just to + * give meaning to this application, and hopefully your application + * will use the data collected from the AFM file in a more useful way. + * + * History: + * original: DSM Thu Oct 20 17:39:59 PDT 1988 + * modified: DSM Mon Jul 3 14:17:50 PDT 1989 + * - added 'storageProblem' check in main + */ + +#include <stdio.h> +#include "parseAFM.h" + + +/*************************** GLOBALS ***************************/ +FontInfo *fi; +FLAGS myflags = 0; + + +/*************************** printGlobals **********************/ + +printGlobals() +{ + printf("StartFontMetrics %s\n", fi->gfi->afmVersion); + printf("FontName %s\n", fi->gfi->fontName); + printf("FullName %s\n", fi->gfi->fullName); + printf("FamilyName %s\n", fi->gfi->familyName); + printf("Weight %s\n", fi->gfi->weight); + printf("ItalicAngle %3.1f\n", fi->gfi->italicAngle); + if (fi->gfi->isFixedPitch) + printf("IsFixedPitch true\n"); + else + printf("IsFixedPitch false\n"); + printf("UnderlinePosition %d\n", fi->gfi->underlinePosition); + printf("UnderlineThickness %d\n", fi->gfi->underlineThickness); + printf("Version %s\n", fi->gfi->version); + printf("FontBBox %d %d %d %d\n", + fi->gfi->fontBBox.llx, fi->gfi->fontBBox.lly, + fi->gfi->fontBBox.urx, fi->gfi->fontBBox.ury); + printf("Notice %s\n", fi->gfi->notice); + printf("EncodingScheme %s\n", fi->gfi->encodingScheme); + printf("CapHeight %d\n", fi->gfi->capHeight); + printf("XHeight %d\n", fi->gfi->xHeight); + printf("Descender %d\n", fi->gfi->descender); + printf("Ascender %d\n", fi->gfi->ascender); + +} /* printGlobals */ + + +/*************************** printCharWidths *********************/ +printCharWidths() +{ + int i = 0; + for (i = 0; i < 256; ++i) + printf(" code: %3d width: %4d\n", i, fi->cwi[i]); + printf("\n"); + +} /* printCharWidths */ + + +/*************************** printAllCharMetrics *****************/ +printAllCharMetrics() +{ + int i = 0; + CharMetricInfo *temp = fi->cmi; + Ligature *node = temp->ligs; + printf("StartCharMetrics %d\n", fi->numOfChars); + for (i = 0; i < fi->numOfChars; ++i) + { + printf( + "C %d ; WX %d ; N %s ; B %d %d %d %d ;", + temp->code, temp->wx, temp->name, temp->charBBox.llx, + temp->charBBox.lly, temp->charBBox.urx, temp->charBBox.ury); + for (node = temp->ligs; node != NULL; node = node->next) + { + printf(" L %s %s ;", node->succ, node->lig); + } + printf("\n"); + temp++; + } /* for */ + printf("EndCharMetrics\n"); + +} /* printAllCharMetrics */ + + +/*************************** printKernPairData ******************/ +printKernPairData() +{ + int i = 0; + PairKernData *pkd = fi->pkd; + + if (fi->numOfPairs != 0) + { + printf("StartKernData\n"); + printf("StartKernPairs %d\n",fi->numOfPairs); + for (i = 0; i < fi->numOfPairs; ++i) + printf( + "KPX %s %s %d\n", + pkd[i].name1, pkd[i].name2, pkd[i].xamt); +/* "KPX %s %s %d %d\n", + pkd[i].name1, pkd[i].name2, pkd[i].xamt, pkd[i].yamt); */ + printf("EndKernPairs\n"); + printf("EndKernData\n"); + } + +} /* printKernPairData */ + + +/*************************** printKernTrackData *******************/ +printKernTrackData() +{ + int i = 0; + TrackKernData *tkd = fi->tkd; + + if (fi->numOfTracks != 0) + { + printf("StartTrackKern %d\n",fi->numOfTracks); + for (i = 0; i < fi->numOfTracks; ++i) + printf( + "TrackKern %d %d %d %d %d\n", + tkd[i].degree, tkd[i].minPtSize, tkd[i].minKernAmt, + tkd[i].maxPtSize, tkd[i].maxKernAmt); + printf("EndTrackKern\n"); + } + +} /* printKernTrackData */ + + +/*************************** printCompCharData ********************/ +printCompCharData() +{ + int i = 0, j = 0; + CompCharData *ccd = fi->ccd; + + if (fi->numOfComps != 0) + { + printf("StartComposites %d\n",fi->numOfComps); + for (i = 0; i < fi->numOfComps; ++i) + { + printf("CC %s %d ;", + ccd[i].ccName, ccd[i].numOfPieces); + for (j = 0; j < ccd[i].numOfPieces; ++j) + printf( + " PCC %s %d %d ;", ccd[i].pieces[j].pccName, + ccd[i].pieces[j].deltax, ccd[i].pieces[j].deltay); + printf("\n"); + } + printf("EndComposites\n"); + } + +} /* printCompCharData */ + + + +/*************************** freeStorage ***********************/ + +freeStorage() +{ + if (fi != NULL) + { + if (fi->gfi != NULL) + { + free(fi->gfi->afmVersion); fi->gfi->afmVersion = NULL; + free(fi->gfi->fontName); fi->gfi->fontName = NULL; + free(fi->gfi->fullName); fi->gfi->fullName = NULL; + free(fi->gfi->familyName); fi->gfi->familyName = NULL; + free(fi->gfi->weight); fi->gfi->weight = NULL; + free(fi->gfi->version); fi->gfi->version = NULL; + free(fi->gfi->notice); fi->gfi->notice = NULL; + free(fi->gfi->encodingScheme); fi->gfi->encodingScheme = NULL; + free(fi->gfi); fi->gfi = NULL; + } + + if (fi->cwi != NULL) + { free(fi->cwi); fi->cwi = NULL; } + + if (fi->cmi != NULL) + { + int i = 0; + CharMetricInfo *temp = fi->cmi; + Ligature *node = temp->ligs; + + for (i = 0; i < fi->numOfChars; ++i) + { + for (node = temp->ligs; node != NULL; node = node->next) + { + free(node->succ); node->succ = NULL; + free(node->lig); node->lig = NULL; + } + + free(temp->name); temp->name = NULL; + temp++; + } + + free(fi->cmi); fi->cmi = NULL; + } + + if (fi->tkd != NULL) + { free(fi->tkd); fi->tkd = NULL; } + + if (fi->pkd != NULL) + { + free(fi->pkd->name1); fi->pkd->name1 = NULL; + free(fi->pkd->name2); fi->pkd->name2 = NULL; + free(fi->pkd); fi->pkd = NULL; + } + + if (fi->ccd != NULL) + { + int i = 0, j = 0; + CompCharData *ccd = fi->ccd; + + for (i = 0; i < fi->numOfComps; ++i) + { + for (j = 0; j < ccd[i].numOfPieces; ++j) + { + free(ccd[i].pieces[j].pccName); + ccd[i].pieces[j].pccName = NULL; + } + + free(ccd[i].ccName); ccd[i].ccName = NULL; + } + + free(fi->ccd); fi->ccd = NULL; + } + + free(fi); + + } /* if */ + +} /* freeStorage */ + + +/*************************** printValues **************************/ + +printValues() +{ + if (fi->gfi != NULL) printGlobals(); + if (fi->cmi != NULL) printAllCharMetrics(); + if (fi->pkd != NULL) printKernPairData(); + if (fi->tkd != NULL) printKernTrackData(); + if (fi->ccd != NULL) printCompCharData(); + printf("EndFontMetrics\n"); + +} /* printValues */ + + + +/*************************** main *********************************/ + +main (argc, argv) + int argc; + char **argv; +{ + char *filename, *prog = *argv; + FILE *fp; + + ++argv; --argc; myflags |= P_ALL; + + if (!argc) + { + printf(" usage: parseAFM [AFM File]\n"); + exit(0); + } + else + filename = *argv; + + if (!filename[0]) + { + printf ("*** ERROR: can't open. filename is missing.\n", + filename ); + return 0; + } + + fp = fopen(filename, "r" ); + if (fp == NULL) + { + printf ("*** ERROR: can't find: %s\n", filename ); + exit(1); + } + + switch (parseFile(fp, &fi, myflags)) + { + case parseError: + printf("*** ERROR: problem in parsing the AFM File.\n"); + case ok: + fclose(fp); + printValues(); + freeStorage(); + break; + case earlyEOF: + printf("The AFM File ended prematurely.\n"); + break; + case storageProblem: + printf("*** ERROR: problem allocating storage.\n"); + break; + default: + break; + } + +} /* main */ |