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