a9925eddc71d2c1fe585b4edf7f560823ea76c8b
[enscript.git] / 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  * 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_ISO_8859_15:
651       apply_encoding (font, afm_885915_encoding, flags);
652       break;
653
654     case AFM_ENCODING_IBMPC:
655       apply_encoding (font, afm_ibmpc_encoding, flags);
656       break;
657
658     case AFM_ENCODING_ASCII:
659       /*
660        * First apply one encoding (all have equal first 128 characters),
661        * then zap last 128 chars.
662        */
663       apply_encoding (font, afm_88591_encoding, flags);
664       for (i = 128; i < 256; i++)
665         font->encoding[i] = AFM_ENC_NONE;
666       break;
667
668     case AFM_ENCODING_MAC:
669       apply_encoding (font, afm_mac_encoding, flags);
670       break;
671
672     case AFM_ENCODING_VMS:
673       apply_encoding (font, afm_vms_encoding, flags);
674       break;
675
676     case AFM_ENCODING_HP8:
677       apply_encoding (font, afm_hp8_encoding, flags);
678       break;
679
680     case AFM_ENCODING_KOI8:
681       apply_encoding (font, afm_koi8_encoding, flags);
682       break;
683     }
684
685   return AFM_SUCCESS;
686 }
687
688
689 /*
690  * Internal help functions.
691  */
692
693
694 void
695 afm_message (AFMHandle handle, unsigned int level, char *message)
696 {
697   if (handle->verbose < level)
698     return;
699
700   fprintf (stderr, "%s", message);
701 }
702
703
704 void
705 afm_error (AFMHandle handle, char *message)
706 {
707   fprintf (stderr, "AFM Error: %s\n", message);
708 }
709
710
711 /*
712  * Static functions.
713  */
714
715 static void
716 read_font_map (AFMHandle handle, char *name)
717 {
718   FILE *fp;
719   char buf[512];
720   char fullname[512];
721   unsigned int dirlen;
722   char *cp, *cp2;
723   char msg[256];
724
725   sprintf (msg, "AFM: reading font map \"%s\"\n", name);
726   afm_message (handle, 1, msg);
727
728   fp = fopen (name, "r");
729   if (fp == NULL)
730     {
731       sprintf (msg, "AFM: couldn't open font map \"%s\": %s\n", name,
732                strerror (errno));
733       afm_message (handle, 1, msg);
734       return;
735     }
736
737   /* Get directory */
738   cp = strrchr (name, '/');
739   if (cp)
740     {
741       dirlen = cp - name + 1;
742       memcpy (fullname, name, dirlen);
743     }
744   else
745     {
746       dirlen = 2;
747       memcpy (fullname, "./", dirlen);
748     }
749
750   while (fgets (buf, sizeof (buf), fp))
751     {
752       char font[256];
753       char file[256];
754
755       if (sscanf (buf, "%s %s", font, file) != 2)
756         {
757           sprintf (msg, "malformed line in font map \"%s\":\n%s",
758                    name, buf);
759           afm_error (handle, msg);
760           continue;
761         }
762
763       /* Do we already have this font? */
764       if (strhash_get (handle->font_map, font, strlen (font), (void *) &cp))
765         continue;
766
767       /* Append file name. */
768       strcpy (fullname + dirlen, file);
769       cp = (char *) malloc (strlen (fullname) + 1);
770       if (cp == NULL)
771         {
772           afm_error (handle, "couldn't add font: out of memory");
773           goto out;
774         }
775       strcpy (cp, fullname);
776
777       sprintf (msg, "AFM: font mapping: %s -> %s\n", font, cp);
778       afm_message (handle, 2, msg);
779       (void) strhash_put (handle->font_map, font, strlen (font), cp,
780                           (void *) &cp2);
781     }
782
783  out:
784   fclose (fp);
785 }
786
787
788 static void
789 apply_encoding (AFMFont font, AFMEncodingTable *enc, unsigned int flags)
790 {
791   int i;
792   AFMIndividualCharacterMetrics *cm;
793   AFMComposite *comp;
794
795   for (i = 0; enc[i].code >= 0; i++)
796     {
797       if (enc[i].character == AFM_ENC_NONE)
798         font->encoding[enc[i].code] = AFM_ENC_NONE;
799       else if (enc[i].character == AFM_ENC_NON_EXISTENT)
800         font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
801       else
802         {
803           if (strhash_get (font->private->fontnames, enc[i].character,
804                            strlen (enc[i].character), (void *) &cm))
805             font->encoding[enc[i].code] = cm;
806           else
807             {
808               /* Check composite characters. */
809               if ((flags & AFM_ENCODE_ACCEPT_COMPOSITES) == 0
810                   || strhash_get (font->private->compositenames,
811                                   enc[i].character, strlen (enc[i].character),
812                                   (void *) &comp) == 0)
813                 font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
814               else
815                 {
816                   /* Composite character found. */
817                   if (strhash_get (font->private->fontnames,
818                                    comp->components[0].name,
819                                    strlen (comp->components[0].name),
820                                    (void *) &cm))
821                     font->encoding[enc[i].code] = cm;
822                   else
823                     font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
824                 }
825             }
826         }
827     }
828 }