summaryrefslogtreecommitdiff
path: root/fonts/utilities/mm
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /fonts/utilities/mm
Initial commit
Diffstat (limited to 'fonts/utilities/mm')
-rw-r--r--fonts/utilities/mm/makefile9
-rw-r--r--fonts/utilities/mm/makeinstance.sh70
-rw-r--r--fonts/utilities/mm/mmafm.c493
-rw-r--r--fonts/utilities/mm/mmfont183
-rw-r--r--fonts/utilities/mm/parseAFM.c1226
-rw-r--r--fonts/utilities/mm/parseAFM.h321
-rw-r--r--fonts/utilities/mm/parseAFMclient.c346
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 */