| /* |
| * fontconfig/fc-glyphname/fc-glyphname.c |
| * |
| * Copyright © 2003 Keith Packard |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and its |
| * documentation for any purpose is hereby granted without fee, provided that |
| * the above copyright notice appear in all copies and that both that |
| * copyright notice and this permission notice appear in supporting |
| * documentation, and that the name of the author(s) not be used in |
| * advertising or publicity pertaining to distribution of the software without |
| * specific, written prior permission. The authors make no |
| * representations about the suitability of this software for any purpose. It |
| * is provided "as is" without express or implied warranty. |
| * |
| * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include "fcint.h" |
| |
| static int |
| rawindex (const FcGlyphName *gn); |
| |
| static void |
| scan (FILE *f, char *filename); |
| |
| static int |
| isprime (int i); |
| |
| static void |
| find_hash (void); |
| |
| static FcChar32 |
| FcHashGlyphName (const FcChar8 *name); |
| |
| static void |
| insert (FcGlyphName *gn, FcGlyphName **table, FcChar32 h); |
| |
| static void |
| dump (FcGlyphName * const *table, const char *name); |
| |
| static FcGlyphName * |
| FcAllocGlyphName (FcChar32 ucs, FcChar8 *name) |
| { |
| FcGlyphName *gn; |
| |
| gn = malloc (sizeof (FcGlyphName) + strlen ((char *) name)); |
| if (!gn) |
| return 0; |
| gn->ucs = ucs; |
| strcpy ((char *) gn->name, (char *) name); |
| return gn; |
| } |
| |
| static void |
| fatal (const char *file, int lineno, const char *msg) |
| { |
| if (lineno) |
| fprintf (stderr, "%s:%d: %s\n", file, lineno, msg); |
| else |
| fprintf (stderr, "%s: %s\n", file, msg); |
| |
| exit (1); |
| } |
| |
| #define MAX_GLYPHFILE 256 |
| #define MAX_GLYPHNAME 10240 |
| #define MAX_NAMELEN 1024 |
| |
| static FcGlyphName *raw[MAX_GLYPHNAME]; |
| static int nraw; |
| static int max_name_len; |
| static FcGlyphName *name_to_ucs[MAX_GLYPHNAME*2]; |
| static FcGlyphName *ucs_to_name[MAX_GLYPHNAME*2]; |
| static unsigned int hash, rehash; |
| |
| static int |
| rawindex (const FcGlyphName *gn) |
| { |
| int i; |
| |
| for (i = 0; i < nraw; i++) |
| if (raw[i] == gn) |
| return i; |
| return -1; |
| } |
| |
| static void |
| scan (FILE *f, char *filename) |
| { |
| char buf[MAX_NAMELEN]; |
| char name[MAX_NAMELEN]; |
| unsigned long ucs; |
| FcGlyphName *gn; |
| int lineno = 0; |
| int len; |
| |
| while (fgets (buf, sizeof (buf), f)) |
| { |
| lineno++; |
| if (sscanf (buf, "%[^;];%lx\n", name, &ucs) != 2) |
| continue; |
| gn = FcAllocGlyphName ((FcChar32) ucs, (FcChar8 *) name); |
| if (!gn) |
| fatal (filename, lineno, "out of memory"); |
| len = strlen (name); |
| if (len > max_name_len) |
| max_name_len = len; |
| raw[nraw++] = gn; |
| } |
| } |
| |
| static int compare_string (const void *a, const void *b) |
| { |
| const char *const *as = a, *const *bs = b; |
| return strcmp (*as, *bs); |
| } |
| |
| static int compare_glyphname (const void *a, const void *b) |
| { |
| const FcGlyphName *const *ag = a, *const *bg = b; |
| |
| return strcmp ((char *) (*ag)->name, (char *) (*bg)->name); |
| } |
| |
| static int |
| isqrt (int a) |
| { |
| int l, h, m; |
| |
| l = 2; |
| h = a/2; |
| while ((h-l) > 1) |
| { |
| m = (h+l) >> 1; |
| if (m * m < a) |
| l = m; |
| else |
| h = m; |
| } |
| return h; |
| } |
| |
| static int |
| isprime (int i) |
| { |
| int l, t; |
| |
| if (i < 2) |
| return FcFalse; |
| if ((i & 1) == 0) |
| { |
| if (i == 2) |
| return FcTrue; |
| return FcFalse; |
| } |
| l = isqrt (i) + 1; |
| for (t = 3; t <= l; t += 2) |
| if (i % t == 0) |
| return 0; |
| return 1; |
| } |
| |
| /* |
| * Find a prime pair that leaves at least 25% of the hash table empty |
| */ |
| |
| static void |
| find_hash (void) |
| { |
| int h; |
| |
| h = nraw + nraw / 4; |
| if ((h & 1) == 0) |
| h++; |
| while (!isprime(h-2) || !isprime(h)) |
| h += 2; |
| hash = h; |
| rehash = h-2; |
| } |
| |
| static FcChar32 |
| FcHashGlyphName (const FcChar8 *name) |
| { |
| FcChar32 h = 0; |
| FcChar8 c; |
| |
| while ((c = *name++)) |
| { |
| h = ((h << 1) | (h >> 31)) ^ c; |
| } |
| return h; |
| } |
| |
| static void |
| insert (FcGlyphName *gn, FcGlyphName **table, FcChar32 h) |
| { |
| unsigned int i, r = 0; |
| |
| i = (int) (h % hash); |
| while (table[i]) |
| { |
| if (!r) r = (h % rehash + 1); |
| i += r; |
| if (i >= hash) |
| i -= hash; |
| } |
| table[i] = gn; |
| } |
| |
| static void |
| dump (FcGlyphName * const *table, const char *name) |
| { |
| unsigned int i; |
| |
| printf ("static const FcGlyphId %s[%d] = {\n", name, hash); |
| |
| for (i = 0; i < hash; i++) |
| if (table[i]) |
| printf (" %d,\n", rawindex(table[i])); |
| else |
| printf (" -1,\n"); |
| |
| printf ("};\n"); |
| } |
| |
| int |
| main (int argc FC_UNUSED, char **argv) |
| { |
| char *files[MAX_GLYPHFILE + 1]; |
| char line[1024]; |
| FILE *f; |
| int i; |
| const char *type; |
| |
| i = 0; |
| while (argv[i+1]) |
| { |
| if (i == MAX_GLYPHFILE) |
| fatal (*argv, 0, "Too many glyphname files"); |
| files[i] = argv[i+1]; |
| i++; |
| } |
| files[i] = 0; |
| qsort (files, i, sizeof (char *), compare_string); |
| for (i = 0; files[i]; i++) |
| { |
| f = fopen (files[i], "r"); |
| if (!f) |
| fatal (files[i], 0, strerror (errno)); |
| scan (f, files[i]); |
| fclose (f); |
| } |
| qsort (raw, nraw, sizeof (FcGlyphName *), compare_glyphname); |
| |
| find_hash (); |
| |
| for (i = 0; i < nraw; i++) |
| { |
| insert (raw[i], name_to_ucs, FcHashGlyphName (raw[i]->name)); |
| insert (raw[i], ucs_to_name, raw[i]->ucs); |
| } |
| |
| /* |
| * Scan the input until the marker is found |
| */ |
| |
| while (fgets (line, sizeof (line), stdin)) |
| { |
| if (!strncmp (line, "@@@", 3)) |
| break; |
| fputs (line, stdout); |
| } |
| |
| printf ("/* %d glyphnames in %d entries, %d%% occupancy */\n\n", |
| nraw, hash, nraw * 100 / hash); |
| |
| printf ("#define FC_GLYPHNAME_HASH %u\n", hash); |
| printf ("#define FC_GLYPHNAME_REHASH %u\n", rehash); |
| printf ("#define FC_GLYPHNAME_MAXLEN %d\n\n", max_name_len); |
| if (nraw < 128) |
| type = "int8_t"; |
| else if (nraw < 32768) |
| type = "int16_t"; |
| else |
| type = "int32_t"; |
| |
| printf ("typedef %s FcGlyphId;\n\n", type); |
| |
| /* |
| * Dump out entries |
| */ |
| |
| printf ("static const struct { const FcChar32 ucs; const FcChar8 name[%d]; } _fc_glyph_names[%d] = {\n", |
| max_name_len + 1, nraw); |
| |
| for (i = 0; i < nraw; i++) |
| printf (" { 0x%lx, \"%s\" },\n", |
| (unsigned long) raw[i]->ucs, raw[i]->name); |
| |
| printf ("};\n"); |
| |
| /* |
| * Dump out name_to_ucs table |
| */ |
| |
| dump (name_to_ucs, "_fc_name_to_ucs"); |
| |
| /* |
| * Dump out ucs_to_name table |
| */ |
| dump (ucs_to_name, "_fc_ucs_to_name"); |
| |
| while (fgets (line, sizeof (line), stdin)) |
| fputs (line, stdout); |
| |
| fflush (stdout); |
| exit (ferror (stdout)); |
| } |