* lily/vaticana-ligature-engraver.cc: bugfix: fixed programming
[lilypond.git] / flower / parse-afm.cc
blob2634ab1e20c5393cec7417550c52deacb38613b5
1 /* Our mods:
3 1. FontInfo has become AFM_AFM_Font_info to avoid namespace collisions.
4 2. Version is a linetoken because Bitstream Charter has a space in the version.
5 3. Added some necessary #include headers.
6 4. Added AFM_ prefixes to error codes.
7 5. Made it recognize both '\n' and '\r' as line terminators. Sheesh!
8 6. Stopped buffer overflows in token and linetoken.
10 Raph Levien <raph@acm.org> writing on 4 Oct 1998, updating 21 Oct 1998
13 1. parseFileFree function.
14 2. Leak fix in parseFile.
16 Morten Welinder <terra@diku.dk> September 1999.
21 * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
23 * This file may be freely copied and redistributed as long as:
24 * 1) This entire notice continues to be included in the file,
25 * 2) If the file has been modified in any way, a notice of such
26 * modification is conspicuously indicated.
28 * PostScript, Display PostScript, and Adobe are registered trademarks of
29 * Adobe Systems Incorporated.
31 * ************************************************************************
32 * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
33 * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
34 * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
35 * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
36 * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
37 * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
38 * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
39 * ************************************************************************
42 /* parseAFM.c
44 * This file is used in conjuction with the parseAFM.h header file.
45 * This file contains several procedures that are used to parse AFM
46 * files. It is intended to work with an application program that needs
47 * font metric information. The program can be used as is by making a
48 * procedure call to "parseFile" (passing in the expected parameters)
49 * and having it fill in a data structure with the data from the
50 * AFM file, or an application developer may wish to customize this
51 * code.
53 * There is also a file, parseAFMclient.c, that is a sample application
54 * showing how to call the "parseFile" procedure and how to use the data
55 * after "parseFile" has returned.
57 * Please read the comments in parseAFM.h and parseAFMclient.c.
59 * History:
60 * original: DSM Thu Oct 20 17:39:59 PDT 1988
61 * modified: DSM Mon Jul 3 14:17:50 PDT 1989
62 * - added 'storageProblem' return code
63 * - fixed bug of not allocating extra byte for string duplication
64 * - fixed typos
65 * modified: DSM Tue Apr 3 11:18:34 PDT 1990
66 * - added free (ident) at end of parseFile routine
67 * modified: DSM Tue Jun 19 10:16:29 PDT 1990
68 * - changed (width == 250) to (width = 250) in initializeArray
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <errno.h>
74 #include <sys/file.h>
75 #include <math.h>
76 #include <string.h>
77 #include "parse-afm.hh"
78 #include "warn.hh"
80 #define lineterm EOL /* line terminating character */
81 #define lineterm_alt '\r' /* alternative line terminating character */
82 #define normalEOF 1 /* return code from parsing routines used only */
83 /* in this module */
84 #define Space "space" /* used in string comparison to look for the width */
85 /* of the space character to init the widths array */
86 #define False "false" /* used in string comparison to check the value of */
87 /* boolean keys (e.g. IsFixedPitch) */
89 #define MATCH(A,B) (strncmp ((A), (B), MAX_NAME) == 0)
93 /*************************** GLOBALS ***********************/
95 static char *ident = NULL; /* storage buffer for keywords */
98 /* "shorts" for fast case statement
99 * The values of each of these enumerated items correspond to an entry in the
100 * table of strings defined below. Therefore, if you add a new string as
101 * new keyword into the keyStrings table, you must also add a corresponding
102 * parseKey AND it MUST be in the same position!
104 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
105 * keywords must be placed in lexicographical order, below. [Therefore, the
106 * enumerated items are not necessarily in lexicographical order, depending
107 * on the name chosen. BUT, they must be placed in the same position as the
108 * corresponding key string.] The NOPE shall remain in the last position,
109 * since it does not correspond to any key string, and it is used in the
110 * "recognize" procedure to calculate how many possible keys there are.
113 enum parseKey {
114 ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT,
115 DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES,
116 ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
117 FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH,
118 ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME,
119 NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES,
120 STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
121 STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION,
122 UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
123 NOPE };
125 /* keywords for the system:
126 * This a table of all of the current strings that are vaild AFM keys.
127 * Each entry can be referenced by the appropriate parseKey value (an
128 * enumerated data type defined above). If you add a new keyword here,
129 * a corresponding parseKey MUST be added to the enumerated data type
130 * defined above, AND it MUST be added in the same position as the
131 * string is in this table.
133 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
134 * must be placed in lexicographical order. And, NULL should remain at the
135 * end.
138 static char *keyStrings[] = {
139 "Ascender", "B", "C", "CC", "CapHeight", "Comment",
140 "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites",
141 "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern",
142 "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch",
143 "ItalicAngle", "KP", "KPX", "L", "N",
144 "Notice", "PCC", "StartCharMetrics", "StartComposites",
145 "StartFontMetrics", "StartKernData", "StartKernPairs",
146 "StartTrackKern", "TrackKern", "UnderlinePosition",
147 "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
148 NULL };
150 /*************************** PARSING ROUTINES **************/
152 /*************************** token *************************/
154 /* A "AFM File Conventions" tokenizer. That means that it will
155 * return the next token delimited by white space. See also
156 * the `linetoken' routine, which does a similar thing but
157 * reads all tokens until the next end-of-line.
160 static char *token (FILE *stream)
162 int ch, idx;
164 /* skip over white space */
165 while ((ch = fgetc (stream)) == ' ' || ch == lineterm ||
166 ch == lineterm_alt ||
167 ch == ',' || ch == '\t' || ch == ';');
169 idx = 0;
170 while (idx < MAX_NAME - 1 &&
171 ch != EOF && ch != ' ' && ch != lineterm && ch != lineterm_alt
172 && ch != '\t' && ch != ':' && ch != ';')
174 ident[idx++] = ch;
175 ch = fgetc (stream);
176 } /* while */
178 if (ch == EOF && idx < 1) return ((char *)NULL);
179 if (idx >= 1 && ch != ':' ) ungetc (ch, stream);
180 if (idx < 1 ) ident[idx++] = ch; /* single-character token */
181 ident[idx] = 0;
183 return (ident); /* returns pointer to the token */
185 } /* token */
188 /*************************** linetoken *************************/
190 /* "linetoken" will get read all tokens until the EOL character from
191 * the given stream. This is used to get any arguments that can be
192 * more than one word (like Comment lines and FullName).
195 static char *linetoken (FILE *stream)
197 int ch, idx;
199 while ((ch = fgetc (stream)) == ' ' || ch == '\t' );
201 idx = 0;
202 while (idx < MAX_NAME - 1 &&
203 ch != EOF && ch != lineterm && ch != lineterm_alt)
205 ident[idx++] = ch;
206 ch = fgetc (stream);
207 } /* while */
209 ungetc (ch, stream);
210 ident[idx] = 0;
212 return (ident); /* returns pointer to the token */
214 } /* linetoken */
217 /*************************** recognize *************************/
219 /* This function tries to match a string to a known list of
220 * valid AFM entries (check the keyStrings array above).
221 * "ident" contains everything from white space through the
222 * next space, tab, or ":" character.
224 * The algorithm is a standard Knuth binary search.
227 static enum parseKey recognize ( register char *ident)
229 int lower = 0,
230 upper = (int) NOPE,
231 midpoint = 0,
232 cmpvalue = 0;
233 BOOL found = FALSE;
235 while ((upper >= lower) && !found)
237 midpoint = (lower + upper)/2;
238 if (keyStrings[midpoint] == NULL) break;
239 cmpvalue = strncmp (ident, keyStrings[midpoint], MAX_NAME);
240 if (cmpvalue == 0) found = TRUE;
241 else if (cmpvalue < 0) upper = midpoint - 1;
242 else lower = midpoint + 1;
243 } /* while */
245 if (found) return (enum parseKey) midpoint;
246 else return NOPE;
248 } /* recognize */
251 /************************* parseGlobals *****************************/
253 /* This function is called by "parseFile". It will parse the AFM File
254 * up to the "StartCharMetrics" keyword, which essentially marks the
255 * end of the Global Font Information and the beginning of the character
256 * metrics information.
258 * If the caller of "parseFile" specified that it wanted the Global
259 * Font Information (as defined by the "AFM File Specification"
260 * document), then that information will be stored in the returned
261 * data structure.
263 * Any Global Font Information entries that are not found in a
264 * given file, will have the usual default initialization value
265 * for its type (i.e. entries of type int will be 0, etc).
267 * This function returns an error code specifying whether there was
268 * a premature EOF or a parsing error. This return value is used by
269 * parseFile to determine if there is more file to parse.
272 static BOOL parseGlobals (FILE *fp, register AFM_GlobalFontInfo *gfi)
274 BOOL cont = TRUE, save = (gfi != NULL);
275 int error = AFM_ok;
276 register char *keyword;
278 while (cont)
280 keyword = token (fp);
282 if (keyword == NULL)
283 /* Have reached an early and unexpected EOF. */
284 /* Set flag and stop parsing */
286 error = AFM_earlyEOF;
287 break; /* get out of loop */
289 if (!save)
290 /* get tokens until the end of the Global Font info section */
291 /* without saving any of the data */
292 switch (recognize (keyword))
294 case STARTCHARMETRICS:
295 cont = FALSE;
296 break;
297 case ENDFONTMETRICS:
298 cont = FALSE;
299 error = normalEOF;
300 break;
301 default:
302 break;
303 } /* switch */
304 else
305 /* otherwise parse entire global font info section, */
306 /* saving the data */
307 switch (recognize (keyword))
309 case STARTFONTMETRICS:
310 keyword = token (fp);
311 gfi->afmVersion = (char *) malloc (strlen (keyword) + 1);
312 strcpy (gfi->afmVersion, keyword);
313 break;
314 case COMMENT:
315 keyword = linetoken (fp);
316 break;
317 case FONTNAME:
318 keyword = token (fp);
319 gfi->fontName = (char *) malloc (strlen (keyword) + 1);
320 strcpy (gfi->fontName, keyword);
321 break;
322 case ENCODINGSCHEME:
323 keyword = token (fp);
324 gfi->encodingScheme = (char *)
325 malloc (strlen (keyword) + 1);
326 strcpy (gfi->encodingScheme, keyword);
327 break;
328 case FULLNAME:
329 keyword = linetoken (fp);
330 gfi->fullName = (char *) malloc (strlen (keyword) + 1);
331 strcpy (gfi->fullName, keyword);
332 break;
333 case FAMILYNAME:
334 keyword = linetoken (fp);
335 gfi->familyName = (char *) malloc (strlen (keyword) + 1);
336 strcpy (gfi->familyName, keyword);
337 break;
338 case WEIGHT:
339 keyword = token (fp);
340 gfi->weight = (char *) malloc (strlen (keyword) + 1);
341 strcpy (gfi->weight, keyword);
342 break;
343 case ITALICANGLE:
344 keyword = token (fp);
345 gfi->italicAngle = atof (keyword);
346 if (errno == ERANGE) error = AFM_parseError;
347 break;
348 case ISFIXEDPITCH:
349 keyword = token (fp);
350 if (MATCH (keyword, False))
351 gfi->isFixedPitch = 0;
352 else
353 gfi->isFixedPitch = 1;
354 break;
355 case UNDERLINEPOSITION:
356 keyword = token (fp);
357 gfi->underlinePosition = atoi (keyword);
358 break;
359 case UNDERLINETHICKNESS:
360 keyword = token (fp);
361 gfi->underlineThickness = atoi (keyword);
362 break;
363 case VERSION:
364 keyword = linetoken (fp);
365 gfi->version = (char *) malloc (strlen (keyword) + 1);
366 strcpy (gfi->version, keyword);
367 break;
368 case NOTICE:
369 keyword = linetoken (fp);
370 gfi->notice = (char *) malloc (strlen (keyword) + 1);
371 strcpy (gfi->notice, keyword);
372 break;
373 case FONTBBOX:
374 keyword = token (fp);
375 gfi->fontBBox.llx = atoi (keyword);
376 keyword = token (fp);
377 gfi->fontBBox.lly = atoi (keyword);
378 keyword = token (fp);
379 gfi->fontBBox.urx = atoi (keyword);
380 keyword = token (fp);
381 gfi->fontBBox.ury = atoi (keyword);
382 break;
383 case CAPHEIGHT:
384 keyword = token (fp);
385 gfi->capHeight = atoi (keyword);
386 break;
387 case XHEIGHT:
388 keyword = token (fp);
389 gfi->xHeight = atoi (keyword);
390 break;
391 case DESCENDER:
392 keyword = token (fp);
393 gfi->descender = atoi (keyword);
394 break;
395 case ASCENDER:
396 keyword = token (fp);
397 gfi->ascender = atoi (keyword);
398 break;
399 case STARTCHARMETRICS:
400 cont = FALSE;
401 break;
402 case ENDFONTMETRICS:
403 cont = FALSE;
404 error = normalEOF;
405 break;
406 case NOPE:
407 default:
408 error = AFM_parseError;
409 break;
410 } /* switch */
411 } /* while */
413 return (error);
415 } /* parseGlobals */
419 /************************* initializeArray ************************/
421 /* Unmapped character codes are (at Adobe Systems) assigned the
422 * width of the space character (if one exists) else they get the
423 * value of 250 ems. This function initializes all entries in the
424 * char widths array to have this value. Then any mapped character
425 * codes will be replaced with the width of the appropriate character
426 * when parsing the character metric section.
428 * This function parses the Character Metrics Section looking
429 * for a space character (by comparing character names). If found,
430 * the width of the space character will be used to initialize the
431 * values in the array of character widths.
433 * Before returning, the position of the read/write pointer of the
434 * file is reset to be where it was upon entering this function.
437 static int initializeArray (FILE *fp, register int *cwi)
439 BOOL cont = TRUE, found = FALSE;
440 long opos = ftell (fp);
441 int code = 0, width = 0, i = 0, error = 0;
442 register char *keyword;
444 while (cont)
446 keyword = token (fp);
447 if (keyword == NULL)
449 error = AFM_earlyEOF;
450 break; /* get out of loop */
452 switch (recognize (keyword))
454 case COMMENT:
455 keyword = linetoken (fp);
456 break;
457 case CODE:
458 code = atoi (token (fp));
459 break;
460 case XWIDTH:
461 width = atoi (token (fp));
462 break;
463 case CHARNAME:
464 keyword = token (fp);
465 if (MATCH (keyword, Space))
467 cont = FALSE;
468 found = TRUE;
470 break;
471 case ENDCHARMETRICS:
472 cont = FALSE;
473 break;
474 case ENDFONTMETRICS:
475 cont = FALSE;
476 error = normalEOF;
477 break;
478 case NOPE:
479 default:
480 error = AFM_parseError;
481 break;
482 } /* switch */
483 } /* while */
485 if (!found)
486 width = 250;
488 for (i = 0; i < 256; ++i)
489 cwi[i] = width;
491 fseek (fp, opos, 0);
493 return (error);
495 } /* initializeArray */
498 /************************* parseCharWidths **************************/
500 /* This function is called by "parseFile". It will parse the AFM File
501 * up to the "EndCharMetrics" keyword. It will save the character
502 * width info (as opposed to all of the character metric information)
503 * if requested by the caller of parseFile. Otherwise, it will just
504 * parse through the section without saving any information.
506 * If data is to be saved, parseCharWidths is passed in a pointer
507 * to an array of widths that has already been initialized by the
508 * standard value for unmapped character codes. This function parses
509 * the Character Metrics section only storing the width information
510 * for the encoded characters into the array using the character code
511 * as the index into that array.
513 * This function returns an error code specifying whether there was
514 * a premature EOF or a parsing error. This return value is used by
515 * parseFile to determine if there is more file to parse.
518 static int parseCharWidths (FILE *fp, register int *cwi)
520 BOOL cont = TRUE, save = (cwi != NULL);
521 int pos = 0, error = AFM_ok;
522 register char *keyword;
524 while (cont)
526 keyword = token (fp);
527 /* Have reached an early and unexpected EOF. */
528 /* Set flag and stop parsing */
529 if (keyword == NULL)
531 error = AFM_earlyEOF;
532 break; /* get out of loop */
534 if (!save)
535 /* get tokens until the end of the Char Metrics section without */
536 /* saving any of the data*/
537 switch (recognize (keyword))
539 case ENDCHARMETRICS:
540 cont = FALSE;
541 break;
542 case ENDFONTMETRICS:
543 cont = FALSE;
544 error = normalEOF;
545 break;
546 default:
547 break;
548 } /* switch */
549 else
550 /* otherwise parse entire char metrics section, saving */
551 /* only the char x-width info */
552 switch (recognize (keyword))
554 case COMMENT:
555 keyword = linetoken (fp);
556 break;
557 case CODE:
558 keyword = token (fp);
559 pos = atoi (keyword);
560 break;
561 case XYWIDTH:
562 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
563 keyword = token (fp); keyword = token (fp); /* eat values */
564 error = AFM_parseError;
565 break;
566 case XWIDTH:
567 keyword = token (fp);
568 if (pos >= 0) /* ignore unmapped chars */
569 cwi[pos] = atoi (keyword);
570 break;
571 case ENDCHARMETRICS:
572 cont = FALSE;
573 break;
574 case ENDFONTMETRICS:
575 cont = FALSE;
576 error = normalEOF;
577 break;
578 case CHARNAME: /* eat values (so doesn't cause AFM_parseError) */
579 keyword = token (fp);
580 break;
581 case CHARBBOX:
582 keyword = token (fp); keyword = token (fp);
583 keyword = token (fp); keyword = token (fp);
584 break;
585 case LIGATURE:
586 keyword = token (fp); keyword = token (fp);
587 break;
588 case NOPE:
589 default:
590 error = AFM_parseError;
591 break;
592 } /* switch */
593 } /* while */
595 return (error);
597 } /* parseCharWidths */
600 /************************* parseCharMetrics ************************/
602 /* This function is called by parseFile if the caller of parseFile
603 * requested that all character metric information be saved
604 * (as opposed to only the character width information).
606 * parseCharMetrics is passed in a pointer to an array of records
607 * to hold information on a per character basis. This function
608 * parses the Character Metrics section storing all character
609 * metric information for the ALL characters (mapped and unmapped)
610 * into the array.
612 * This function returns an error code specifying whether there was
613 * a premature EOF or a parsing error. This return value is used by
614 * parseFile to determine if there is more file to parse.
617 static int parseCharMetrics (FILE *fp, register AFM_Font_info *fi)
619 BOOL cont = TRUE, firstTime = TRUE;
620 int error = AFM_ok, count = 0;
621 register AFM_CharMetricInfo *temp = fi->cmi;
622 register char *keyword;
624 while (cont)
626 keyword = token (fp);
627 if (keyword == NULL)
629 error = AFM_earlyEOF;
630 break; /* get out of loop */
632 switch (recognize (keyword))
634 case COMMENT:
635 keyword = linetoken (fp);
636 break;
637 case CODE:
638 if (count < fi->numOfChars)
640 if (firstTime)
641 firstTime = FALSE;
642 else
643 temp++;
644 temp->code = atoi (token (fp));
645 count++;
647 else
649 warning ("Too many metrics.");
650 error = AFM_parseError;
651 cont = FALSE;
653 break;
654 case XYWIDTH:
655 temp->wx = atoi (token (fp));
656 temp->wy = atoi (token (fp));
657 break;
658 case XWIDTH:
659 temp->wx = atoi (token (fp));
660 break;
662 case CHARNAME:
663 keyword = token (fp);
664 temp->name = (char *) malloc (strlen (keyword) + 1);
665 strcpy (temp->name, keyword);
666 break;
668 case CHARBBOX:
669 temp->charBBox.llx = atoi (token (fp));
670 temp->charBBox.lly = atoi (token (fp));
671 temp->charBBox.urx = atoi (token (fp));
672 temp->charBBox.ury = atoi (token (fp));
673 break;
675 case LIGATURE: {
676 AFM_Ligature **tail = & (temp->ligs);
677 AFM_Ligature *node = *tail;
679 if (*tail != NULL)
681 while (node->next != NULL)
682 node = node->next;
683 tail = & (node->next);
686 *tail = (AFM_Ligature *) calloc (1, sizeof (AFM_Ligature));
687 keyword = token (fp);
688 (*tail)->succ = (char *) malloc (strlen (keyword) + 1);
689 strcpy ((*tail)->succ, keyword);
690 keyword = token (fp);
691 (*tail)->lig = (char *) malloc (strlen (keyword) + 1);
692 strcpy ((*tail)->lig, keyword);
693 break; }
694 case ENDCHARMETRICS:
695 cont = FALSE;;
696 break;
697 case ENDFONTMETRICS:
698 cont = FALSE;
699 error = normalEOF;
700 break;
701 case NOPE:
702 default:
703 warning ("Unknown token");
705 error = AFM_parseError;
706 break;
707 } /* switch */
708 } /* while */
710 if ((error == AFM_ok) && (count != fi->numOfChars))
712 warning ("Incorrect char count");
713 error = AFM_parseError;
715 return (error);
717 } /* parseCharMetrics */
721 /************************* parseAFM_TrackKernData ***********************/
723 /* This function is called by "parseFile". It will parse the AFM File
724 * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
725 * track kerning data if requested by the caller of parseFile.
727 * parseAFM_TrackKernData is passed in a pointer to the FontInfo record.
728 * If data is to be saved, the FontInfo record will already contain
729 * a valid pointer to storage for the track kerning data.
731 * This function returns an error code specifying whether there was
732 * a premature EOF or a parsing error. This return value is used by
733 * parseFile to determine if there is more file to parse.
736 static int parseAFM_TrackKernData (FILE *fp, register AFM_Font_info *fi)
738 BOOL cont = TRUE, save = (fi->tkd != NULL);
739 int pos = 0, error = AFM_ok, tcount = 0;
740 register char *keyword;
742 while (cont)
744 keyword = token (fp);
746 if (keyword == NULL)
748 error = AFM_earlyEOF;
749 break; /* get out of loop */
751 if (!save)
752 /* get tokens until the end of the Track Kerning Data */
753 /* section without saving any of the data */
754 switch (recognize (keyword))
756 case ENDTRACKKERN:
757 case ENDKERNDATA:
758 cont = FALSE;
759 break;
760 case ENDFONTMETRICS:
761 cont = FALSE;
762 error = normalEOF;
763 break;
764 default:
765 break;
766 } /* switch */
767 else
768 /* otherwise parse entire Track Kerning Data section, */
769 /* saving the data */
770 switch (recognize (keyword))
772 case COMMENT:
773 keyword = linetoken (fp);
774 break;
775 case TRACKKERN:
776 if (tcount < fi->numOfTracks)
778 keyword = token (fp);
779 fi->tkd[pos].degree = atoi (keyword);
780 keyword = token (fp);
781 fi->tkd[pos].minPtSize = atof (keyword);
782 if (errno == ERANGE) error = AFM_parseError;
783 keyword = token (fp);
784 fi->tkd[pos].minKernAmt = atof (keyword);
785 if (errno == ERANGE) error = AFM_parseError;
786 keyword = token (fp);
787 fi->tkd[pos].maxPtSize = atof (keyword);
788 if (errno == ERANGE) error = AFM_parseError;
789 keyword = token (fp);
790 fi->tkd[pos++].maxKernAmt = atof (keyword);
791 if (errno == ERANGE) error = AFM_parseError;
792 tcount++;
794 else
796 error = AFM_parseError;
797 cont = FALSE;
799 break;
800 case ENDTRACKKERN:
801 case ENDKERNDATA:
802 cont = FALSE;
803 break;
804 case ENDFONTMETRICS:
805 cont = FALSE;
806 error = normalEOF;
807 break;
808 case NOPE:
809 default:
810 error = AFM_parseError;
811 break;
812 } /* switch */
813 } /* while */
815 if (error == AFM_ok && tcount != fi->numOfTracks)
816 error = AFM_parseError;
818 return (error);
820 } /* parseAFM_TrackKernData */
823 /************************* parseAFM_PairKernData ************************/
825 /* This function is called by "parseFile". It will parse the AFM File
826 * up to the "EndKernPairs" or "EndKernData" keywords. It will save
827 * the pair kerning data if requested by the caller of parseFile.
829 * parseAFM_PairKernData is passed in a pointer to the FontInfo record.
830 * If data is to be saved, the FontInfo record will already contain
831 * a valid pointer to storage for the pair kerning data.
833 * This function returns an error code specifying whether there was
834 * a premature EOF or a parsing error. This return value is used by
835 * parseFile to determine if there is more file to parse.
838 static int parseAFM_PairKernData (FILE *fp, register AFM_Font_info *fi)
840 BOOL cont = TRUE, save = (fi->pkd != NULL);
841 int pos = 0, error = AFM_ok, pcount = 0;
842 register char *keyword;
844 while (cont)
846 keyword = token (fp);
848 if (keyword == NULL)
850 error = AFM_earlyEOF;
851 break; /* get out of loop */
853 if (!save)
854 /* get tokens until the end of the Pair Kerning Data */
855 /* section without saving any of the data */
856 switch (recognize (keyword))
858 case ENDKERNPAIRS:
859 case ENDKERNDATA:
860 cont = FALSE;
861 break;
862 case ENDFONTMETRICS:
863 cont = FALSE;
864 error = normalEOF;
865 break;
866 default:
867 break;
868 } /* switch */
869 else
870 /* otherwise parse entire Pair Kerning Data section, */
871 /* saving the data */
872 switch (recognize (keyword))
874 case COMMENT:
875 keyword = linetoken (fp);
876 break;
877 case KERNPAIR:
878 if (pcount < fi->numOfPairs)
880 keyword = token (fp);
881 fi->pkd[pos].name1 = (char *)
882 malloc (strlen (keyword) + 1);
883 strcpy (fi->pkd[pos].name1, keyword);
884 keyword = token (fp);
885 fi->pkd[pos].name2 = (char *)
886 malloc (strlen (keyword) + 1);
887 strcpy (fi->pkd[pos].name2, keyword);
888 keyword = token (fp);
889 fi->pkd[pos].xamt = atoi (keyword);
890 keyword = token (fp);
891 fi->pkd[pos++].yamt = atoi (keyword);
892 pcount++;
894 else
896 error = AFM_parseError;
897 cont = FALSE;
899 break;
900 case KERNPAIRXAMT:
901 if (pcount < fi->numOfPairs)
903 keyword = token (fp);
904 fi->pkd[pos].name1 = (char *)
905 malloc (strlen (keyword) + 1);
906 strcpy (fi->pkd[pos].name1, keyword);
907 keyword = token (fp);
908 fi->pkd[pos].name2 = (char *)
909 malloc (strlen (keyword) + 1);
910 strcpy (fi->pkd[pos].name2, keyword);
911 keyword = token (fp);
912 fi->pkd[pos++].xamt = atoi (keyword);
913 pcount++;
915 else
917 error = AFM_parseError;
918 cont = FALSE;
920 break;
921 case ENDKERNPAIRS:
922 case ENDKERNDATA:
923 cont = FALSE;
924 break;
925 case ENDFONTMETRICS:
926 cont = FALSE;
927 error = normalEOF;
928 break;
929 case NOPE:
930 default:
931 error = AFM_parseError;
932 break;
933 } /* switch */
934 } /* while */
936 if (error == AFM_ok && pcount != fi->numOfPairs)
937 error = AFM_parseError;
939 return (error);
941 } /* parseAFM_PairKernData */
944 /************************* parseAFM_CompCharData **************************/
946 /* This function is called by "parseFile". It will parse the AFM File
947 * up to the "EndComposites" keyword. It will save the composite
948 * character data if requested by the caller of parseFile.
950 * parseAFM_CompCharData is passed in a pointer to the FontInfo record, and
951 * a boolean representing if the data should be saved.
953 * This function will create the appropriate amount of storage for
954 * the composite character data and store a pointer to the storage
955 * in the FontInfo record.
957 * This function returns an error code specifying whether there was
958 * a premature EOF or a parsing error. This return value is used by
959 * parseFile to determine if there is more file to parse.
962 static int parseAFM_CompCharData (FILE *fp, register AFM_Font_info *fi)
964 BOOL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
965 int pos = 0, j = 0, error = AFM_ok, ccount = 0, pcount = 0;
966 register char *keyword;
968 while (cont)
970 keyword = token (fp);
971 if (keyword == NULL)
972 /* Have reached an early and unexpected EOF. */
973 /* Set flag and stop parsing */
975 error = AFM_earlyEOF;
976 break; /* get out of loop */
978 if (ccount > fi->numOfComps)
980 error = AFM_parseError;
981 break; /* get out of loop */
983 if (!save)
984 /* get tokens until the end of the Composite Character info */
985 /* section without saving any of the data */
986 switch (recognize (keyword))
988 case ENDCOMPOSITES:
989 cont = FALSE;
990 break;
991 case ENDFONTMETRICS:
992 cont = FALSE;
993 error = normalEOF;
994 break;
995 default:
996 break;
997 } /* switch */
998 else
999 /* otherwise parse entire Composite Character info section, */
1000 /* saving the data */
1001 switch (recognize (keyword))
1003 case COMMENT:
1004 keyword = linetoken (fp);
1005 break;
1006 case COMPCHAR:
1007 if (ccount < fi->numOfComps)
1009 keyword = token (fp);
1010 if (pcount != fi->ccd[pos].numOfPieces)
1011 error = AFM_parseError;
1012 pcount = 0;
1013 if (firstTime) firstTime = FALSE;
1014 else pos++;
1015 fi->ccd[pos].ccName = (char *)
1016 malloc (strlen (keyword) + 1);
1017 strcpy (fi->ccd[pos].ccName, keyword);
1018 keyword = token (fp);
1019 fi->ccd[pos].numOfPieces = atoi (keyword);
1020 fi->ccd[pos].pieces = (AFM_Pcc *)
1021 calloc (fi->ccd[pos].numOfPieces, sizeof (AFM_Pcc));
1022 j = 0;
1023 ccount++;
1025 else
1027 error = AFM_parseError;
1028 cont = FALSE;
1030 break;
1031 case COMPCHARPIECE:
1032 if (pcount < fi->ccd[pos].numOfPieces)
1034 keyword = token (fp);
1035 fi->ccd[pos].pieces[j].AFM_PccName = (char *)
1036 malloc (strlen (keyword) + 1);
1037 strcpy (fi->ccd[pos].pieces[j].AFM_PccName, keyword);
1038 keyword = token (fp);
1039 fi->ccd[pos].pieces[j].deltax = atoi (keyword);
1040 keyword = token (fp);
1041 fi->ccd[pos].pieces[j++].deltay = atoi (keyword);
1042 pcount++;
1044 else
1045 error = AFM_parseError;
1046 break;
1047 case ENDCOMPOSITES:
1048 cont = FALSE;
1049 break;
1050 case ENDFONTMETRICS:
1051 cont = FALSE;
1052 error = normalEOF;
1053 break;
1054 case NOPE:
1055 default:
1056 error = AFM_parseError;
1057 break;
1058 } /* switch */
1059 } /* while */
1061 if (error == AFM_ok && ccount != fi->numOfComps)
1062 error = AFM_parseError;
1064 return (error);
1066 } /* parseAFM_CompCharData */
1071 /*************************** 'PUBLIC' FUNCTION ********************/
1073 void
1074 AFM_free (AFM_Font_info *fi)
1076 if (fi->gfi) {
1077 free (fi->gfi->afmVersion);
1078 free (fi->gfi->fontName);
1079 free (fi->gfi->fullName);
1080 free (fi->gfi->familyName);
1081 free (fi->gfi->weight);
1082 free (fi->gfi->version);
1083 free (fi->gfi->notice);
1084 free (fi->gfi->encodingScheme);
1085 free (fi->gfi);
1088 /* This contains just scalars. */
1089 free (fi->cwi);
1091 if (fi->cmi) {
1092 int i;
1093 for (i = 0; i < fi->numOfChars; i++) {
1094 free (fi->cmi[i].name);
1095 while (fi->cmi[i].ligs) {
1096 AFM_Ligature *tmp;
1097 tmp = fi->cmi[i].ligs;
1098 free (tmp->succ);
1099 free (tmp->lig);
1100 free (tmp);
1101 fi->cmi[i].ligs = fi->cmi[i].ligs->next;
1104 free (fi->cmi);
1107 /* This contains just scalars. */
1108 free (fi->tkd);
1110 if (fi->pkd) {
1111 int i;
1112 for (i = 0; i < fi->numOfPairs; i++) {
1113 free (fi->pkd[i].name1);
1114 free (fi->pkd[i].name2);
1116 free (fi->pkd);
1119 if (fi->ccd) {
1120 int i, j;
1121 for (i = 0; i < fi->numOfComps; i++) {
1122 free (fi->ccd[i].ccName);
1123 for (j = 0; j < fi->ccd[i].numOfPieces; j++) {
1124 free (fi->ccd[i].pieces[j].AFM_PccName);
1126 free (fi->ccd[i].pieces);
1128 free (fi->ccd);
1131 free (fi);
1135 /*************************** parseFile *****************************/
1137 /* parseFile is the only 'public' procedure available. It is called
1138 * from an application wishing to get information from an AFM file.
1139 * The caller of this function is responsible for locating and opening
1140 * an AFM file and handling all errors associated with that task.
1142 * parseFile expects 3 parameters: a vaild file pointer, a pointer
1143 * to a (FontInfo *) variable (for which storage will be allocated and
1144 * the data requested filled in), and a mask specifying which
1145 * data from the AFM File should be saved in the FontInfo structure.
1147 * The file will be parsed and the requested data will be stored in
1148 * a record of type FontInfo (refer to ParseAFM.h).
1150 * parseFile returns an error code as defined in parseAFM.h.
1152 * The position of the read/write pointer associated with the file
1153 * pointer upon return of this function is undefined.
1156 extern int AFM_parseFile (FILE *fp, AFM_Font_info **fi, int flags)
1159 int code = AFM_ok; /* return code from each of the parsing routines */
1160 int error = AFM_ok; /* used as the return code from this function */
1162 register char *keyword; /* used to store a token */
1165 /* storage data for the global variable ident */
1166 if (!ident)
1167 ident = (char *) calloc (MAX_NAME, sizeof (char));
1168 if (ident == NULL) {error = AFM_storageProblem; return (error);}
1170 (*fi) = (AFM_Font_info *) calloc (1, sizeof (AFM_Font_info));
1171 if ((*fi) == NULL) {error = AFM_storageProblem; return (error);}
1173 if (flags & P_G)
1175 (*fi)->gfi = (AFM_GlobalFontInfo *) calloc (1, sizeof (AFM_GlobalFontInfo));
1176 if ((*fi)->gfi == NULL) {error = AFM_storageProblem; return (error);}
1179 /* The AFM File begins with Global Font Information. This section */
1180 /* will be parsed whether or not information should be saved. */
1181 code = parseGlobals (fp, (*fi)->gfi);
1183 if (code < 0)
1184 error = code;
1186 /* The Global Font Information is followed by the Character Metrics */
1187 /* section. Which procedure is used to parse this section depends on */
1188 /* how much information should be saved. If all of the metrics info */
1189 /* is wanted, parseCharMetrics is called. If only the character widths */
1190 /* is wanted, parseCharWidths is called. parseCharWidths will also */
1191 /* be called in the case that no character data is to be saved, just */
1192 /* to parse through the section. */
1194 if ((code != normalEOF) && (code != AFM_earlyEOF))
1196 (*fi)->numOfChars = atoi (token (fp));
1197 if (flags & (P_M ^ P_W))
1199 (*fi)->cmi = (AFM_CharMetricInfo *)
1200 calloc ((*fi)->numOfChars, sizeof (AFM_CharMetricInfo));
1201 if ((*fi)->cmi == NULL) {
1202 error = AFM_storageProblem;
1203 return (error);
1206 code = parseCharMetrics (fp, *fi);
1208 else
1210 if (flags & P_W)
1212 (*fi)->cwi = (int *) calloc (256, sizeof (int));
1213 if ((*fi)->cwi == NULL)
1215 error = AFM_storageProblem;
1216 return (error);
1219 /* parse section regardless */
1220 code = parseCharWidths (fp, (*fi)->cwi);
1221 } /* else */
1222 } /* if */
1224 if ((error != AFM_earlyEOF) && (code < 0))
1225 error = code;
1227 /* The remaining sections of the AFM are optional. This code will */
1228 /* look at the next keyword in the file to determine what section */
1229 /* is next, and then allocate the appropriate amount of storage */
1230 /* for the data (if the data is to be saved) and call the */
1231 /* appropriate parsing routine to parse the section. */
1233 while ((code != normalEOF) && (code != AFM_earlyEOF))
1235 keyword = token (fp);
1236 if (keyword == NULL)
1237 /* Have reached an early and unexpected EOF. */
1238 /* Set flag and stop parsing */
1240 code = AFM_earlyEOF;
1241 break; /* get out of loop */
1243 switch (recognize (keyword))
1245 case STARTKERNDATA:
1246 break;
1247 case ENDKERNDATA:
1248 break;
1249 case STARTTRACKKERN:
1250 keyword = token (fp);
1251 if (flags & P_T)
1253 (*fi)->numOfTracks = atoi (keyword);
1254 (*fi)->tkd = (AFM_TrackKernData *)
1255 calloc ((*fi)->numOfTracks, sizeof (AFM_TrackKernData));
1256 if ((*fi)->tkd == NULL)
1258 error = AFM_storageProblem;
1259 return (error);
1261 } /* if */
1262 code = parseAFM_TrackKernData (fp, *fi);
1263 break;
1264 case STARTKERNPAIRS:
1265 keyword = token (fp);
1266 if (flags & P_P)
1268 (*fi)->numOfPairs = atoi (keyword);
1269 (*fi)->pkd = (AFM_PairKernData *)
1270 calloc ((*fi)->numOfPairs, sizeof (AFM_PairKernData));
1271 if ((*fi)->pkd == NULL)
1273 error = AFM_storageProblem;
1274 return (error);
1276 } /* if */
1277 code = parseAFM_PairKernData (fp, *fi);
1278 break;
1279 case STARTCOMPOSITES:
1280 keyword = token (fp);
1281 if (flags & P_C)
1283 (*fi)->numOfComps = atoi (keyword);
1284 (*fi)->ccd = (AFM_CompCharData *)
1285 calloc ((*fi)->numOfComps, sizeof (AFM_CompCharData));
1286 if ((*fi)->ccd == NULL)
1288 error = AFM_storageProblem;
1289 return (error);
1291 } /* if */
1292 code = parseAFM_CompCharData (fp, *fi);
1293 break;
1294 case ENDFONTMETRICS:
1295 code = normalEOF;
1296 break;
1297 case NOPE:
1298 default:
1299 code = AFM_parseError;
1300 break;
1301 } /* switch */
1303 if ((error != AFM_earlyEOF) && (code < 0))
1304 error = code;
1306 } /* while */
1308 if ((error != AFM_earlyEOF) && (code < 0))
1309 error = code;
1311 if (ident != NULL) { free (ident); ident = NULL; }
1313 return (error);
1315 } /* parseFile */