Release version 1.6.5.
[enscript.git] / afmlib / afmparse.c
1 /*
2  * Parse AFM files.
3  * Copyright (c) 1995-1998 Markku Rossi.
4  *
5  * Author: Markku Rossi <mtr@iki.fi>
6  */
7
8 /*
9  * Enscript is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Enscript is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Enscript.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "afmint.h"
24 #include "afm.h"
25
26 /*
27  * Definitions.
28  */
29
30 #define ISSPACE(ch) \
31   ((ch) == ' ' || (ch) == '\n' || (ch) == '\r' || (ch) == '\t' || (ch) == ';')
32
33 #define GET_VALUE(typenum) get_type (handle, ctx, (typenum), &node)
34
35 struct parse_ctx_st
36 {
37   FILE *fp;
38   char token[1024];             /* maximum line length is 255, this should be
39                                    enought */
40   unsigned int tokenlen;        /* length of the token */
41 };
42
43 typedef struct parse_ctx_st ParseCtx;
44
45 /*
46  * Static variables.
47  */
48
49 /*
50  * The AFM keys.  This array must be kept sorted because keys are
51  * searched by using binary search.
52  */
53 static struct keyname_st
54 {
55   char *name;
56   AFMKey key;
57 } keynames[] =
58 {
59   {"Ascender",                  kAscender},
60   {"Axes",                      kAxes},
61   {"AxisLabel",                 kAxisLabel},
62   {"AxisType",                  kAxisType},
63   {"B",                         kB},
64   {"BlendAxisTypes",            kBlendAxisTypes},
65   {"BlendDesignMap",            kBlendDesignMap},
66   {"BlendDesignPositions",      kBlendDesignPositions},
67   {"C",                         kC},
68   {"CC",                        kCC},
69   {"CH",                        kCH},
70   {"CapHeight",                 kCapHeight},
71   {"CharWidth",                 kCharWidth},
72   {"CharacterSet",              kCharacterSet},
73   {"Characters",                kCharacters},
74   {"Comment",                   kComment},
75   {"Descendents",               kDescendents},
76   {"Descender",                 kDescender},
77   {"EncodingScheme",            kEncodingScheme},
78   {"EndAxis",                   kEndAxis},
79   {"EndCharMetrics",            kEndCharMetrics},
80   {"EndCompFontMetrics",        kEndCompFontMetrics},
81   {"EndComposites",             kEndComposites},
82   {"EndDescendent",             kEndDescendent},
83   {"EndDirection",              kEndDirection},
84   {"EndFontMetrics",            kEndFontMetrics},
85   {"EndKernData",               kEndKernData},
86   {"EndKernPairs",              kEndKernPairs},
87   {"EndMaster",                 kEndMaster},
88   {"EndMasterFontMetrics",      kEndMasterFontMetrics},
89   {"EndTrackKern",              kEndTrackKern},
90   {"EscChar",                   kEscChar},
91   {"FamilyName",                kFamilyName},
92   {"FontBBox",                  kFontBBox},
93   {"FontName",                  kFontName},
94   {"FullName",                  kFullName},
95   {"IsBaseFont",                kIsBaseFont},
96   {"IsFixedPitch",              kIsFixedPitch},
97   {"IsFixedV",                  kIsFixedV},
98   {"ItalicAngle",               kItalicAngle},
99   {"KP",                        kKP},
100   {"KPH",                       kKPH},
101   {"KPX",                       kKPX},
102   {"KPY",                       kKPY},
103   {"L",                         kL},
104   {"MappingScheme",             kMappingScheme},
105   {"Masters",                   kMasters},
106   {"MetricsSets",               kMetricsSets},
107   {"N",                         kN},
108   {"Notice",                    kNotice},
109   {"PCC",                       kPCC},
110   {"StartAxis",                 kStartAxis},
111   {"StartCharMetrics",          kStartCharMetrics},
112   {"StartCompFontMetrics",      kStartCompFontMetrics},
113   {"StartComposites",           kStartComposites},
114   {"StartDescendent",           kStartDescendent},
115   {"StartDirection",            kStartDirection},
116   {"StartFontMetrics",          kStartFontMetrics},
117   {"StartKernData",             kStartKernData},
118   {"StartKernPairs",            kStartKernPairs},
119   {"StartMaster",               kStartMaster},
120   {"StartMasterFontMetrics",    kStartMasterFontMetrics},
121   {"StartTrackKern",            kStartTrackKern},
122   {"TrackKern",                 kTrackKern},
123   {"UnderlinePosition",         kUnderlinePosition},
124   {"UnderlineThickness",        kUnderlineThickness},
125   {"VV",                        kVV},
126   {"VVector",                   kVVector},
127   {"Version",                   kVersion},
128   {"W",                         kW},
129   {"W0",                        kW0},
130   {"W0X",                       kW0X},
131   {"W0Y",                       kW0Y},
132   {"W1",                        kW1},
133   {"W1X",                       kW1X},
134   {"W1Y",                       kW1Y},
135   {"WX",                        kWX},
136   {"WY",                        kWY},
137   {"Weight",                    kWeight},
138   {"WeightVector",              kWeightVector},
139   {"XHeight",                   kXHeight},
140
141   {NULL, 0},
142 };
143
144 #define NUM_KEYS (sizeof (keynames) / sizeof (struct keyname_st) - 1)
145
146 /*
147  * Prototypes for static functions.
148  */
149
150 /* Throw parse error <error>.  Never returns. */
151 static void parse_error ___P ((AFMHandle handle, AFMError error));
152
153 static int get_token ___P ((AFMHandle handle, ParseCtx *ctx));
154 static int get_line_token ___P ((AFMHandle handle, ParseCtx *ctx));
155 static void get_key ___P ((AFMHandle handle, ParseCtx *ctx,
156                            AFMKey *key_return));
157 static void get_type ___P ((AFMHandle handle, ParseCtx *ctx, int type,
158                             AFMNode *type_return));
159 static void read_character_metrics ___P ((AFMHandle handle, ParseCtx *ctx,
160                                           AFMFont font));
161 static void read_kern_pairs ___P ((AFMHandle handle, ParseCtx *ctx,
162                                    AFMFont font));
163 static void read_track_kerns ___P ((AFMHandle handle, ParseCtx *ctx,
164                                     AFMFont font));
165 static void read_composites ___P ((AFMHandle handle, ParseCtx *ctx,
166                                    AFMFont font));
167
168 /*
169  * Global functions.
170  */
171
172 void
173 afm_parse_file (AFMHandle handle, const char *filename, AFMFont font)
174 {
175   AFMKey key;
176   AFMNode node;
177   ParseCtx context;
178   ParseCtx *ctx = &context;
179   int wd = 0;                   /* Writing direction. */
180   int done = 0;
181
182   ctx->fp = fopen (filename, "r");
183   if (ctx->fp == NULL)
184     parse_error (handle, SYSERROR (AFM_ERROR_FILE_IO));
185
186   /* Check that file is really an AFM file. */
187
188   get_key (handle, ctx, &key);
189   if (key != kStartFontMetrics)
190     parse_error (handle, AFM_ERROR_NOT_AFM_FILE);
191   GET_VALUE (AFM_TYPE_NUMBER);
192   font->version = node.u.number;
193
194   /* Parse it. */
195   while (!done)
196     {
197       get_key (handle, ctx, &key);
198       switch (key)
199         {
200         case kComment:
201           (void) get_line_token (handle, ctx);
202           continue;
203           break;
204
205           /* File structure. */
206
207         case kStartFontMetrics:
208           GET_VALUE (AFM_TYPE_NUMBER);
209           font->version = node.u.number;
210           break;
211
212         case kEndFontMetrics:
213           done = 1;
214           break;
215
216         case kStartCompFontMetrics:
217         case kEndCompFontMetrics:
218         case kStartMasterFontMetrics:
219         case kEndMasterFontMetrics:
220           parse_error (handle, AFM_ERROR_UNSUPPORTED_FORMAT);
221           break;
222
223           /* Global font information. */
224         case kFontName:
225           GET_VALUE (AFM_TYPE_STRING);
226           font->global_info.FontName = node.u.string;
227           break;
228
229         case kFullName:
230           GET_VALUE (AFM_TYPE_STRING);
231           font->global_info.FullName = node.u.string;
232           break;
233
234         case kFamilyName:
235           GET_VALUE (AFM_TYPE_STRING);
236           font->global_info.FamilyName = node.u.string;
237           break;
238
239         case kWeight:
240           GET_VALUE (AFM_TYPE_STRING);
241           font->global_info.Weight = node.u.string;
242           break;
243
244         case kFontBBox:
245           GET_VALUE (AFM_TYPE_NUMBER);
246           font->global_info.FontBBox_llx = node.u.number;
247           GET_VALUE (AFM_TYPE_NUMBER);
248           font->global_info.FontBBox_lly = node.u.number;
249           GET_VALUE (AFM_TYPE_NUMBER);
250           font->global_info.FontBBox_urx = node.u.number;
251           GET_VALUE (AFM_TYPE_NUMBER);
252           font->global_info.FontBBox_ury = node.u.number;
253           break;
254
255         case kVersion:
256           GET_VALUE (AFM_TYPE_STRING);
257           font->global_info.Version = node.u.string;
258           break;
259
260         case kNotice:
261           GET_VALUE (AFM_TYPE_STRING);
262           font->global_info.Notice = node.u.string;
263           break;
264
265         case kEncodingScheme:
266           GET_VALUE (AFM_TYPE_STRING);
267           font->global_info.EncodingScheme = node.u.string;
268           break;
269
270         case kMappingScheme:
271           GET_VALUE (AFM_TYPE_INTEGER);
272           font->global_info.MappingScheme = node.u.integer;
273           break;
274
275         case kEscChar:
276           GET_VALUE (AFM_TYPE_INTEGER);
277           font->global_info.EscChar = node.u.integer;
278           break;
279
280         case kCharacterSet:
281           GET_VALUE (AFM_TYPE_STRING);
282           font->global_info.CharacterSet = node.u.string;
283           break;
284
285         case kCharacters:
286           GET_VALUE (AFM_TYPE_INTEGER);
287           font->global_info.Characters = node.u.integer;
288           break;
289
290         case kIsBaseFont:
291           GET_VALUE (AFM_TYPE_BOOLEAN);
292           font->global_info.IsBaseFont = node.u.boolean;
293           break;
294
295         case kVVector:
296           GET_VALUE (AFM_TYPE_NUMBER);
297           font->global_info.VVector_0 = node.u.number;
298           GET_VALUE (AFM_TYPE_NUMBER);
299           font->global_info.VVector_1 = node.u.number;
300           break;
301
302         case kIsFixedV:
303           GET_VALUE (AFM_TYPE_BOOLEAN);
304           font->global_info.IsFixedV = node.u.boolean;
305           break;
306
307         case kCapHeight:
308           GET_VALUE (AFM_TYPE_NUMBER);
309           font->global_info.CapHeight = node.u.number;
310           break;
311
312         case kXHeight:
313           GET_VALUE (AFM_TYPE_NUMBER);
314           font->global_info.XHeight = node.u.number;
315           break;
316
317         case kAscender:
318           GET_VALUE (AFM_TYPE_NUMBER);
319           font->global_info.Ascender = node.u.number;
320           break;
321
322         case kDescender:
323           GET_VALUE (AFM_TYPE_NUMBER);
324           font->global_info.Descender = node.u.number;
325           break;
326
327           /* Writing directions. */
328         case kStartDirection:
329           GET_VALUE (AFM_TYPE_INTEGER);
330           wd = node.u.integer;
331           font->writing_direction_metrics[wd].is_valid = AFMTrue;
332           break;
333
334         case kUnderlinePosition:
335           GET_VALUE (AFM_TYPE_NUMBER);
336           font->writing_direction_metrics[wd].UnderlinePosition
337             = node.u.number;
338           break;
339
340         case kUnderlineThickness:
341           GET_VALUE (AFM_TYPE_NUMBER);
342           font->writing_direction_metrics[wd].UnderlineThickness
343             = node.u.number;
344           break;
345
346         case kItalicAngle:
347           GET_VALUE (AFM_TYPE_NUMBER);
348           font->writing_direction_metrics[wd].ItalicAngle = node.u.number;
349           break;
350
351         case kCharWidth:
352           GET_VALUE (AFM_TYPE_NUMBER);
353           font->writing_direction_metrics[wd].CharWidth_x = node.u.number;
354           GET_VALUE (AFM_TYPE_NUMBER);
355           font->writing_direction_metrics[wd].CharWidth_y = node.u.number;
356           break;
357
358         case kIsFixedPitch:
359           GET_VALUE (AFM_TYPE_BOOLEAN);
360           font->writing_direction_metrics[wd].IsFixedPitch = node.u.boolean;
361           break;
362
363         case kEndDirection:
364           break;
365
366           /* Individual Character Metrics. */
367         case kStartCharMetrics:
368           GET_VALUE (AFM_TYPE_INTEGER);
369           font->num_character_metrics = node.u.integer;
370           font->character_metrics
371             = ((AFMIndividualCharacterMetrics *)
372                calloc (font->num_character_metrics + 1,
373                        sizeof (AFMIndividualCharacterMetrics)));
374           if (font->character_metrics == NULL)
375             parse_error (handle, AFM_ERROR_MEMORY);
376
377           read_character_metrics (handle, ctx, font);
378           break;
379
380           /* Kerning Data. */
381         case kStartKernData:
382           break;
383
384         case kStartKernPairs:
385           if (font->info_level & AFM_I_KERN_PAIRS)
386             {
387               GET_VALUE (AFM_TYPE_INTEGER);
388               font->num_kern_pairs = node.u.integer;
389               font->kern_pairs =
390                 (AFMPairWiseKerning *) calloc (font->num_kern_pairs + 1,
391                                                sizeof (AFMPairWiseKerning));
392               if (font->kern_pairs == NULL)
393                 parse_error (handle, AFM_ERROR_MEMORY);
394
395               read_kern_pairs (handle, ctx, font);
396             }
397           else
398             {
399               do
400                 {
401                   (void) get_line_token (handle, ctx);
402                   get_key (handle, ctx, &key);
403                 }
404               while (key != kEndKernPairs);
405             }
406           break;
407
408         case kStartTrackKern:
409           if (font->info_level & AFM_I_TRACK_KERNS)
410             {
411               GET_VALUE (AFM_TYPE_INTEGER);
412               font->num_track_kerns = node.u.integer;
413               font->track_kerns
414                 = (AFMTrackKern *) calloc (font->num_track_kerns + 1,
415                                            sizeof (AFMTrackKern));
416               if (font->track_kerns == NULL)
417                 parse_error (handle, AFM_ERROR_MEMORY);
418
419               read_track_kerns (handle, ctx, font);
420             }
421           else
422             {
423               do
424                 {
425                   (void) get_line_token (handle, ctx);
426                   get_key (handle, ctx, &key);
427                 }
428               while (key != kEndTrackKern);
429             }
430           break;
431
432         case kEndKernData:
433           break;
434
435           /* Composite Character Data. */
436         case kStartComposites:
437           if (font->info_level & AFM_I_COMPOSITES)
438             {
439               GET_VALUE (AFM_TYPE_INTEGER);
440               font->num_composites = node.u.integer;
441               font->composites
442                 = (AFMComposite *) calloc (font->num_composites + 1,
443                                            sizeof (AFMComposite));
444               if (font->composites == NULL)
445                 parse_error (handle, AFM_ERROR_MEMORY);
446
447               read_composites (handle, ctx, font);
448             }
449           else
450             {
451               do
452                 {
453                   (void) get_line_token (handle, ctx);
454                   get_key (handle, ctx, &key);
455                 }
456               while (key != kEndComposites);
457             }
458           break;
459
460         default:
461           /* Ignore. */
462           break;
463         }
464     }
465   fclose (ctx->fp);
466
467   /* Check post conditions. */
468
469   if (!font->writing_direction_metrics[0].is_valid
470       && !font->writing_direction_metrics[1].is_valid)
471     /* No direction specified, 0 implied. */
472     font->writing_direction_metrics[0].is_valid = AFMTrue;
473
474   /* Undef character. */
475   if (!strhash_get (font->private->fontnames, "space", 5,
476                     (void *) font->private->undef))
477     {
478       /* Character "space" is not defined.  Select the first one. */
479       assert (font->num_character_metrics > 0);
480       font->private->undef = &font->character_metrics[0];
481     }
482
483   /* Fixed pitch. */
484   if (font->writing_direction_metrics[0].is_valid
485       && font->writing_direction_metrics[0].IsFixedPitch)
486     {
487       /* Take one, it doesn't matter which one. */
488       font->writing_direction_metrics[0].CharWidth_x
489         = font->character_metrics[0].w0x;
490       font->writing_direction_metrics[0].CharWidth_y
491         = font->character_metrics[0].w0y;
492     }
493   if (font->writing_direction_metrics[1].is_valid
494       && font->writing_direction_metrics[1].IsFixedPitch)
495     {
496       font->writing_direction_metrics[1].CharWidth_x
497         = font->character_metrics[1].w1x;
498       font->writing_direction_metrics[1].CharWidth_y
499         = font->character_metrics[1].w1y;
500     }
501 }
502
503
504 /*
505  * Static functions.
506  */
507
508 static void
509 parse_error (AFMHandle handle, AFMError error)
510 {
511   handle->parse_error = error;
512   longjmp (handle->jmpbuf, 1);
513
514   /* If this is reached, then all is broken. */
515   fprintf (stderr, "AFM: fatal internal longjmp() error.\n");
516   abort ();
517 }
518
519
520 static int
521 get_token (AFMHandle handle, ParseCtx *ctx)
522 {
523   int ch;
524   int i;
525
526   /* Skip the leading whitespace. */
527   while ((ch = getc (ctx->fp)) != EOF)
528     if (!ISSPACE (ch))
529       break;
530
531   if (ch == EOF)
532     return 0;
533
534   ungetc (ch, ctx->fp);
535
536   /* Get name. */
537   for (i = 0, ch = getc (ctx->fp);
538        i < sizeof (ctx->token) && ch != EOF && !ISSPACE (ch);
539        i++, ch = getc (ctx->fp))
540     ctx->token[i] = ch;
541
542   if (i >= sizeof (ctx->token))
543     /* Line is too long, this is against AFM specification. */
544     parse_error (handle, AFM_ERROR_SYNTAX);
545
546   ctx->token[i] = '\0';
547   ctx->tokenlen = i;
548
549   return 1;
550 }
551
552
553 static int
554 get_line_token (AFMHandle handle, ParseCtx *ctx)
555 {
556   int i, ch;
557
558   /* Skip the leading whitespace. */
559   while ((ch = getc (ctx->fp)) != EOF)
560     if (!ISSPACE (ch))
561       break;
562
563   if (ch == EOF)
564     return 0;
565
566   ungetc (ch, ctx->fp);
567
568   /* Read to the end of the line. */
569   for (i = 0, ch = getc (ctx->fp);
570        i < sizeof (ctx->token) && ch != EOF && ch != '\n';
571        i++, ch = getc (ctx->fp))
572     ctx->token[i] = ch;
573
574   if (i >= sizeof (ctx->token))
575     parse_error (handle, AFM_ERROR_SYNTAX);
576
577   /* Skip all trailing whitespace. */
578   for (i--; i >= 0 && ISSPACE (ctx->token[i]); i--)
579     ;
580   i++;
581
582   ctx->token[i] = '\0';
583   ctx->tokenlen = i;
584
585   return 1;
586 }
587
588
589 static int
590 match_key (char *key)
591 {
592   int lower = 0;
593   int upper = NUM_KEYS;
594   int midpoint, cmpvalue;
595   AFMBoolean found = AFMFalse;
596
597   while ((upper >= lower) && !found)
598     {
599       midpoint = (lower + upper) / 2;
600       if (keynames[midpoint].name == NULL)
601         break;
602
603       cmpvalue = strcmp (key, keynames[midpoint].name);
604       if (cmpvalue == 0)
605         found = AFMTrue;
606       else if (cmpvalue < 0)
607         upper = midpoint - 1;
608       else
609         lower = midpoint + 1;
610     }
611
612   if (found)
613     return keynames[midpoint].key;
614
615   return -1;
616 }
617
618
619 static void
620 get_key (AFMHandle handle, ParseCtx *ctx, AFMKey *key_return)
621 {
622   int key;
623   char msg[256];
624
625   while (1)
626     {
627       if (!get_token (handle, ctx))
628         /* Unexpected EOF. */
629         parse_error (handle, AFM_ERROR_SYNTAX);
630
631       key = match_key (ctx->token);
632       if (key >= 0)
633         {
634           *key_return = key;
635           return;
636         }
637
638       /* No match found.  According to standard, we must skip this key. */
639       sprintf (msg, "skipping key \"%s\"", ctx->token);
640       afm_error (handle, msg);
641       get_line_token (handle, ctx);
642     }
643
644   /* NOTREACHED */
645 }
646
647
648 /* Reader for AFM types. */
649 static void
650 get_type (AFMHandle handle, ParseCtx *ctx, int type, AFMNode *type_return)
651 {
652   char buf[256];
653
654   switch (type)
655     {
656     case AFM_TYPE_STRING:
657       if (!get_line_token (handle, ctx))
658         parse_error (handle, AFM_ERROR_SYNTAX);
659
660       type_return->u.string = (AFMString) calloc (1, ctx->tokenlen + 1);
661       if (type_return->u.string == NULL)
662         parse_error (handle, AFM_ERROR_MEMORY);
663
664       memcpy (type_return->u.string, ctx->token, ctx->tokenlen);
665       break;
666
667     case AFM_TYPE_NAME:
668       if (!get_token (handle, ctx))
669         parse_error (handle, AFM_ERROR_SYNTAX);
670
671       type_return->u.name = (AFMName) calloc (1, ctx->tokenlen + 1);
672       if (type_return->u.string == NULL)
673         parse_error (handle, AFM_ERROR_MEMORY);
674
675       memcpy (type_return->u.name, ctx->token, ctx->tokenlen);
676       break;
677
678     case AFM_TYPE_NUMBER:
679       if (!get_token (handle, ctx))
680         parse_error (handle, AFM_ERROR_SYNTAX);
681
682       memcpy (buf, ctx->token, ctx->tokenlen);
683       buf[ctx->tokenlen] = '\0';
684       type_return->u.number = atof (buf);
685       break;
686
687     case AFM_TYPE_INTEGER:
688       if (!get_token (handle, ctx))
689         parse_error (handle, AFM_ERROR_SYNTAX);
690
691       memcpy (buf, ctx->token, ctx->tokenlen);
692       buf[ctx->tokenlen] = '\0';
693       type_return->u.integer = atoi (buf);
694       break;
695
696     case AFM_TYPE_ARRAY:
697       fprintf (stderr, "Array types not implemented yet.\n");
698       abort ();
699       break;
700
701     case AFM_TYPE_BOOLEAN:
702       if (!get_token (handle, ctx))
703         parse_error (handle, AFM_ERROR_SYNTAX);
704
705       memcpy (buf, ctx->token, ctx->tokenlen);
706       buf[ctx->tokenlen] = '\0';
707
708       if (strcmp (buf, "true") == 0)
709         type_return->u.boolean = AFMTrue;
710       else if (strcmp (buf, "false") == 0)
711         type_return->u.boolean = AFMFalse;
712       else
713         parse_error (handle, AFM_ERROR_SYNTAX);
714       break;
715
716     default:
717       fprintf (stderr, "get_type(): illegal type %d\n", type_return->type);
718       abort ();
719       break;
720     }
721 }
722
723
724 static void
725 read_character_metrics (AFMHandle handle, ParseCtx *ctx, AFMFont font)
726 {
727   int i = 0;
728   AFMNode node;
729   AFMIndividualCharacterMetrics *cm = NULL;
730   AFMKey key;
731   int done = 0;
732   int first = 1;
733
734   while (!done)
735     {
736       get_key (handle, ctx, &key);
737       switch (key)
738         {
739         case kC:
740           if (first)
741             first = 0;
742           else
743             i++;
744           if (i >= font->num_character_metrics)
745             parse_error (handle, AFM_ERROR_SYNTAX);
746
747           cm = &font->character_metrics[i];
748           GET_VALUE (AFM_TYPE_INTEGER);
749           cm->character_code = node.u.integer;
750           if (cm->character_code >= 0 && cm->character_code <= 255)
751             font->encoding[cm->character_code] = cm;
752           break;
753
754         case kCH:
755           printf ("* CH\n");
756           break;
757
758         case kWX:
759         case kW0X:
760           GET_VALUE (AFM_TYPE_NUMBER);
761           cm->w0x = node.u.number;
762           cm->w0y = 0.0;
763           break;
764
765         case kW1X:
766           GET_VALUE (AFM_TYPE_NUMBER);
767           cm->w1x = node.u.number;
768           cm->w1y = 0.0;
769           break;
770
771         case kWY:
772         case kW0Y:
773           GET_VALUE (AFM_TYPE_NUMBER);
774           cm->w0y = node.u.number;
775           cm->w0x = 0.0;
776           break;
777
778         case kW1Y:
779           GET_VALUE (AFM_TYPE_NUMBER);
780           cm->w1y = node.u.number;
781           cm->w1x = 0.0;
782           break;
783
784         case kW:
785         case kW0:
786           GET_VALUE (AFM_TYPE_NUMBER);
787           cm->w0x = node.u.number;
788           GET_VALUE (AFM_TYPE_NUMBER);
789           cm->w0y = node.u.number;
790           break;
791
792         case kW1:
793           GET_VALUE (AFM_TYPE_NUMBER);
794           cm->w1x = node.u.number;
795           GET_VALUE (AFM_TYPE_NUMBER);
796           cm->w1y = node.u.number;
797           break;
798
799         case kVV:
800           GET_VALUE (AFM_TYPE_NUMBER);
801           cm->vv_x = node.u.number;
802           GET_VALUE (AFM_TYPE_NUMBER);
803           cm->vv_y = node.u.number;
804           break;
805
806         case kN:
807           GET_VALUE (AFM_TYPE_NAME);
808           cm->name = node.u.name;
809           if (!strhash_put (font->private->fontnames, cm->name,
810                             strlen (cm->name), cm, NULL))
811             parse_error (handle, AFM_ERROR_MEMORY);
812           break;
813
814         case kB:
815           GET_VALUE (AFM_TYPE_NUMBER);
816           cm->llx = node.u.number;
817           GET_VALUE (AFM_TYPE_NUMBER);
818           cm->lly = node.u.number;
819           GET_VALUE (AFM_TYPE_NUMBER);
820           cm->urx = node.u.number;
821           GET_VALUE (AFM_TYPE_NUMBER);
822           cm->ury = node.u.number;
823           break;
824
825         case kL:
826           /* XXX Skip ligatures. */
827           get_line_token (handle, ctx);
828           break;
829
830         case kEndCharMetrics:
831           if (i != font->num_character_metrics - 1)
832             {
833               /*
834                * My opinion is that this is a syntax error; the
835                * creator of this AFM file should have been smart
836                * enought to count these character metrics.  Well,
837                * maybe that is too much asked...
838                */
839               font->num_character_metrics = i + 1;
840             }
841
842           done = 1;
843           break;
844
845         default:
846           parse_error (handle, AFM_ERROR_SYNTAX);
847           break;
848         }
849     }
850 }
851
852
853 static void
854 read_kern_pairs (AFMHandle handle, ParseCtx *ctx, AFMFont font)
855 {
856   int i;
857   AFMNode node;
858   AFMPairWiseKerning *kp;
859   AFMKey key;
860
861   for (i = 0; i < font->num_kern_pairs; i++)
862     {
863       kp = &font->kern_pairs[i];
864       get_key (handle, ctx, &key);
865
866       switch (key)
867         {
868         case kKP:
869         case kKPX:
870         case kKPY:
871           GET_VALUE (AFM_TYPE_NAME);
872           kp->name1 = node.u.name;
873
874           GET_VALUE (AFM_TYPE_NAME);
875           kp->name2 = node.u.name;
876
877           GET_VALUE (AFM_TYPE_NUMBER);
878
879           switch (key)
880             {
881             case kKP:
882               kp->kx = node.u.number;
883               GET_VALUE (AFM_TYPE_NUMBER);
884               kp->ky = node.u.number;
885               break;
886
887             case kKPX:
888               kp->kx = node.u.number;
889               kp->ky = 0.0;
890               break;
891
892             case kKPY:
893               kp->ky = node.u.number;
894               kp->kx = 0.0;
895               break;
896
897             default:
898               fprintf (stderr, "AFM: fatal corruption\n");
899               abort ();
900               break;
901             }
902           break;
903
904         case kKPH:
905           /* XXX ignore. */
906           break;
907
908         default:
909           parse_error (handle, AFM_ERROR_SYNTAX);
910           break;
911         }
912     }
913
914   /* Get end token. */
915   get_key (handle, ctx, &key);
916   if (key != kEndKernPairs)
917     parse_error (handle, AFM_ERROR_SYNTAX);
918 }
919
920
921 static void
922 read_track_kerns (AFMHandle handle, ParseCtx *ctx, AFMFont font)
923 {
924   int i;
925   AFMNode node;
926   AFMTrackKern *tk;
927   AFMKey key;
928
929   for (i = 0; i < font->num_kern_pairs; i++)
930     {
931       tk = &font->track_kerns[i];
932       get_key (handle, ctx, &key);
933
934       /* TrackKern degree min-ptsize min-kern max-ptrsize max-kern */
935
936       if (key != kTrackKern)
937         parse_error (handle, AFM_ERROR_SYNTAX);
938
939       GET_VALUE (AFM_TYPE_INTEGER);
940       tk->degree = node.u.integer;
941
942       GET_VALUE (AFM_TYPE_NUMBER);
943       tk->min_ptsize = node.u.number;
944
945       GET_VALUE (AFM_TYPE_NUMBER);
946       tk->min_kern = node.u.number;
947
948       GET_VALUE (AFM_TYPE_NUMBER);
949       tk->max_ptsize = node.u.number;
950
951       GET_VALUE (AFM_TYPE_NUMBER);
952       tk->max_kern = node.u.number;
953     }
954
955   /* Get end token. */
956   get_key (handle, ctx, &key);
957   if (key != kEndTrackKern)
958     parse_error (handle, AFM_ERROR_SYNTAX);
959 }
960
961
962 static void
963 read_composites (AFMHandle handle, ParseCtx *ctx, AFMFont font)
964 {
965   int i, j;
966   AFMNode node;
967   AFMComposite *cm;
968   AFMKey key;
969
970   for (i = 0; i < font->num_composites; i++)
971     {
972       cm = &font->composites[i];
973       get_key (handle, ctx, &key);
974
975       if (key != kCC)
976         parse_error (handle, AFM_ERROR_SYNTAX);
977
978       GET_VALUE (AFM_TYPE_NAME);
979       cm->name = node.u.name;
980
981       /* Create name -> AFMComposite mapping. */
982       if (!strhash_put (font->private->compositenames, cm->name,
983                         strlen (cm->name), cm, NULL))
984         parse_error (handle, AFM_ERROR_MEMORY);
985
986       GET_VALUE (AFM_TYPE_INTEGER);
987       cm->num_components = node.u.integer;
988       cm->components
989         = (AFMCompositeComponent *) calloc (cm->num_components + 1,
990                                             sizeof (AFMCompositeComponent));
991
992       /* Read composite components. */
993       for (j = 0; j < cm->num_components; j++)
994         {
995           /* Read "PCC". */
996           get_key (handle, ctx, &key);
997           if (key != kPCC)
998             parse_error (handle, AFM_ERROR_SYNTAX);
999
1000           /* Read values. */
1001
1002           GET_VALUE (AFM_TYPE_NAME);
1003           cm->components[j].name = node.u.name;
1004
1005           GET_VALUE (AFM_TYPE_NUMBER);
1006           cm->components[j].deltax = node.u.number;
1007
1008           GET_VALUE (AFM_TYPE_NUMBER);
1009           cm->components[j].deltay = node.u.number;
1010         }
1011     }
1012
1013   /* Get end token. */
1014   get_key (handle, ctx, &key);
1015   if (key != kEndComposites)
1016     parse_error (handle, AFM_ERROR_SYNTAX);
1017 }