2 * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
4 * This file may be freely copied and redistributed as long as:
5 * 1) This entire notice continues to be included in the file,
6 * 2) If the file has been modified in any way, a notice of such
7 * modification is conspicuously indicated.
9 * PostScript, Display PostScript, and Adobe are registered trademarks of
10 * Adobe Systems Incorporated.
12 * ************************************************************************
13 * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
14 * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
15 * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
16 * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
17 * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
18 * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
20 * ************************************************************************
25 * - some names changed to avoid conflicts with T1lib
26 * - changed to ANSI C prototypes, as used by MDVI
32 * This file is used in conjuction with the parseAFM.h header file.
33 * This file contains several procedures that are used to parse AFM
34 * files. It is intended to work with an application program that needs
35 * font metric information. The program can be used as is by making a
36 * procedure call to "parseFile" (passing in the expected parameters)
37 * and having it fill in a data structure with the data from the
38 * AFM file, or an application developer may wish to customize this
41 * There is also a file, parseAFMclient.c, that is a sample application
42 * showing how to call the "parseFile" procedure and how to use the data
43 * after "parseFile" has returned.
45 * Please read the comments in parseAFM.h and parseAFMclient.c.
48 * original: DSM Thu Oct 20 17:39:59 PDT 1988
49 * modified: DSM Mon Jul 3 14:17:50 PDT 1989
50 * - added 'storageProblem' return code
51 * - fixed bug of not allocating extra byte for string duplication
53 * modified: DSM Tue Apr 3 11:18:34 PDT 1990
54 * - added free(ident) at end of parseFile routine
55 * modified: DSM Tue Jun 19 10:16:29 PDT 1990
56 * - changed (width == 250) to (width = 250) in initializeArray
63 #include <stdlib.h> /* added for MDVI */
64 #include <string.h> /* added for MDVI */
73 #define lineterm EOL /* line terminating character */
74 #define normalEOF 1 /* return code from parsing routines used only */
76 #define Space "space" /* used in string comparison to look for the width */
77 /* of the space character to init the widths array */
78 #define False "false" /* used in string comparison to check the value of */
79 /* boolean keys (e.g. IsFixedPitch) */
81 #define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
85 /*************************** GLOBALS ***********************/
87 static char *ident = NULL; /* storage buffer for keywords */
90 /* "shorts" for fast case statement
91 * The values of each of these enumerated items correspond to an entry in the
92 * table of strings defined below. Therefore, if you add a new string as
93 * new keyword into the keyStrings table, you must also add a corresponding
94 * parseKey AND it MUST be in the same position!
96 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
97 * keywords must be placed in lexicographical order, below. [Therefore, the
98 * enumerated items are not necessarily in lexicographical order, depending
99 * on the name chosen. BUT, they must be placed in the same position as the
100 * corresponding key string.] The NOPE shall remain in the last position,
101 * since it does not correspond to any key string, and it is used in the
102 * "recognize" procedure to calculate how many possible keys there are.
106 ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
107 DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
108 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
109 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH,
110 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
111 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
112 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
113 STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
114 UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
117 /* keywords for the system:
118 * This a table of all of the current strings that are vaild AFM keys.
119 * Each entry can be referenced by the appropriate parseKey value (an
120 * enumerated data type defined above). If you add a new keyword here,
121 * a corresponding parseKey MUST be added to the enumerated data type
122 * defined above, AND it MUST be added in the same position as the
123 * string is in this table.
125 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
126 * must be placed in lexicographical order. And, NULL should remain at the
130 static char *keyStrings[] = {
131 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
132 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
133 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
134 "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch",
135 "ItalicAngle", "KP", "KPX", "L", "N",
136 "Notice", "PCC", "StartCharMetrics", "StartComposites",
137 "StartFontMetrics", "StartKernData", "StartKernPairs",
138 "StartTrackKern", "TrackKern", "UnderlinePosition",
139 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
142 /*************************** PARSING ROUTINES **************/
144 /*************************** token *************************/
146 /* A "AFM File Conventions" tokenizer. That means that it will
147 * return the next token delimited by white space. See also
148 * the `linetoken' routine, which does a similar thing but
149 * reads all tokens until the next end-of-line.
152 static char *token(FILE *stream)
156 /* skip over white space */
157 while ((ch = fgetc(stream)) == ' ' || ch == lineterm ||
158 ch == ',' || ch == '\t' || ch == ';');
161 while (ch != EOF && ch != ' ' && ch != lineterm
162 && ch != '\t' && ch != ':' && ch != ';')
168 if (ch == EOF && idx < 1) return ((char *)NULL);
169 if (idx >= 1 && ch != ':' ) ungetc(ch, stream);
170 if (idx < 1 ) ident[idx++] = ch; /* single-character token */
173 return(ident); /* returns pointer to the token */
178 /*************************** linetoken *************************/
180 /* "linetoken" will get read all tokens until the EOL character from
181 * the given stream. This is used to get any arguments that can be
182 * more than one word (like Comment lines and FullName).
185 static char *linetoken(FILE *stream)
189 while ((ch = fgetc(stream)) == ' ' || ch == '\t' );
192 while (ch != EOF && ch != lineterm)
201 return(ident); /* returns pointer to the token */
206 /*************************** recognize *************************/
208 /* This function tries to match a string to a known list of
209 * valid AFM entries (check the keyStrings array above).
210 * "ident" contains everything from white space through the
211 * next space, tab, or ":" character.
213 * The algorithm is a standard Knuth binary search.
216 static enum parseKey recognize(char *ident)
218 int lower = 0, upper = (int) NOPE, midpoint, cmpvalue;
221 while ((upper >= lower) && !found)
223 midpoint = (lower + upper)/2;
224 if (keyStrings[midpoint] == NULL) break;
225 cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME);
226 if (cmpvalue == 0) found = TRUE;
227 else if (cmpvalue < 0) upper = midpoint - 1;
228 else lower = midpoint + 1;
231 if (found) return (enum parseKey) midpoint;
237 /************************* parseGlobals *****************************/
239 /* This function is called by "parseFile". It will parse the AFM File
240 * up to the "StartCharMetrics" keyword, which essentially marks the
241 * end of the Global Font Information and the beginning of the character
242 * metrics information.
244 * If the caller of "parseFile" specified that it wanted the Global
245 * Font Information (as defined by the "AFM File Specification"
246 * document), then that information will be stored in the returned
249 * Any Global Font Information entries that are not found in a
250 * given file, will have the usual default initialization value
251 * for its type (i.e. entries of type int will be 0, etc).
253 * This function returns an error code specifying whether there was
254 * a premature EOF or a parsing error. This return value is used by
255 * parseFile to determine if there is more file to parse.
258 static BOOL parseGlobals(FILE *fp, GlobalFontInfo *gfi)
260 BOOL cont = TRUE, save = (gfi != NULL);
262 register char *keyword;
269 /* Have reached an early and unexpected EOF. */
270 /* Set flag and stop parsing */
273 break; /* get out of loop */
276 /* get tokens until the end of the Global Font info section */
277 /* without saving any of the data */
278 switch (recognize(keyword))
280 case STARTCHARMETRICS:
291 /* otherwise parse entire global font info section, */
292 /* saving the data */
293 switch(recognize(keyword))
295 case STARTFONTMETRICS:
297 gfi->afmVersion = (char *) malloc(strlen(keyword) + 1);
298 strcpy(gfi->afmVersion, keyword);
301 keyword = linetoken(fp);
305 gfi->fontName = (char *) malloc(strlen(keyword) + 1);
306 strcpy(gfi->fontName, keyword);
310 gfi->encodingScheme = (char *)
311 malloc(strlen(keyword) + 1);
312 strcpy(gfi->encodingScheme, keyword);
315 keyword = linetoken(fp);
316 gfi->fullName = (char *) malloc(strlen(keyword) + 1);
317 strcpy(gfi->fullName, keyword);
320 keyword = linetoken(fp);
321 gfi->familyName = (char *) malloc(strlen(keyword) + 1);
322 strcpy(gfi->familyName, keyword);
326 gfi->weight = (char *) malloc(strlen(keyword) + 1);
327 strcpy(gfi->weight, keyword);
331 gfi->italicAngle = atof(keyword);
332 if (errno == ERANGE) error = parseError;
336 if (MATCH(keyword, False))
337 gfi->isFixedPitch = 0;
339 gfi->isFixedPitch = 1;
341 case UNDERLINEPOSITION:
343 gfi->underlinePosition = atoi(keyword);
345 case UNDERLINETHICKNESS:
347 gfi->underlineThickness = atoi(keyword);
351 gfi->version = (char *) malloc(strlen(keyword) + 1);
352 strcpy(gfi->version, keyword);
355 keyword = linetoken(fp);
356 gfi->notice = (char *) malloc(strlen(keyword) + 1);
357 strcpy(gfi->notice, keyword);
361 gfi->fontBBox.llx = atoi(keyword);
363 gfi->fontBBox.lly = atoi(keyword);
365 gfi->fontBBox.urx = atoi(keyword);
367 gfi->fontBBox.ury = atoi(keyword);
371 gfi->capHeight = atoi(keyword);
375 gfi->xHeight = atoi(keyword);
379 gfi->descender = atoi(keyword);
383 gfi->ascender = atoi(keyword);
385 case STARTCHARMETRICS:
405 #if 0 /* this function does not seem to be used anywhere */
406 /************************* initializeArray ************************/
408 /* Unmapped character codes are (at Adobe Systems) assigned the
409 * width of the space character (if one exists) else they get the
410 * value of 250 ems. This function initializes all entries in the
411 * char widths array to have this value. Then any mapped character
412 * codes will be replaced with the width of the appropriate character
413 * when parsing the character metric section.
415 * This function parses the Character Metrics Section looking
416 * for a space character (by comparing character names). If found,
417 * the width of the space character will be used to initialize the
418 * values in the array of character widths.
420 * Before returning, the position of the read/write pointer of the
421 * file is reset to be where it was upon entering this function.
424 static int initializeArray(FILE *fp, int *cwi)
426 BOOL cont = TRUE, found = FALSE;
427 long opos = ftell(fp);
428 int code = 0, width = 0, i = 0, error = 0;
429 register char *keyword;
437 break; /* get out of loop */
439 switch(recognize(keyword))
442 keyword = linetoken(fp);
445 code = atoi(token(fp));
448 width = atoi(token(fp));
452 if (MATCH(keyword, Space))
475 for (i = 0; i < 256; ++i)
482 } /* initializeArray */
485 /************************* parseCharWidths **************************/
487 /* This function is called by "parseFile". It will parse the AFM File
488 * up to the "EndCharMetrics" keyword. It will save the character
489 * width info (as opposed to all of the character metric information)
490 * if requested by the caller of parseFile. Otherwise, it will just
491 * parse through the section without saving any information.
493 * If data is to be saved, parseCharWidths is passed in a pointer
494 * to an array of widths that has already been initialized by the
495 * standard value for unmapped character codes. This function parses
496 * the Character Metrics section only storing the width information
497 * for the encoded characters into the array using the character code
498 * as the index into that array.
500 * This function returns an error code specifying whether there was
501 * a premature EOF or a parsing error. This return value is used by
502 * parseFile to determine if there is more file to parse.
505 static int parseCharWidths(FILE *fp, int *cwi)
507 BOOL cont = TRUE, save = (cwi != NULL);
508 int pos = 0, error = ok;
509 register char *keyword;
514 /* Have reached an early and unexpected EOF. */
515 /* Set flag and stop parsing */
519 break; /* get out of loop */
522 /* get tokens until the end of the Char Metrics section without */
523 /* saving any of the data*/
524 switch (recognize(keyword))
537 /* otherwise parse entire char metrics section, saving */
538 /* only the char x-width info */
539 switch(recognize(keyword))
542 keyword = linetoken(fp);
549 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
550 keyword = token(fp); keyword = token(fp); /* eat values */
555 if (pos >= 0) /* ignore unmapped chars */
556 cwi[pos] = atoi(keyword);
565 case CHARNAME: /* eat values (so doesn't cause parseError) */
569 keyword = token(fp); keyword = token(fp);
570 keyword = token(fp); keyword = token(fp);
573 keyword = token(fp); keyword = token(fp);
584 } /* parseCharWidths */
587 /************************* parseCharMetrics ************************/
589 /* This function is called by parseFile if the caller of parseFile
590 * requested that all character metric information be saved
591 * (as opposed to only the character width information).
593 * parseCharMetrics is passed in a pointer to an array of records
594 * to hold information on a per character basis. This function
595 * parses the Character Metrics section storing all character
596 * metric information for the ALL characters (mapped and unmapped)
599 * This function returns an error code specifying whether there was
600 * a premature EOF or a parsing error. This return value is used by
601 * parseFile to determine if there is more file to parse.
604 static int parseCharMetrics(FILE *fp, FontInfo *fi)
606 BOOL cont = TRUE, firstTime = TRUE;
607 int error = ok, count = 0;
608 register CharMetricInfo *temp = fi->cmi;
609 register char *keyword;
617 break; /* get out of loop */
619 switch(recognize(keyword))
622 keyword = linetoken(fp);
625 if (count < fi->numOfChars)
627 if (firstTime) firstTime = FALSE;
629 temp->code = atoi(token(fp));
639 temp->wx = atoi(token(fp));
640 temp->wy = atoi(token(fp));
643 temp->wx = atoi(token(fp));
647 temp->name = (char *) malloc(strlen(keyword) + 1);
648 strcpy(temp->name, keyword);
651 temp->charBBox.llx = atoi(token(fp));
652 temp->charBBox.lly = atoi(token(fp));
653 temp->charBBox.urx = atoi(token(fp));
654 temp->charBBox.ury = atoi(token(fp));
657 Ligature **tail = &(temp->ligs);
658 Ligature *node = *tail;
662 while (node->next != NULL)
664 tail = &(node->next);
667 *tail = (Ligature *) calloc(1, sizeof(Ligature));
669 (*tail)->succ = (char *) malloc(strlen(keyword) + 1);
670 strcpy((*tail)->succ, keyword);
672 (*tail)->lig = (char *) malloc(strlen(keyword) + 1);
673 strcpy((*tail)->lig, keyword);
689 if ((error == ok) && (count != fi->numOfChars))
694 } /* parseCharMetrics */
698 /************************* parseTrackKernData ***********************/
700 /* This function is called by "parseFile". It will parse the AFM File
701 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
702 * track kerning data if requested by the caller of parseFile.
704 * parseTrackKernData is passed in a pointer to the FontInfo record.
705 * If data is to be saved, the FontInfo record will already contain
706 * a valid pointer to storage for the track kerning data.
708 * This function returns an error code specifying whether there was
709 * a premature EOF or a parsing error. This return value is used by
710 * parseFile to determine if there is more file to parse.
713 static int parseTrackKernData(FILE *fp, FontInfo *fi)
715 BOOL cont = TRUE, save = (fi->tkd != NULL);
716 int pos = 0, error = ok, tcount = 0;
717 register char *keyword;
726 break; /* get out of loop */
729 /* get tokens until the end of the Track Kerning Data */
730 /* section without saving any of the data */
731 switch(recognize(keyword))
745 /* otherwise parse entire Track Kerning Data section, */
746 /* saving the data */
747 switch(recognize(keyword))
750 keyword = linetoken(fp);
753 if (tcount < fi->numOfTracks)
756 fi->tkd[pos].degree = atoi(keyword);
758 fi->tkd[pos].minPtSize = atof(keyword);
759 if (errno == ERANGE) error = parseError;
761 fi->tkd[pos].minKernAmt = atof(keyword);
762 if (errno == ERANGE) error = parseError;
764 fi->tkd[pos].maxPtSize = atof(keyword);
765 if (errno == ERANGE) error = parseError;
767 fi->tkd[pos++].maxKernAmt = atof(keyword);
768 if (errno == ERANGE) error = parseError;
792 if (error == ok && tcount != fi->numOfTracks)
797 } /* parseTrackKernData */
800 /************************* parsePairKernData ************************/
802 /* This function is called by "parseFile". It will parse the AFM File
803 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
804 * the pair kerning data if requested by the caller of parseFile.
806 * parsePairKernData is passed in a pointer to the FontInfo record.
807 * If data is to be saved, the FontInfo record will already contain
808 * a valid pointer to storage for the pair kerning data.
810 * This function returns an error code specifying whether there was
811 * a premature EOF or a parsing error. This return value is used by
812 * parseFile to determine if there is more file to parse.
815 static int parsePairKernData(FILE *fp, FontInfo *fi)
817 BOOL cont = TRUE, save = (fi->pkd != NULL);
818 int pos = 0, error = ok, pcount = 0;
819 register char *keyword;
828 break; /* get out of loop */
831 /* get tokens until the end of the Pair Kerning Data */
832 /* section without saving any of the data */
833 switch(recognize(keyword))
847 /* otherwise parse entire Pair Kerning Data section, */
848 /* saving the data */
849 switch(recognize(keyword))
852 keyword = linetoken(fp);
855 if (pcount < fi->numOfPairs)
858 fi->pkd[pos].name1 = (char *)
859 malloc(strlen(keyword) + 1);
860 strcpy(fi->pkd[pos].name1, keyword);
862 fi->pkd[pos].name2 = (char *)
863 malloc(strlen(keyword) + 1);
864 strcpy(fi->pkd[pos].name2, keyword);
866 fi->pkd[pos].xamt = atoi(keyword);
868 fi->pkd[pos++].yamt = atoi(keyword);
878 if (pcount < fi->numOfPairs)
881 fi->pkd[pos].name1 = (char *)
882 malloc(strlen(keyword) + 1);
883 strcpy(fi->pkd[pos].name1, keyword);
885 fi->pkd[pos].name2 = (char *)
886 malloc(strlen(keyword) + 1);
887 strcpy(fi->pkd[pos].name2, keyword);
889 fi->pkd[pos++].xamt = atoi(keyword);
913 if (error == ok && pcount != fi->numOfPairs)
918 } /* parsePairKernData */
921 /************************* parseCompCharData **************************/
923 /* This function is called by "parseFile". It will parse the AFM File
924 * up to the "EndComposites" keyword. It will save the composite
925 * character data if requested by the caller of parseFile.
927 * parseCompCharData is passed in a pointer to the FontInfo record, and
928 * a boolean representing if the data should be saved.
930 * This function will create the appropriate amount of storage for
931 * the composite character data and store a pointer to the storage
932 * in the FontInfo record.
934 * This function returns an error code specifying whether there was
935 * a premature EOF or a parsing error. This return value is used by
936 * parseFile to determine if there is more file to parse.
939 static int parseCompCharData(FILE *fp, FontInfo *fi)
941 BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
942 int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0;
943 register char *keyword;
949 /* Have reached an early and unexpected EOF. */
950 /* Set flag and stop parsing */
953 break; /* get out of loop */
955 if (ccount > fi->numOfComps)
958 break; /* get out of loop */
961 /* get tokens until the end of the Composite Character info */
962 /* section without saving any of the data */
963 switch(recognize(keyword))
976 /* otherwise parse entire Composite Character info section, */
977 /* saving the data */
978 switch(recognize(keyword))
981 keyword = linetoken(fp);
984 if (ccount < fi->numOfComps)
987 if (pcount != fi->ccd[pos].numOfPieces)
990 if (firstTime) firstTime = FALSE;
992 fi->ccd[pos].ccName = (char *)
993 malloc(strlen(keyword) + 1);
994 strcpy(fi->ccd[pos].ccName, keyword);
996 fi->ccd[pos].numOfPieces = atoi(keyword);
997 fi->ccd[pos].pieces = (Pcc *)
998 calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
1009 if (pcount < fi->ccd[pos].numOfPieces)
1011 keyword = token(fp);
1012 fi->ccd[pos].pieces[j].pccName = (char *)
1013 malloc(strlen(keyword) + 1);
1014 strcpy(fi->ccd[pos].pieces[j].pccName, keyword);
1015 keyword = token(fp);
1016 fi->ccd[pos].pieces[j].deltax = atoi(keyword);
1017 keyword = token(fp);
1018 fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
1027 case ENDFONTMETRICS:
1038 if (error == ok && ccount != fi->numOfComps)
1043 } /* parseCompCharData */
1048 /*************************** 'PUBLIC' FUNCTION ********************/
1051 /*************************** parseFile *****************************/
1053 /* parseFile is the only 'public' procedure available. It is called
1054 * from an application wishing to get information from an AFM file.
1055 * The caller of this function is responsible for locating and opening
1056 * an AFM file and handling all errors associated with that task.
1058 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1059 * to a (FontInfo *) variable (for which storage will be allocated and
1060 * the data requested filled in), and a mask specifying which
1061 * data from the AFM File should be saved in the FontInfo structure.
1063 * The file will be parsed and the requested data will be stored in
1064 * a record of type FontInfo (refer to ParseAFM.h).
1066 * parseFile returns an error code as defined in parseAFM.h.
1068 * The position of the read/write pointer associated with the file
1069 * pointer upon return of this function is undefined.
1072 extern int afm_parse_file(FILE *fp, FontInfo **fi, FLAGS flags)
1075 int code = ok; /* return code from each of the parsing routines */
1076 int error = ok; /* used as the return code from this function */
1078 register char *keyword; /* used to store a token */
1081 /* storage data for the global variable ident */
1082 ident = (char *) calloc(MAX_NAME, sizeof(char));
1083 if (ident == NULL) {error = storageProblem; return(error);}
1085 (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
1086 if ((*fi) == NULL) {error = storageProblem; return(error);}
1090 (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
1091 if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}
1094 /* The AFM File begins with Global Font Information. This section */
1095 /* will be parsed whether or not information should be saved. */
1096 code = parseGlobals(fp, (*fi)->gfi);
1098 if (code < 0) error = code;
1100 /* The Global Font Information is followed by the Character Metrics */
1101 /* section. Which procedure is used to parse this section depends on */
1102 /* how much information should be saved. If all of the metrics info */
1103 /* is wanted, parseCharMetrics is called. If only the character widths */
1104 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1105 /* be called in the case that no character data is to be saved, just */
1106 /* to parse through the section. */
1108 if ((code != normalEOF) && (code != earlyEOF))
1110 (*fi)->numOfChars = atoi(token(fp));
1111 if (flags & (P_M ^ P_W))
1113 (*fi)->cmi = (CharMetricInfo *)
1114 calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
1115 if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
1116 code = parseCharMetrics(fp, *fi);
1122 (*fi)->cwi = (int *) calloc(256, sizeof(int));
1123 if ((*fi)->cwi == NULL)
1125 error = storageProblem;
1129 /* parse section regardless */
1130 code = parseCharWidths(fp, (*fi)->cwi);
1134 if ((error != earlyEOF) && (code < 0)) error = code;
1136 /* The remaining sections of the AFM are optional. This code will */
1137 /* look at the next keyword in the file to determine what section */
1138 /* is next, and then allocate the appropriate amount of storage */
1139 /* for the data (if the data is to be saved) and call the */
1140 /* appropriate parsing routine to parse the section. */
1142 while ((code != normalEOF) && (code != earlyEOF))
1144 keyword = token(fp);
1145 if (keyword == NULL)
1146 /* Have reached an early and unexpected EOF. */
1147 /* Set flag and stop parsing */
1150 break; /* get out of loop */
1152 switch(recognize(keyword))
1158 case STARTTRACKKERN:
1159 keyword = token(fp);
1162 (*fi)->numOfTracks = atoi(keyword);
1163 (*fi)->tkd = (TrackKernData *)
1164 calloc((*fi)->numOfTracks, sizeof(TrackKernData));
1165 if ((*fi)->tkd == NULL)
1167 error = storageProblem;
1171 code = parseTrackKernData(fp, *fi);
1173 case STARTKERNPAIRS:
1174 keyword = token(fp);
1177 (*fi)->numOfPairs = atoi(keyword);
1178 (*fi)->pkd = (PairKernData *)
1179 calloc((*fi)->numOfPairs, sizeof(PairKernData));
1180 if ((*fi)->pkd == NULL)
1182 error = storageProblem;
1186 code = parsePairKernData(fp, *fi);
1188 case STARTCOMPOSITES:
1189 keyword = token(fp);
1192 (*fi)->numOfComps = atoi(keyword);
1193 (*fi)->ccd = (CompCharData *)
1194 calloc((*fi)->numOfComps, sizeof(CompCharData));
1195 if ((*fi)->ccd == NULL)
1197 error = storageProblem;
1201 code = parseCompCharData(fp, *fi);
1203 case ENDFONTMETRICS:
1212 if ((error != earlyEOF) && (code < 0)) error = code;
1216 if ((error != earlyEOF) && (code < 0)) error = code;
1218 if (ident != NULL) { free(ident); ident = NULL; }
1224 /* added for MDVI: this function was copied from `parseAFMclient.c' */
1226 void afm_free_fontinfo(FontInfo *fi)
1230 if (fi->gfi != NULL)
1232 free(fi->gfi->afmVersion); fi->gfi->afmVersion = NULL;
1233 free(fi->gfi->fontName); fi->gfi->fontName = NULL;
1234 free(fi->gfi->fullName); fi->gfi->fullName = NULL;
1235 free(fi->gfi->familyName); fi->gfi->familyName = NULL;
1236 free(fi->gfi->weight); fi->gfi->weight = NULL;
1237 free(fi->gfi->version); fi->gfi->version = NULL;
1238 free(fi->gfi->notice); fi->gfi->notice = NULL;
1239 free(fi->gfi->encodingScheme); fi->gfi->encodingScheme = NULL;
1240 free(fi->gfi); fi->gfi = NULL;
1243 if (fi->cwi != NULL)
1244 { free(fi->cwi); fi->cwi = NULL; }
1246 if (fi->cmi != NULL)
1249 CharMetricInfo *temp = fi->cmi;
1250 Ligature *node = temp->ligs;
1252 for (i = 0; i < fi->numOfChars; ++i)
1254 for (node = temp->ligs; node != NULL; node = node->next)
1256 free(node->succ); node->succ = NULL;
1257 free(node->lig); node->lig = NULL;
1260 free(temp->name); temp->name = NULL;
1264 free(fi->cmi); fi->cmi = NULL;
1267 if (fi->tkd != NULL)
1268 { free(fi->tkd); fi->tkd = NULL; }
1270 if (fi->pkd != NULL)
1272 free(fi->pkd->name1); fi->pkd->name1 = NULL;
1273 free(fi->pkd->name2); fi->pkd->name2 = NULL;
1274 free(fi->pkd); fi->pkd = NULL;
1277 if (fi->ccd != NULL)
1280 CompCharData *ccd = fi->ccd;
1282 for (i = 0; i < fi->numOfComps; ++i)
1284 for (j = 0; j < ccd[i].numOfPieces; ++j)
1286 free(ccd[i].pieces[j].pccName);
1287 ccd[i].pieces[j].pccName = NULL;
1290 free(ccd[i].ccName); ccd[i].ccName = NULL;
1293 free(fi->ccd); fi->ccd = NULL;
1300 } /* afm_free_fontinfo */
1302 #endif /* WITH_AFM_FILES */