afmparse.c - enscript - GNU Enscript
 (HTM) git clone git://thinkerwim.org/enscript.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       afmparse.c (23680B)
       ---
            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[1024+16];
          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 }