afm.c - enscript - GNU Enscript
 (HTM) git clone git://thinkerwim.org/enscript.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       afm.c (19635B)
       ---
            1 /*
            2  * AFM library public interface.
            3  * Copyright (c) 1995-1999 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  * Static variables
           28  */
           29 
           30 static char *default_path = "/usr/local/lib/ps:/usr/lib/ps";
           31 
           32 static char *error_names[] =
           33 {
           34   "AFM Success",
           35   "AFM Error",
           36   "out of memory",
           37   "illegal argument",
           38   "unknown font",
           39   "syntax error",
           40   "unsupported format",
           41   "file IO failed",
           42   "file is not an AFM file",
           43 };
           44 
           45 /*
           46  * Prototypes for static functions.
           47  */
           48 
           49 static void read_font_map ___P ((AFMHandle handle, char *name));
           50 static void apply_encoding ___P ((AFMFont font, AFMEncodingTable *enc,
           51                                   unsigned int flags));
           52 
           53 
           54 /*
           55  * Global functions.
           56  */
           57 
           58 void
           59 afm_error_to_string (AFMError error, char *buf)
           60 {
           61   char *syserr;
           62   int code, syserrno;
           63 
           64   code = error & 0xffff;
           65   syserrno = (error >> 16) & 0xffff;
           66 
           67   if (syserrno)
           68     syserr = strerror (syserrno);
           69   else
           70     syserr = NULL;
           71 
           72   if (code >= NUM_ERRORS)
           73     {
           74       sprintf (buf, "afm_error_to_string(): illegal error code: %d\n",
           75                error);
           76       return;
           77     }
           78 
           79   if (code == 0)
           80     sprintf (buf, "AFM Success");
           81   else if (code == 1)
           82     sprintf (buf, "%s%s%s", "AFM Error",
           83              syserr ? ":" : "",
           84              syserr ? syserr : "");
           85   else
           86     sprintf (buf, "AFM Error: %s%s%s", error_names[code],
           87              syserr ? ": " : "",
           88              syserr ? syserr : "");
           89 }
           90 
           91 
           92 AFMError
           93 afm_create (const char *path, unsigned int verbose_level,
           94             AFMHandle *handle_return)
           95 {
           96   AFMHandle handle;
           97   AFMError error = AFM_SUCCESS;
           98   const char *cp, *cp2;
           99   int len;
          100   char buf[512];
          101   struct stat stat_st;
          102 
          103   /* Init handle. */
          104 
          105   handle = (AFMHandle) calloc (1, sizeof (*handle));
          106   if (handle == NULL)
          107     {
          108       error = AFM_ERROR_MEMORY;
          109       goto error_out;
          110     }
          111 
          112   handle->font_map = strhash_init ();
          113   if (handle->font_map == NULL)
          114     {
          115       error = AFM_ERROR_MEMORY;
          116       goto error_out;
          117     }
          118 
          119   handle->verbose = verbose_level;
          120 
          121   /* Traverse path. */
          122 
          123   if (path == NULL)
          124     path = default_path;
          125 
          126   afm_message (handle, 1, "AFM: scanning path...\n");
          127   for (cp = path; cp; cp = strchr (cp, PATH_SEPARATOR))
          128     {
          129       if (cp != path)
          130         cp++;
          131 
          132       cp2 = strchr (cp, PATH_SEPARATOR);
          133       if (cp2)
          134         len = cp2 - cp;
          135       else
          136         len = strlen (cp);
          137 
          138       memcpy (buf, cp, len);
          139       buf[len] = '\0';
          140       if (len > 0 && buf[len - 1] == '/')
          141         buf[len - 1] = '\0';
          142 
          143       strcat (buf, "/font.map");
          144 
          145       if (stat (buf, &stat_st) == 0)
          146         read_font_map (handle, buf);
          147     }
          148 
          149   *handle_return = handle;
          150 
          151   return AFM_SUCCESS;
          152 
          153 
          154   /* Error handling. */
          155 
          156  error_out:
          157 
          158   (void) afm_destroy (handle);
          159 
          160   return error;
          161 }
          162 
          163 
          164 AFMError
          165 afm_destroy (AFMHandle handle)
          166 {
          167   char *key;
          168   int keylen;
          169   char *cp;
          170 
          171   if (handle == NULL)
          172     return AFM_ERROR_ARGUMENT;
          173 
          174   /* Free filenames. */
          175   while (strhash_get_first (handle->font_map, &key, &keylen, (void *) &cp))
          176     free (cp);
          177 
          178   strhash_free (handle->font_map);
          179   free (handle);
          180 
          181   return AFM_SUCCESS;
          182 }
          183 
          184 
          185 AFMError
          186 afm_set_verbose (AFMHandle handle, unsigned int level)
          187 {
          188   if (handle == NULL)
          189     return AFM_ERROR_ARGUMENT;
          190 
          191   handle->verbose = level;
          192 
          193   return AFM_SUCCESS;
          194 }
          195 
          196 
          197 AFMError
          198 afm_font_prefix (AFMHandle handle, const char *fontname,
          199                  const char **prefix_return)
          200 {
          201   char *filename;
          202 
          203   if (handle == NULL || fontname == NULL || prefix_return == NULL)
          204     return AFM_ERROR_ARGUMENT;
          205 
          206   /* Lookup font. */
          207   if (!strhash_get (handle->font_map, fontname, strlen (fontname),
          208                     (void *) &filename))
          209     return AFM_ERROR_UNKNOWN_FONT;
          210 
          211   *prefix_return = filename;
          212 
          213   return AFM_SUCCESS;
          214 }
          215 
          216 
          217 AFMError
          218 afm_open_font (AFMHandle handle, unsigned int info_level,
          219                const char *fontname, AFMFont *font_return)
          220 {
          221   char *filename;
          222   char fname[512];
          223 
          224   if (handle == NULL || fontname == NULL)
          225     return AFM_ERROR_ARGUMENT;
          226 
          227   /* Lookup font. */
          228   if (!strhash_get (handle->font_map, fontname, strlen (fontname),
          229                     (void *) &filename))
          230     return AFM_ERROR_UNKNOWN_FONT;
          231 
          232   /* Append suffix to the filename. */
          233   sprintf (fname, "%s.afm", filename);
          234 
          235   return afm_open_file (handle, info_level, fname, font_return);
          236 }
          237 
          238 
          239 AFMError
          240 afm_open_file (AFMHandle handle, unsigned int info_level,
          241                const char *filename, AFMFont *font_return)
          242 {
          243   AFMFont font;
          244   AFMError error = AFM_SUCCESS;
          245 
          246   if (handle == NULL || filename == NULL)
          247     return AFM_ERROR_ARGUMENT;
          248 
          249   font = (AFMFont) calloc (1, sizeof (*font));
          250   if (font == NULL)
          251     return AFM_ERROR_MEMORY;
          252 
          253   font->private
          254     = (struct afm_font_private_data_st *) calloc (1, sizeof (*font->private));
          255   if (font->private == NULL)
          256     {
          257       error = AFM_ERROR_MEMORY;
          258       goto error_out;
          259     }
          260   font->private->fontnames = strhash_init ();
          261   if (font->private->fontnames == NULL)
          262     {
          263       error = AFM_ERROR_MEMORY;
          264       goto error_out;
          265     }
          266 
          267   font->private->compositenames = strhash_init ();
          268   if (font->private->compositenames == NULL)
          269     {
          270       error = AFM_ERROR_MEMORY;
          271       goto error_out;
          272     }
          273 
          274   font->info_level = info_level;
          275 
          276   /* Parse file. */
          277   if (setjmp (handle->jmpbuf))
          278     {
          279       /* Error during parse. */
          280       error = handle->parse_error;
          281       goto error_out;
          282     }
          283   else
          284     {
          285       afm_parse_file (handle, filename, font);
          286       /* Parse successful. */
          287     }
          288 
          289   *font_return = font;
          290   return AFM_SUCCESS;
          291 
          292 
          293   /* Error handling. */
          294 
          295  error_out:
          296 
          297   (void) afm_close_font (font);
          298 
          299   return error;
          300 }
          301 
          302 
          303 #define FREE(ptr) if (ptr) free (ptr)
          304 AFMError
          305 afm_close_font (AFMFont font)
          306 {
          307   int i;
          308 
          309   if (font == NULL)
          310     return AFM_ERROR_ARGUMENT;
          311 
          312   /* Global info. */
          313   FREE (font->global_info.FontName);
          314   FREE (font->global_info.FullName);
          315   FREE (font->global_info.FamilyName);
          316   FREE (font->global_info.Weight);
          317   FREE (font->global_info.Version);
          318   FREE (font->global_info.Notice);
          319   FREE (font->global_info.EncodingScheme);
          320   FREE (font->global_info.CharacterSet);
          321 
          322   /* Character metrics. */
          323   for (i = 0; i < font->num_character_metrics; i++)
          324     FREE (font->character_metrics[i].name);
          325   FREE (font->character_metrics);
          326 
          327   /* Composites. */
          328   for (i = 0; i < font->num_composites; i++)
          329     FREE (font->composites[i].name);
          330   FREE (font->composites);
          331 
          332   /* Kern pairs. */
          333   for (i = 0; i < font->num_kern_pairs; i++)
          334     {
          335       FREE (font->kern_pairs[i].name1);
          336       FREE (font->kern_pairs[i].name2);
          337     }
          338   FREE (font->kern_pairs);
          339 
          340   /* Track kern. */
          341   FREE (font->track_kerns);
          342 
          343   /* Private data. */
          344   strhash_free (font->private->fontnames);
          345   strhash_free (font->private->compositenames);
          346 
          347   free (font);
          348 
          349   return AFM_SUCCESS;
          350 }
          351 
          352 
          353 #define STR(str) (str ? str : "")
          354 #define BOOL(val) (val ? "true" : "false")
          355 void
          356 afm_font_dump (FILE *fp, AFMFont font)
          357 {
          358   int i;
          359 
          360   fprintf (fp, "AFM Format Specification version: %g\n", font->version);
          361   fprintf (fp, "Global Font Information\n");
          362   fprintf (fp, "  FontName:\t%s\n",         STR (font->global_info.FontName));
          363   fprintf (fp, "  FullName:\t%s\n",         STR (font->global_info.FullName));
          364   fprintf (fp, "  FamilyName:\t%s\n",         STR (font->global_info.FamilyName));
          365   fprintf (fp, "  Weight:\t%s\n",         STR (font->global_info.Weight));
          366   fprintf (fp, "  FontBBox:\t%g %g %g %g\n",
          367            font->global_info.FontBBox_llx, font->global_info.FontBBox_lly,
          368            font->global_info.FontBBox_urx, font->global_info.FontBBox_ury);
          369   fprintf (fp, "  Version:\t%s\n",         STR (font->global_info.Version));
          370   fprintf (fp, "  Notice:\t%s\n",         STR (font->global_info.Notice));
          371   fprintf (fp, "  EncodingScheme:\t%s\n",
          372            STR (font->global_info.EncodingScheme));
          373   fprintf (fp, "  MappingScheme:\t%ld\n", font->global_info.MappingScheme);
          374   fprintf (fp, "  EscChar:\t%ld\n", font->global_info.EscChar);
          375   fprintf (fp, "  CharacterSet:\t%s\n", STR (font->global_info.CharacterSet));
          376   fprintf (fp, "  Characters:\t%ld\n",         font->global_info.Characters);
          377   fprintf (fp, "  IsBaseFont:\t%s\n",         BOOL(font->global_info.IsBaseFont));
          378   fprintf (fp, "  VVector:\t%g %g\n",
          379            font->global_info.VVector_0,        font->global_info.VVector_1);
          380   fprintf (fp, "  IsFixedV:\t%s\n",         BOOL(font->global_info.IsFixedV));
          381   fprintf (fp, "  CapHeight:\t%g\n",         font->global_info.CapHeight);
          382   fprintf (fp, "  XHeight:\t%g\n",         font->global_info.XHeight);
          383   fprintf (fp, "  Ascender:\t%g\n",         font->global_info.Ascender);
          384   fprintf (fp, "  Descender:\t%g\n",         font->global_info.Descender);
          385 
          386   for (i = 0; i < 2; i++)
          387     if (font->writing_direction_metrics[i].is_valid)
          388       {
          389         fprintf (fp, "Writing Direction %d\n", i);
          390         fprintf (fp, "  UnderlinePosition: %g\n",
          391                  font->writing_direction_metrics[i].UnderlinePosition);
          392         fprintf (fp, "  UnderlineThickness: %g\n",
          393                  font->writing_direction_metrics[i].UnderlineThickness);
          394         fprintf (fp, "  ItalicAngle: %g\n",
          395                  font->writing_direction_metrics[i].ItalicAngle);
          396         fprintf (fp, "  CharWidth: %g %g\n",
          397                  font->writing_direction_metrics[i].CharWidth_x,
          398                  font->writing_direction_metrics[i].CharWidth_y);
          399         fprintf (fp, "  IsFixedPitch: %s\n",
          400                  BOOL (font->writing_direction_metrics[i].IsFixedPitch));
          401       }
          402 
          403   /* Individual Character Metrics. */
          404   fprintf (fp, "Individual Character Metrics %ld\n",
          405            font->num_character_metrics);
          406   for (i = 0; i < font->num_character_metrics; i++)
          407     {
          408       AFMIndividualCharacterMetrics *cm;
          409       cm = &font->character_metrics[i];
          410 
          411       fprintf (fp, "  C %ld ; N %s ; B %g %g %g %g\n",
          412                cm->character_code, STR (cm->name),
          413                cm->llx, cm->lly, cm->urx, cm->ury);
          414       fprintf (fp,
          415                "    W0X %g ; W0Y %g ; W1X %g ; W1Y %g ; VV %g %g\n",
          416                cm->w0x, cm->w0y, cm->w1x, cm->w1y, cm->vv_x, cm->vv_y);
          417     }
          418 
          419   /* Composite Character Data. */
          420   fprintf (fp, "Composite Character Data %ld\n", font->num_composites);
          421   for (i = 0; i < font->num_composites; i++)
          422     {
          423       AFMComposite *cm;
          424       int j;
          425 
          426       cm = &font->composites[i];
          427 
          428       fprintf (fp, "  CC %s %ld", cm->name, cm->num_components);
          429       for (j = 0; j < cm->num_components; j++)
          430         fprintf (fp, " ; PCC %s %g %g",
          431                  cm->components[j].name,
          432                  cm->components[j].deltax,
          433                  cm->components[j].deltay);
          434       fprintf (fp, "\n");
          435     }
          436 
          437   /* Kern pairs. */
          438   fprintf (fp, "Pair-Wise Kerning %ld\n", font->num_kern_pairs);
          439   for (i = 0; i < font->num_kern_pairs; i++)
          440     {
          441       AFMPairWiseKerning *kp;
          442       kp = &font->kern_pairs[i];
          443 
          444       fprintf (fp, "  KP %s %s %g %g\n", STR (kp->name1), STR (kp->name2),
          445                kp->kx, kp->ky);
          446     }
          447 
          448   fprintf (fp, "Track Kerning %ld\n", font->num_track_kerns);
          449   for (i = 0; i < font->num_track_kerns; i++)
          450     {
          451       AFMTrackKern *tk;
          452       tk = &font->track_kerns[i];
          453 
          454       fprintf (fp, "  TrackKern %ld %g %g %g %g\n", tk->degree,
          455                tk->min_ptsize, tk->min_kern,
          456                tk->max_ptsize, tk->max_kern);
          457     }
          458 }
          459 
          460 
          461 AFMError
          462 afm_font_stringwidth (AFMFont font, AFMNumber ptsize, char *string,
          463                       unsigned int stringlen, AFMNumber *w0x_return,
          464                       AFMNumber *w0y_return)
          465 {
          466   unsigned int i;
          467   AFMNumber x = 0.0;
          468   AFMNumber y = 0.0;
          469   AFMIndividualCharacterMetrics *cm;
          470 
          471   if (!font || !string || !font->writing_direction_metrics[0].is_valid)
          472     return AFM_ERROR_ARGUMENT;
          473 
          474   /* Check shortcut. */
          475   if (font->writing_direction_metrics[0].IsFixedPitch)
          476     {
          477       /* This is the easy case. */
          478       x = stringlen * font->writing_direction_metrics[0].CharWidth_x;
          479       y = stringlen * font->writing_direction_metrics[0].CharWidth_y;
          480     }
          481   else
          482     {
          483       /* Count character by character. */
          484       for (i = 0; i < stringlen; i++)
          485         {
          486           cm = font->encoding[(unsigned char) string[i]];
          487           if (cm == AFM_ENC_NONE || cm == AFM_ENC_NON_EXISTENT)
          488             {
          489               /* Use the undef font. */
          490               x += font->private->undef->w0x;
          491               y += font->private->undef->w0y;
          492             }
          493           else
          494             {
          495               /* Font found and valid, take values. */
          496               x += cm->w0x;
          497               y += cm->w0y;
          498             }
          499         }
          500     }
          501 
          502   *w0x_return = x / UNITS_PER_POINT * ptsize;
          503   *w0y_return = y / UNITS_PER_POINT * ptsize;
          504 
          505   return AFM_SUCCESS;
          506 }
          507 
          508 
          509 AFMError
          510 afm_font_charwidth (AFMFont font, AFMNumber ptsize, char ch,
          511                     AFMNumber *w0x_return, AFMNumber *w0y_return)
          512 {
          513   AFMNumber x = 0.0;
          514   AFMNumber y = 0.0;
          515   AFMIndividualCharacterMetrics *cm;
          516 
          517   if (!font || !font->writing_direction_metrics[0].is_valid)
          518     return AFM_ERROR_ARGUMENT;
          519 
          520   /* Check shortcut. */
          521   if (font->writing_direction_metrics[0].IsFixedPitch)
          522     {
          523       x = font->writing_direction_metrics[0].CharWidth_x;
          524       y = font->writing_direction_metrics[0].CharWidth_y;
          525     }
          526   else
          527     {
          528       cm = font->encoding[(unsigned char) ch];
          529       if (cm == AFM_ENC_NONE || cm == AFM_ENC_NON_EXISTENT)
          530         {
          531           /* Use the undef font. */
          532           x = font->private->undef->w0x;
          533           y = font->private->undef->w0y;
          534         }
          535       else
          536         {
          537           /* Font found and valid, take values. */
          538           x = cm->w0x;
          539           y = cm->w0y;
          540         }
          541     }
          542 
          543   *w0x_return = x / UNITS_PER_POINT * ptsize;
          544   *w0y_return = y / UNITS_PER_POINT * ptsize;
          545 
          546   return AFM_SUCCESS;
          547 }
          548 
          549 
          550 AFMError
          551 afm_font_encode (AFMFont font, unsigned char code, char *name,
          552                  unsigned int flags)
          553 {
          554   AFMIndividualCharacterMetrics *cm;
          555   AFMComposite *comp;
          556 
          557   if (font == NULL)
          558     return AFM_ERROR_ARGUMENT;
          559 
          560   if (name)
          561     {
          562       /* Get font. */
          563       if (!strhash_get (font->private->fontnames, name, strlen (name),
          564                         (void *) &cm))
          565         {
          566           /* Check composite characters. */
          567           if ((flags & AFM_ENCODE_ACCEPT_COMPOSITES) == 0
          568               || strhash_get (font->private->compositenames, name,
          569                               strlen (name), (void *) &comp) == 0)
          570             cm = AFM_ENC_NON_EXISTENT;
          571           else
          572             {
          573               /*
          574                * Ok, composite character found, now find the character
          575                * specified by the first composite component.
          576                */
          577               if (!strhash_get (font->private->fontnames,
          578                                 comp->components[0].name,
          579                                 strlen (comp->components[0].name),
          580                                 (void *) &cm))
          581                 cm = AFM_ENC_NON_EXISTENT;
          582             }
          583         }
          584     }
          585   else
          586     cm = AFM_ENC_NONE;
          587 
          588   font->encoding[(unsigned int) code] = cm;
          589 
          590   return AFM_SUCCESS;
          591 }
          592 
          593 
          594 AFMError
          595 afm_font_encoding (AFMFont font, AFMEncoding enc, unsigned int flags)
          596 {
          597   int i;
          598   AFMIndividualCharacterMetrics *cm;
          599 
          600   if (font == NULL)
          601     return AFM_ERROR_ARGUMENT;
          602 
          603   switch (enc)
          604     {
          605     case AFM_ENCODING_DEFAULT:
          606       /* Clear encoding. */
          607       for (i = 0; i < 256; i++)
          608         font->encoding[i] = AFM_ENC_NONE;
          609 
          610       /* Apply font's default encoding. */
          611       for (i = 0; i < font->num_character_metrics; i++)
          612         {
          613           cm = &font->character_metrics[i];
          614           font->encoding[cm->character_code] = cm;
          615         }
          616       break;
          617 
          618     case AFM_ENCODING_ISO_8859_1:
          619       apply_encoding (font, afm_88591_encoding, flags);
          620       break;
          621 
          622     case AFM_ENCODING_ISO_8859_2:
          623       apply_encoding (font, afm_88592_encoding, flags);
          624       break;
          625 
          626     case AFM_ENCODING_ISO_8859_3:
          627       apply_encoding (font, afm_88593_encoding, flags);
          628       break;
          629 
          630     case AFM_ENCODING_ISO_8859_4:
          631       apply_encoding (font, afm_88594_encoding, flags);
          632       break;
          633 
          634     case AFM_ENCODING_ISO_8859_5:
          635       apply_encoding (font, afm_88595_encoding, flags);
          636       break;
          637 
          638     case AFM_ENCODING_ISO_8859_7:
          639       apply_encoding (font, afm_88597_encoding, flags);
          640       break;
          641 
          642     case AFM_ENCODING_ISO_8859_9:
          643       apply_encoding (font, afm_88599_encoding, flags);
          644       break;
          645 
          646     case AFM_ENCODING_ISO_8859_10:
          647       apply_encoding (font, afm_885910_encoding, flags);
          648       break;
          649 
          650     case AFM_ENCODING_IBMPC:
          651       apply_encoding (font, afm_ibmpc_encoding, flags);
          652       break;
          653 
          654     case AFM_ENCODING_ASCII:
          655       /*
          656        * First apply one encoding (all have equal first 128 characters),
          657        * then zap last 128 chars.
          658        */
          659       apply_encoding (font, afm_88591_encoding, flags);
          660       for (i = 128; i < 256; i++)
          661         font->encoding[i] = AFM_ENC_NONE;
          662       break;
          663 
          664     case AFM_ENCODING_MAC:
          665       apply_encoding (font, afm_mac_encoding, flags);
          666       break;
          667 
          668     case AFM_ENCODING_VMS:
          669       apply_encoding (font, afm_vms_encoding, flags);
          670       break;
          671 
          672     case AFM_ENCODING_HP8:
          673       apply_encoding (font, afm_hp8_encoding, flags);
          674       break;
          675 
          676     case AFM_ENCODING_KOI8:
          677       apply_encoding (font, afm_koi8_encoding, flags);
          678       break;
          679     }
          680 
          681   return AFM_SUCCESS;
          682 }
          683 
          684 
          685 /*
          686  * Internal help functions.
          687  */
          688 
          689 
          690 void
          691 afm_message (AFMHandle handle, unsigned int level, char *message)
          692 {
          693   if (handle->verbose < level)
          694     return;
          695 
          696   fprintf (stderr, "%s", message);
          697 }
          698 
          699 
          700 void
          701 afm_error (AFMHandle handle, char *message)
          702 {
          703   fprintf (stderr, "AFM Error: %s\n", message);
          704 }
          705 
          706 
          707 /*
          708  * Static functions.
          709  */
          710 
          711 static void
          712 read_font_map (AFMHandle handle, char *name)
          713 {
          714   FILE *fp;
          715   char buf[512];
          716   char fullname[512];
          717   unsigned int dirlen;
          718   char *cp, *cp2;
          719   char msg[256];
          720 
          721   sprintf (msg, "AFM: reading font map \"%s\"\n", name);
          722   afm_message (handle, 1, msg);
          723 
          724   fp = fopen (name, "r");
          725   if (fp == NULL)
          726     {
          727       sprintf (msg, "AFM: couldn't open font map \"%s\": %s\n", name,
          728                strerror (errno));
          729       afm_message (handle, 1, msg);
          730       return;
          731     }
          732 
          733   /* Get directory */
          734   cp = strrchr (name, '/');
          735   if (cp)
          736     {
          737       dirlen = cp - name + 1;
          738       memcpy (fullname, name, dirlen);
          739     }
          740   else
          741     {
          742       dirlen = 2;
          743       memcpy (fullname, "./", dirlen);
          744     }
          745 
          746   while (fgets (buf, sizeof (buf), fp))
          747     {
          748       char font[256];
          749       char file[256];
          750 
          751       if (sscanf (buf, "%s %s", font, file) != 2)
          752         {
          753           sprintf (msg, "malformed line in font map \"%s\":\n%s",
          754                    name, buf);
          755           afm_error (handle, msg);
          756           continue;
          757         }
          758 
          759       /* Do we already have this font? */
          760       if (strhash_get (handle->font_map, font, strlen (font), (void *) &cp))
          761         continue;
          762 
          763       /* Append file name. */
          764       strcpy (fullname + dirlen, file);
          765       cp = (char *) malloc (strlen (fullname) + 1);
          766       if (cp == NULL)
          767         {
          768           afm_error (handle, "couldn't add font: out of memory");
          769           goto out;
          770         }
          771       strcpy (cp, fullname);
          772 
          773       sprintf (msg, "AFM: font mapping: %s -> %s\n", font, cp);
          774       afm_message (handle, 2, msg);
          775       (void) strhash_put (handle->font_map, font, strlen (font), cp,
          776                           (void *) &cp2);
          777     }
          778 
          779  out:
          780   fclose (fp);
          781 }
          782 
          783 
          784 static void
          785 apply_encoding (AFMFont font, AFMEncodingTable *enc, unsigned int flags)
          786 {
          787   int i;
          788   AFMIndividualCharacterMetrics *cm;
          789   AFMComposite *comp;
          790 
          791   for (i = 0; enc[i].code >= 0; i++)
          792     {
          793       if (enc[i].character == AFM_ENC_NONE)
          794         font->encoding[enc[i].code] = AFM_ENC_NONE;
          795       else if (enc[i].character == AFM_ENC_NON_EXISTENT)
          796         font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
          797       else
          798         {
          799           if (strhash_get (font->private->fontnames, enc[i].character,
          800                            strlen (enc[i].character), (void *) &cm))
          801             font->encoding[enc[i].code] = cm;
          802           else
          803             {
          804               /* Check composite characters. */
          805               if ((flags & AFM_ENCODE_ACCEPT_COMPOSITES) == 0
          806                   || strhash_get (font->private->compositenames,
          807                                   enc[i].character, strlen (enc[i].character),
          808                                   (void *) &comp) == 0)
          809                 font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
          810               else
          811                 {
          812                   /* Composite character found. */
          813                   if (strhash_get (font->private->fontnames,
          814                                    comp->components[0].name,
          815                                    strlen (comp->components[0].name),
          816                                    (void *) &cm))
          817                     font->encoding[enc[i].code] = cm;
          818                   else
          819                     font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
          820                 }
          821             }
          822         }
          823     }
          824 }