Back to index

texmacs  1.0.7.15
agl.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/agl.c,v 1.34 2009/09/18 23:56:02 matthias Exp $
00002 
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007 
00008     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019 
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023 */
00024 
00025 /*
00026  * References:
00027  *
00028  *  Unicode and Glyph Names, ver. 2.3., Adobe Solution Network
00029  *  http://partners.adobe.com/asn/tech/type/unicodegn.jsp
00030  */
00031 
00032 #if HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 #include <string.h>
00037 #include <ctype.h>
00038 
00039 #include "system.h"
00040 #include "mem.h"
00041 #include "error.h"
00042 
00043 #include "mfileio.h"
00044 #include "pdfparse.h"
00045 
00046 /* Hash */
00047 #include "dpxutil.h"
00048 
00049 #include "dpxfile.h"
00050 
00051 #include "unicode.h"
00052 
00053 #include "agl.h"
00054 
00055 static int verbose = 0;
00056 
00057 void
00058 agl_set_verbose (void)
00059 {
00060   verbose++;
00061 }
00062 
00063 static agl_name *
00064 agl_new_name (void)
00065 {
00066   agl_name *agln;
00067 
00068   agln = NEW(1, agl_name);
00069   agln->name   = NULL;
00070   agln->suffix = NULL;
00071   agln->n_components = 0;
00072   agln->alternate = NULL;
00073   agln->is_predef = 0;
00074 
00075   return agln;
00076 }
00077 
00078 static void
00079 agl_release_name (agl_name *agln)
00080 {
00081   agl_name *next;
00082 
00083   while (agln) {
00084     next = agln->alternate;
00085     if (agln->name)
00086       RELEASE(agln->name);
00087     if (agln->suffix)
00088       RELEASE(agln->suffix);
00089     agln->name = NULL;
00090     RELEASE(agln);
00091     agln = next;
00092   }
00093 }
00094 
00095 char *
00096 agl_chop_suffix (const char *glyphname, char **suffix)
00097 {
00098   char  *name, *p;
00099   int    len;
00100 
00101   ASSERT(glyphname && suffix);
00102 
00103   p = strchr(glyphname, '.');
00104   if (p) {
00105     len = strlen(glyphname) - strlen(p);
00106     if (len < 1) {
00107       name = NULL;
00108       *suffix = NEW(strlen(glyphname), char);
00109       strcpy(*suffix, glyphname+1);
00110     } else {
00111       p++;
00112       name = NEW(len + 1, char);
00113       strncpy(name, glyphname, len);
00114       name[len] = '\0';
00115       if (p[0] == '\0') {
00116        *suffix = NULL;
00117       } else {
00118        *suffix = NEW(strlen(p) + 1, char);
00119        strcpy(*suffix, p);
00120       }
00121     }
00122   } else {
00123     name = NEW(strlen(glyphname) + 1, char);
00124     strcpy(name, glyphname);
00125     *suffix = NULL;
00126   }
00127 
00128   return name;
00129 }
00130 
00131 static const char * const modifiers[] = {
00132   "acute", "breve", "caron", "cedilla", "circumflex",
00133   "dieresis", "dotaccent", "grave", "hungarumlaut",
00134   "macron", "ogonek", "ring", "tilde", "commaaccent", 
00135   "slash",
00136 
00137   /* The following entries are not accent nor something
00138    * but PS font may have those "small" version...
00139    */
00140   "ampersand", "exclam", "exclamdown",
00141   "question","questiondown",
00142   NULL
00143 };
00144 
00145 static int
00146 skip_capital (char **p, char *endptr)
00147 {
00148   long slen = 0, len;
00149 
00150   len = (long) (endptr - (*p));
00151 
00152   if (len >= 2 &&
00153       ((**p == 'A' && *(*p+1) == 'E') ||
00154        (**p == 'O' && *(*p+1) == 'E'))) {
00155     *p  += 2;
00156     slen = 2;
00157   } else if (len >= 3 &&
00158             **p     == 'E' &&
00159             *(*p+1) == 't' &&
00160             *(*p+2) == 'h') {
00161     *p  += 3;
00162     slen = 3;
00163   } else if (len >= 5 &&
00164             **p     == 'T' &&
00165             *(*p+1) == 'h' &&
00166             *(*p+2) == 'o' &&
00167             *(*p+3) == 'r' &&
00168             *(*p+4) == 'n') {
00169     *p  += 5;
00170     slen = 5;
00171   } else if (len >= 1 &&
00172             **p >= 'A' && **p <= 'Z') {
00173     *p  += 1;
00174     slen = 1;
00175   }
00176 
00177   return slen;
00178 }
00179 
00180 static int
00181 skip_modifier (char **p, char *endptr)
00182 {
00183   long slen = 0, len;
00184   int  i;
00185 
00186   len = (long) (endptr - (*p));
00187 
00188   for (i = 0; modifiers[i] != NULL; i++) {
00189     if ((len >= (long)strlen(modifiers[i]) &&
00190         !memcmp(*p, modifiers[i], len))) {
00191       slen = strlen(modifiers[i]);
00192       *p  += slen;
00193       break;
00194     }
00195   }
00196 
00197   return slen;
00198 }
00199 
00200 static int
00201 is_smallcap (const char *glyphname)
00202 {
00203   long  len, slen;
00204   char *p, *endptr;
00205 
00206   if (!glyphname)
00207     return 0;
00208 
00209   p   = (char *) glyphname;
00210   len = strlen(glyphname);
00211   if (len < 6 ||
00212       strcmp(p + len - 5, "small"))
00213     return 0;
00214 
00215   endptr = p + len - 5;
00216 
00217   len -= 5;
00218   slen = skip_modifier(&p, endptr);
00219   if (slen == len)
00220     return 1;  /* Acutesmall, Gravesmall, etc */
00221   else if (slen > 0) { /* ??? */
00222     return 0;
00223   }
00224 
00225   len -= skip_capital(&p, endptr);
00226   if (len == 0) {
00227     return 1;  /* Asmall, AEsmall, etc */
00228   }
00229 
00230   while (len > 0) { /* allow multiple accent */
00231     slen = skip_modifier(&p, endptr);
00232     if (slen == 0)
00233       return 0;
00234     len -= slen;
00235   }
00236 
00237   return 1;
00238 }
00239 
00240 #define SUFFIX_LIST_MAX  16
00241 #define AGL_VAR_SMCP_IDX 0
00242 static struct {
00243   const char   *key;
00244   const char   *otl_tag;
00245   const char   *suffixes[SUFFIX_LIST_MAX];
00246 } var_list[] = {
00247   {"small"       , "smcp", {"sc", NULL}},
00248   {"swash"       , "swsh", {NULL}},
00249   {"superior"    , "sups", {NULL}},
00250   {"inferior"    , "sinf", {NULL}},
00251   {"numerator"   , "numr", {NULL}},
00252   {"denominator" , "dnom", {NULL}},
00253   {"oldstyle"    , "onum", {NULL}},
00254 
00255   /* The following only used by TeX, there are no
00256    * corresponding OTL feat. tag.
00257    */
00258   {"display" , NULL, {NULL}},
00259   {"text"    , NULL, {NULL}},
00260   {"big"     , NULL, {NULL}},
00261   {"bigg"    , NULL, {NULL}},
00262   {"Big"     , NULL, {NULL}},
00263   {"Bigg"    , NULL, {NULL}},
00264   {NULL, NULL, {NULL}}
00265 };
00266 
00267 const char *
00268 agl_suffix_to_otltag (const char *suffix)
00269 {
00270   int i, j;
00271   
00272   for (i = 0; var_list[i].key; i++) {
00273     for (j = 0; var_list[i].suffixes[j]; j++) {
00274       if (!strcmp(suffix, var_list[i].suffixes[j]))
00275         return var_list[i].otl_tag; 
00276     }
00277     if (!strcmp(suffix, var_list[i].key))
00278       return var_list[i].otl_tag;
00279     if (var_list[i].otl_tag &&
00280        !strcmp(suffix, var_list[i].otl_tag))
00281       return var_list[i].otl_tag;
00282   }
00283   
00284   return NULL;
00285 }
00286 
00287 static int
00288 agl_guess_name (const char *glyphname)
00289 {
00290   int i, len;
00291 
00292   if (is_smallcap(glyphname))
00293     return AGL_VAR_SMCP_IDX;
00294 
00295   len = strlen(glyphname);
00296   for (i = 1; var_list[i].key != NULL; i++) {
00297     if (len > (int)strlen(var_list[i].key) &&
00298        !strcmp(glyphname+len-strlen(var_list[i].key), var_list[i].key)
00299        ) {
00300       return i;
00301     }
00302   }
00303 
00304   return -1;
00305 }
00306 
00307 static agl_name *
00308 agl_normalized_name (char *glyphname)
00309 {
00310   agl_name *agln;
00311   char     *suffix;
00312   int       i, n;
00313 
00314   if (!glyphname)
00315     return NULL;
00316 
00317   agln   = agl_new_name();
00318   suffix = strchr(glyphname, '.');
00319   if (suffix) {
00320     n = strlen(glyphname) - strlen(suffix);
00321     if (suffix[1] != '\0') {
00322       agln->suffix = NEW(strlen(suffix), char);
00323       strcpy(agln->suffix, suffix+1);
00324     }
00325     agln->name    = NEW(n+1, char);
00326     memcpy(agln->name, glyphname, n);
00327     agln->name[n] = '\0';
00328   } else if (is_smallcap(glyphname)) {
00329     n = strlen(glyphname) - 5;
00330     agln->suffix = NEW(3, char);
00331     strcpy(agln->suffix, "sc");
00332     agln->name   = NEW(n+1, char);
00333     for (i = 0; i < n; i++) {
00334       agln->name[i] = isupper(glyphname[i]) ?
00335        (glyphname[i] + 32) : glyphname[i];
00336     }
00337     agln->name[n] = '\0';
00338   } else {
00339     int var_idx;
00340 
00341 #define SET_STRING(p,s) do {\
00342   (p) = NEW(strlen((s))+1, char);\
00343   strcpy((p),(s));\
00344 } while (0)
00345     var_idx = agl_guess_name(glyphname);
00346     if (var_idx < 0 ||
00347         !var_list[var_idx].key) {
00348         n = strlen(glyphname);
00349     } else {
00350         n = strlen(glyphname) - strlen(var_list[var_idx].key);
00351         if (var_list[var_idx].suffixes[0])
00352             SET_STRING(agln->suffix, var_list[var_idx].suffixes[0]);
00353         else {
00354             SET_STRING(agln->suffix, var_list[var_idx].key);
00355         }
00356     }
00357     agln->name    = NEW(n+1, char);
00358     memcpy(agln->name, glyphname, n);
00359     agln->name[n] = '\0';
00360   }
00361   
00362   return agln;
00363 }
00364 
00365 static struct ht_table aglmap;
00366 
00367 static void CDECL
00368 hval_free (void *hval)
00369 {
00370   agl_release_name((struct agl_name *) hval);
00371 }
00372 
00373 void
00374 agl_init_map (void)
00375 {
00376   ht_init_table(&aglmap, hval_free);
00377   agl_load_listfile(AGL_EXTRA_LISTFILE, 0);
00378   if (agl_load_listfile(AGL_PREDEF_LISTFILE, 1) < 0) {
00379     WARN("Failed to load AGL file \"%s\"...", AGL_PREDEF_LISTFILE);
00380   }
00381   if (agl_load_listfile(AGL_DEFAULT_LISTFILE, 0) < 0) {
00382     WARN("Failed to load AGL file \"%s\"...", AGL_DEFAULT_LISTFILE);
00383   }
00384 }
00385 
00386 void
00387 agl_close_map (void)
00388 {
00389   ht_clear_table(&aglmap);
00390 }
00391 
00392 #define WBUF_SIZE 1024
00393 
00394 int
00395 agl_load_listfile (const char *filename, int is_predef)
00396 {
00397   int   count = 0;
00398   char *p, *endptr, *nextptr;
00399   char  wbuf[WBUF_SIZE];
00400   FILE *fp;
00401 
00402   if (!filename)
00403     return  -1;
00404 
00405   fp = DPXFOPEN(filename, DPX_RES_TYPE_AGL);
00406   if (!fp) {
00407     return -1;
00408   }
00409 
00410   if (verbose)
00411     MESG("<AGL:%s", filename);
00412 
00413   while ((p = mfgets(wbuf, WBUF_SIZE, fp)) != NULL) {
00414     agl_name *agln, *duplicate;
00415     char     *name;
00416     int       n_unicodes, i;
00417     long      unicodes[AGL_MAX_UNICODES];
00418 
00419     endptr = p + strlen(p);
00420     skip_white(&p, endptr);
00421 
00422     /* Need table version check. */
00423     if (!p || p[0] == '#' || p >= endptr)
00424       continue;
00425     nextptr = strchr(p, ';');
00426     if (!nextptr || nextptr == p)
00427       continue;
00428 
00429     name = parse_ident(&p, nextptr);
00430 
00431     skip_white(&p, endptr);
00432     if (!name || p[0] != ';') {
00433       WARN("Invalid AGL entry: %s", wbuf);
00434       if (name)
00435         RELEASE(name);
00436       continue;
00437     }
00438 
00439     p++;
00440     skip_white(&p, endptr);
00441 
00442     n_unicodes = 0;
00443     while (p < endptr &&
00444            ((p[0]  >= '0' && p[0] <= '9') ||
00445             (p[0]  >= 'A' && p[0] <= 'F'))
00446           ) {
00447 
00448       if (n_unicodes >= AGL_MAX_UNICODES) {
00449         WARN("Too many Unicode values");
00450         break;
00451       }
00452       unicodes[n_unicodes++] = strtol(p, &nextptr, 16);
00453 
00454       p = nextptr;
00455       skip_white(&p, endptr);
00456     }
00457 
00458     if (n_unicodes == 0) {
00459       WARN("AGL entry ignored (no mapping): %s", wbuf);
00460       RELEASE(name);
00461       continue;
00462     }
00463 
00464     agln = agl_normalized_name(name);
00465     agln->is_predef = is_predef;
00466     agln->n_components = n_unicodes;
00467     for (i = 0; i < n_unicodes; i++) {
00468       agln->unicodes[i] = unicodes[i];
00469     }
00470 
00471     duplicate = ht_lookup_table(&aglmap, name, strlen(name));
00472     if (!duplicate)
00473       ht_append_table(&aglmap, name, strlen(name), agln);
00474     else {
00475       while (duplicate->alternate)
00476         duplicate = duplicate->alternate;
00477       duplicate->alternate = agln;
00478     }
00479 
00480     if (verbose > 3) {
00481       if (agln->suffix)
00482         MESG("agl: %s [%s.%s] -->", name, agln->name, agln->suffix);
00483       else
00484         MESG("agl: %s [%s] -->", name, agln->name);
00485       for (i = 0; i < agln->n_components; i++) {
00486         if (agln->unicodes[i] > 0xffff) {
00487           MESG(" U+%06X", agln->unicodes[i]);
00488         } else {
00489           MESG(" U+%04X", agln->unicodes[i]);
00490         }
00491       }
00492       MESG("\n");
00493     }
00494 
00495     RELEASE(name);
00496     count++;
00497   }
00498   DPXFCLOSE(fp);
00499 
00500   if (verbose)
00501     MESG(">");
00502 
00503   return count;
00504 }
00505 
00506 agl_name *
00507 agl_lookup_list (const char *glyphname)
00508 {
00509   agl_name *agln;
00510 
00511   if (!glyphname)
00512     return NULL;
00513 
00514   agln = ht_lookup_table(&aglmap, glyphname, strlen(glyphname));
00515 
00516   return agln;
00517 }
00518 
00519 int
00520 agl_name_is_unicode (const char *glyphname)
00521 {
00522   char c, *suffix;
00523   int  i, len;
00524 
00525   if (!glyphname)
00526     return 0;
00527 
00528   suffix = strchr(glyphname, '.');
00529   len    = (int) (suffix ? suffix - glyphname : (int)strlen(glyphname));
00530   /*
00531    * uni02ac is invalid glyph name and mapped to th empty string.
00532    */
00533   if (len >= 7 && (len - 3) % 4 == 0 &&
00534       !strncmp(glyphname, "uni", 3)) {
00535     c = glyphname[3];
00536     /*
00537      * Check if the 4th character is uppercase hexadecimal digit.
00538      * "union" should not be treated as Unicode glyph name.
00539      */
00540     if (isdigit(c) || (c >= 'A' && c <= 'F'))
00541       return 1;
00542     else
00543       return 0;
00544   } else if (len <= 7 && len >= 5 &&
00545             glyphname[0] == 'u') {
00546     for (i = 1; i < len - 1; i++) {
00547       c = glyphname[i];
00548       if (!isdigit(c) && (c < 'A' || c > 'F'))
00549        return 0;
00550     }
00551     return 1;
00552   }
00553 
00554   return 0;
00555 }
00556 
00557 long
00558 agl_name_convert_unicode (const char *glyphname)
00559 {
00560   long  ucv = -1;
00561   char *p;
00562 
00563   if (!agl_name_is_unicode(glyphname))
00564     return -1;
00565 
00566   if (strlen(glyphname) > 7 && *(glyphname+7) != '.') {
00567     WARN("Mapping to multiple Unicode characters not supported.");
00568     return -1;
00569   }
00570 
00571   if (glyphname[1] == 'n')
00572     p = (char *) (glyphname + 3);
00573   else
00574     p = (char *) (glyphname + 1);
00575   ucv = 0;
00576   while (*p != '\0' && *p != '.') {
00577     if (!isdigit(*p) && (*p < 'A' || *p > 'F')) {
00578       WARN("Invalid char %c in Unicode glyph name %s.", *p, glyphname);
00579       return -1;
00580     }
00581     ucv <<= 4;
00582     ucv += isdigit(*p) ? *p - '0' : *p - 'A' + 10;
00583     p++;
00584   }
00585 
00586   if (!UC_is_valid(ucv)) {
00587     if (ucv < 0x10000) {
00588       WARN("Invalid Unicode code value U+%04X.", ucv);
00589     } else {
00590       WARN("Invalid Unicode code value U+%06X.", ucv);
00591     }
00592     ucv = -1;
00593   }
00594 
00595   return ucv;
00596 }
00597 
00598 
00599 
00600 static long
00601 xtol (const char *start, int len)
00602 {
00603   long v = 0;
00604 
00605   while (len-- > 0) {
00606     v <<= 4;
00607     if (isdigit(*start)) {
00608       v += *start - '0';
00609     } else if (*start >= 'A' && *start <= 'F') {
00610       v += *start - 'A' + 10;
00611     } else {
00612       return -1;
00613     }
00614     start++;
00615   }
00616 
00617   return v;
00618 }
00619 
00620 #define IS_PUA(u) (((u) >= 0x00E000L && (u) <= 0x00F8FFL) || \
00621   ((u) >= 0x0F0000L && (u) <= 0x0FFFFDL) || \
00622   ((u) >= 0x100000L && (u) <= 0x10FFFDL) \
00623 )
00624 
00625 static long
00626 put_unicode_glyph (const char *name,
00627                  unsigned char **dstpp, unsigned char *limptr)
00628 {
00629   char *p;
00630   long  len = 0, ucv;
00631 
00632   p   = (char *) name;
00633   ucv = 0;
00634 
00635   if (p[1] != 'n') {
00636     p   += 1;
00637     ucv  = xtol(p, strlen(p));
00638     len += UC_sput_UTF16BE (ucv, dstpp, limptr);
00639   } else {
00640     p += 3;
00641     while (*p != '\0') {
00642       ucv  = xtol(p, 4);
00643       len += UC_sput_UTF16BE (ucv, dstpp, limptr);
00644       p   += 4;
00645     }
00646   }
00647 
00648   return len;
00649 }
00650 
00651 long
00652 agl_sput_UTF16BE (const char *glyphstr,
00653                 unsigned char **dstpp, unsigned char *limptr,
00654                 int *fail_count)
00655 {
00656   long  len   = 0;
00657   int   count = 0;
00658   char *p, *endptr;
00659 
00660   ASSERT(glyphstr && dstpp);
00661 
00662   p      = (char *) glyphstr;
00663   endptr = strchr(p, '.');
00664   if (!endptr)
00665     endptr = p + strlen(p);
00666 
00667   while (p < endptr) {
00668     char     *name, *delim;
00669     long      sub_len;
00670     int       i;
00671     agl_name *agln0, *agln1 = NULL;
00672 
00673     delim = strchr(p, '_');
00674     if (delim == p) {
00675       /*
00676        * Glyph names starting with a underscore or two subsequent
00677        * underscore in glyph name not allowed?
00678        */
00679       WARN("Invalid glyph name component in \"%s\".", glyphstr);
00680       count++;
00681       if (fail_count)
00682        *fail_count = count;
00683       return len; /* Cannot continue */
00684     } else if (!delim || delim > endptr) {
00685       delim = endptr;
00686     }
00687     sub_len = (long) (delim - p);
00688 
00689     name = NEW(sub_len+1, char);
00690     memcpy(name, p, sub_len);
00691     name[sub_len] = '\0';
00692 
00693     if (agl_name_is_unicode(name)) {
00694       sub_len = put_unicode_glyph(name, dstpp, limptr);
00695       if (sub_len > 0)
00696        len += sub_len;
00697       else {
00698        count++;
00699       }
00700     } else {
00701       agln1 = agl_lookup_list(name);
00702       if (!agln1 || (agln1->n_components == 1 &&
00703                    IS_PUA(agln1->unicodes[0]))) {
00704        agln0 = agl_normalized_name(name);
00705        if (agln0) {
00706          if (verbose > 1 && agln0->suffix) {
00707            WARN("agl: fix %s --> %s.%s",
00708                name, agln0->name, agln0->suffix);
00709          }
00710          agln1 = agl_lookup_list(agln0->name);
00711          agl_release_name(agln0);
00712        }
00713       }
00714       if (agln1) {
00715        for (i = 0; i < agln1->n_components; i++) {
00716          len += UC_sput_UTF16BE (agln1->unicodes[i], dstpp, limptr);
00717        }
00718       } else {
00719        if (verbose) {
00720          WARN("No Unicode mapping for glyph name \"%s\" found.", name);
00721        }
00722        count++;
00723       }
00724     }
00725     RELEASE(name);
00726     p = delim + 1;
00727   }
00728 
00729   if (fail_count)
00730     *fail_count = count;
00731   return len;
00732 }
00733 
00734 int
00735 agl_get_unicodes (const char *glyphstr,
00736                 long *unicodes, int max_unicodes)
00737 {
00738   int   count = 0;
00739   char *p, *endptr;
00740 
00741   p      = (char *) glyphstr;
00742   endptr = strchr(p, '.');
00743   if (!endptr)
00744     endptr = p + strlen(p);
00745 
00746   while (p < endptr) {
00747     char     *name, *delim;
00748     long      sub_len;
00749     int       i;
00750     agl_name *agln0, *agln1 = NULL;
00751 
00752     delim = strchr(p, '_');
00753     if (delim == p) {
00754       /*
00755        * Glyph names starting with a underscore or two subsequent
00756        * underscore in glyph name not allowed?
00757        */
00758       WARN("Invalid glyph name component in \"%s\".", glyphstr);
00759       return -1; /* Cannot continue */
00760     } else if (!delim || delim > endptr) {
00761       delim = endptr;
00762     }
00763     sub_len = (long) (delim - p);
00764 
00765     name = NEW(sub_len+1, char);
00766     memcpy(name, p, sub_len);
00767     name[sub_len] = '\0';
00768 
00769     if (agl_name_is_unicode(name)) {
00770       p  = name;
00771       if (p[1] != 'n') { /* uXXXXXXXX */
00772        if (count >= max_unicodes) {
00773          RELEASE(name);
00774          return -1;
00775        }
00776        p++;
00777        unicodes[count++] = xtol(p, strlen(p));
00778       } else {
00779        p += 3;
00780        while (*p != '\0') {
00781          if (count >= max_unicodes) {
00782            RELEASE(name);
00783            return -1;
00784          }
00785          unicodes[count++] = xtol(p, 4);
00786          p += 4;
00787        }
00788       }
00789     } else {
00790       agln1 = agl_lookup_list(name);
00791       if (!agln1 || (agln1->n_components == 1 &&
00792                    IS_PUA(agln1->unicodes[0]))) {
00793        agln0 = agl_normalized_name(name);
00794        if (agln0) {
00795          if (verbose > 1 && agln0->suffix) {
00796            WARN("agl: fix %s --> %s.%s",
00797                name, agln0->name, agln0->suffix);
00798          }
00799          agln1 = agl_lookup_list(agln0->name);
00800          agl_release_name(agln0);
00801        }
00802       }
00803       if (agln1) {
00804        if (count + agln1->n_components > max_unicodes) {
00805          RELEASE(name);
00806          return -1;
00807        }
00808        for (i = 0; i < agln1->n_components; i++) {
00809          unicodes[count++] = agln1->unicodes[i];
00810        }
00811       } else {
00812        if (verbose > 1)
00813          WARN("No Unicode mapping for glyph name \"%s\" found.", name);
00814        RELEASE(name);
00815        return -1;
00816       }
00817     }
00818     RELEASE(name);
00819     p = delim + 1;
00820   }
00821 
00822   return count;
00823 }