/*
- * $XFree86$
+ * $RCSId: xc/lib/fontconfig/fc-lang/fc-lang.c,v 1.3 2002/08/22 07:36:43 keithp Exp $
*
- * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ * Copyright © 2002 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
*/
#include "fcint.h"
+#include "fccharset.c"
+#include "fcstr.c"
/*
* fc-lang
*
* Read a set of language orthographies and build C declarations for
* charsets which can then be used to identify which languages are
- * supported by a given font. Note that it would be nice if
- * this could be done while compiling the library, but this
- * code uses a number of routines from the library. It's
- * expediant to just ship the pre-built version along with the
- * source orthographies.
+ * supported by a given font. Note that this uses some utilities
+ * from the fontconfig library, so the necessary file is simply
+ * included in this compilation. A couple of extra utility
+ * functions are also needed in slightly modified form
*/
+void
+FcMemAlloc (int kind, int size)
+{
+}
+
+void
+FcMemFree (int kind, int size)
+{
+}
+
+FcChar8 *
+FcConfigHome (void)
+{
+ return getenv ("HOME");
+}
+
static void
fatal (char *file, int lineno, char *msg)
{
return line;
}
+char *dir = 0;
+
+static FILE *
+scanopen (char *file)
+{
+ FILE *f;
+
+ f = fopen (file, "r");
+ if (!f && dir)
+ {
+ char path[1024];
+
+ strcpy (path, dir);
+ strcat (path, "/");
+ strcat (path, file);
+ f = fopen (path, "r");
+ }
+ return f;
+}
+
/*
* build a single charset from a source file
*
end = strlen (file);
if (file[end-1] == '\n')
file[end-1] = '\0';
- f = fopen (file, "r");
+ f = scanopen (file);
if (!f)
fatal (file, 0, "can't open");
c = scan (f, file);
while ((c = *name++))
{
- if (isupper (c))
- c = tolower (c);
+ if (isupper ((int) (unsigned char) c))
+ c = tolower ((int) (unsigned char) c);
if (c == '_')
c = '-';
if (c == ' ')
return lang;
}
+static int compare (const void *a, const void *b)
+{
+ const FcChar8 *const *as = a, *const *bs = b;
+ return FcStrCmpIgnoreCase (*as, *bs);
+}
+
+#define MAX_LANG 1024
+#define MAX_LANG_SET_MAP ((MAX_LANG + 31) / 32)
+
+#define BitSet(map, id) ((map)[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
+#define BitGet(map, id) ((map)[(id)>>5] >> ((id) & 0x1f)) & 1)
+
int
main (int argc, char **argv)
{
- FcCharSet *sets[1024];
- char *names[1024];
+ char *files[MAX_LANG];
+ FcCharSet *sets[MAX_LANG];
+ int duplicate[MAX_LANG];
+ int country[MAX_LANG];
+ char *names[MAX_LANG];
+ char *langs[MAX_LANG];
FILE *f;
+ int ncountry = 0;
int i = 0;
FcCharLeaf **leaves, **sleaves;
int total_leaves = 0;
int l, sl, tl;
+ int c;
char line[1024];
+ FcChar32 map[MAX_LANG_SET_MAP];
+ int num_lang_set_map;
+ int setRangeStart[26];
+ int setRangeEnd[26];
+ FcChar8 setRangeChar;
while (*++argv)
{
- f = fopen (*argv, "r");
+ if (!strcmp (*argv, "-d"))
+ {
+ dir = *++argv;
+ continue;
+ }
+ if (i == MAX_LANG)
+ fatal (*argv, 0, "Too many languages");
+ files[i++] = *argv;
+ }
+ files[i] = 0;
+ qsort (files, i, sizeof (char *), compare);
+ i = 0;
+ while (files[i])
+ {
+ f = scanopen (files[i]);
if (!f)
- fatal (*argv, 0, strerror (errno));
- sets[i] = scan (f, *argv);
- names[i] = get_name (*argv);
+ fatal (files[i], 0, strerror (errno));
+ sets[i] = scan (f, files[i]);
+ names[i] = get_name (files[i]);
+ langs[i] = get_lang(names[i]);
+ if (strchr (langs[i], '-'))
+ country[ncountry++] = i;
+
total_leaves += sets[i]->num;
i++;
fclose (f);
}
printf ("};\n\n");
printf ("#define L(n) ((FcCharLeaf *) &leaves[n])\n\n");
+
+ /*
+ * Find duplicate charsets
+ */
+ duplicate[0] = -1;
+ for (i = 1; sets[i]; i++)
+ {
+ int j;
+
+ duplicate[i] = -1;
+ for (j = 0; j < i; j++)
+ if (sets[j] == sets[i])
+ {
+ duplicate[i] = j;
+ break;
+ }
+ }
+
+ /*
+ * Find ranges for each letter for faster searching
+ */
+ setRangeChar = 'a';
+ for (i = 0; sets[i]; i++)
+ {
+ char c = names[i][0];
+
+ while (setRangeChar <= c && c <= 'z')
+ setRangeStart[setRangeChar++ - 'a'] = i;
+ }
+ for (setRangeChar = 'a'; setRangeChar < 'z'; setRangeChar++)
+ setRangeEnd[setRangeChar - 'a'] = setRangeStart[setRangeChar+1-'a'] - 1;
+ setRangeEnd[setRangeChar - 'a'] = i - 1;
+
/*
* Dump arrays
*/
{
int n;
+ if (duplicate[i] >= 0)
+ continue;
printf ("static const FcCharLeaf *leaves_%s[%d] = {\n",
names[i], sets[i]->num);
for (n = 0; n < sets[i]->num; n++)
printf ("};\n\n");
}
printf ("#undef L\n\n");
+
/*
* Dump sets
*/
+
printf ("static const FcLangCharSet fcLangCharSets[] = {\n");
for (i = 0; sets[i]; i++)
{
+ int j = duplicate[i];
+
+ if (j < 0)
+ j = i;
printf (" { (FcChar8 *) \"%s\",\n"
- " { 1, FcTrue, %d, "
+ " { FC_REF_CONSTANT, %d, "
"(FcCharLeaf **) leaves_%s, "
"(FcChar16 *) numbers_%s } },\n",
- get_lang(names[i]),
- sets[i]->num, names[i], names[i]);
+ langs[i],
+ sets[j]->num, names[j], names[j]);
+ }
+ printf ("};\n\n");
+ printf ("#define NUM_LANG_CHAR_SET %d\n", i);
+ num_lang_set_map = (i + 31) / 32;
+ printf ("#define NUM_LANG_SET_MAP %d\n", num_lang_set_map);
+ /*
+ * Dump indices with country codes
+ */
+ if (ncountry)
+ {
+ int ncountry_ent = 0;
+ printf ("\n");
+ printf ("static const FcChar32 fcLangCountrySets[][NUM_LANG_SET_MAP] = {\n");
+ for (c = 0; c < ncountry; c++)
+ {
+ i = country[c];
+ if (i >= 0)
+ {
+ int l = strchr (langs[i], '-') - langs[i];
+ int d, k;
+
+ for (k = 0; k < num_lang_set_map; k++)
+ map[k] = 0;
+
+ BitSet (map, i);
+ for (d = c + 1; d < ncountry; d++)
+ {
+ int j = country[d];
+ if (j >= 0 && !strncmp (langs[j], langs[i], l))
+ {
+ BitSet(map, j);
+ country[d] = -1;
+ }
+ }
+ printf (" {");
+ for (k = 0; k < num_lang_set_map; k++)
+ printf (" 0x%08x,", map[k]);
+ printf (" }, /* %*.*s */\n",
+ l, l, langs[i]);
+ ++ncountry_ent;
+ }
+ }
+ printf ("};\n\n");
+ printf ("#define NUM_COUNTRY_SET %d\n", ncountry_ent);
+ }
+
+
+ /*
+ * Dump sets start/finish for the fastpath
+ */
+ printf ("static const FcLangCharSetRange fcLangCharSetRanges[] = {\n");
+ for (setRangeChar = 'a'; setRangeChar <= 'z' ; setRangeChar++)
+ {
+ printf (" { %d, %d }, /* %c */\n",
+ setRangeStart[setRangeChar - 'a'],
+ setRangeEnd[setRangeChar - 'a'], setRangeChar);
}
printf ("};\n\n");
+
while (fgets (line, sizeof (line), stdin))
fputs (line, stdout);