diff options
Diffstat (limited to 'pango/modules.c')
-rw-r--r-- | pango/modules.c | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/pango/modules.c b/pango/modules.c new file mode 100644 index 00000000..0016df1f --- /dev/null +++ b/pango/modules.c @@ -0,0 +1,409 @@ +/* Pango + * modules.c: + * + * Copyright (C) 1999 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include <gmodule.h> +#include <pango.h> + +#include "modules.h" +#include "utils.h" + +typedef struct _PangoMapInfo PangoMapInfo; +typedef struct _PangoEnginePair PangoEnginePair; + +struct _PangoMapInfo +{ + gchar *lang; + gchar *engine_type; + gchar *render_type; +}; + +struct _PangoEnginePair +{ + gchar *module; + PangoEngineInfo info; +}; + +GList *engines; + +static PangoMap *build_map (PangoMapInfo *info); +static void read_modules (void); +static guint map_info_hash (const PangoMapInfo *map); +static gboolean map_info_equal (const PangoMapInfo *map_a, + const PangoMapInfo *map_b); + +PangoMap * +_pango_find_map (gchar *lang, + gchar *engine_type, + gchar *render_type) +{ + PangoMapInfo map_info; + PangoMap *map; + + static GHashTable *map_hash = NULL; + + if (!map_hash) + map_hash = g_hash_table_new ((GHashFunc)map_info_hash, + (GCompareFunc)map_info_equal); + + map_info.lang = lang; + map_info.engine_type = engine_type; + map_info.render_type = render_type; + + map = g_hash_table_lookup (map_hash, &map_info); + if (!map) + { + PangoMapInfo *new_info = g_new (PangoMapInfo, 1); + *new_info = map_info; + + map = build_map (new_info); + g_hash_table_insert (map_hash, new_info, map); + } + + return map; +} + +PangoEngine * +_pango_load_engine (gchar *id) +{ + GList *tmp_list; + + read_modules(); + + tmp_list = engines; + while (tmp_list) + { + PangoEnginePair *pair = tmp_list->data; + tmp_list = tmp_list->next; + + if (!strcmp (pair->info.id, id)) + { + GModule *module; + PangoEngine *(*load) (const gchar *id); + PangoEngine *engine; + + module = g_module_open (pair->module, 0); + if (!module) + { + fprintf(stderr, "Cannot load module %s: %s\n", + pair->module, g_module_error()); + return NULL; + } + + g_module_symbol (module, "script_engine_load", (gpointer)&load); + if (!load) + { + fprintf(stderr, "cannot retrieve script_engine_load from %s: %s\n", + pair->module, g_module_error()); + g_module_close (module); + return NULL; + } + + engine = (*load) (id); + + return engine; + } + } + + return NULL; +} + + +static guint +map_info_hash (const PangoMapInfo *map) +{ + return g_str_hash (map->lang) | + g_str_hash (map->engine_type) | + g_str_hash (map->render_type); +} + +static gboolean +map_info_equal (const PangoMapInfo *map_a, const PangoMapInfo *map_b) +{ + return (strcmp (map_a->lang, map_b->lang) == 0 && + strcmp (map_a->engine_type, map_b->engine_type) == 0 && + strcmp (map_a->render_type, map_b->render_type) == 0); +} + +static char * +readline(FILE *file) +{ + static GString *bufstring = NULL; + int c; + + if (!bufstring) + bufstring = g_string_new (NULL); + else + g_string_truncate (bufstring, 0); + + while ((c = getc(file)) != EOF) + { + g_string_append_c (bufstring, c); + if (c == '\n') + break; + } + + if (bufstring->len == 0) + return NULL; + else + return g_strdup (bufstring->str); +} + +static char * +my_strdupn (char *p, gint n) +{ + gchar *result; + + if (n == 0) + return NULL; + + result = g_malloc (n + 1); + strncpy (result, p, n); + result[n] = '\0'; + + return result; +} + +static void +read_modules (void) +{ + FILE *module_file; + static gboolean init = FALSE; + char *line; + + if (init) + return; + else + init = TRUE; + + module_file = fopen ("pango.modules", "r"); + if (!module_file) + { + fprintf(stderr, "Cannot load module file!\n"); + return; /* FIXME: Error */ + } + + engines = NULL; + while ((line = readline (module_file))) + { + PangoEnginePair *pair = g_new (PangoEnginePair, 1); + PangoEngineRange *range; + GList *ranges; + GList *tmp_list; + char *p, *q; + int i; + int start; + int end; + + p = line; + q = line; + ranges = NULL; + + /* Break line into words on whitespace */ + i = 0; + while (1) + { + if (!*p || isspace(*p)) + { + switch (i) + { + case 0: + pair->module = my_strdupn (q, p-q); + break; + case 1: + pair->info.id = my_strdupn (q, p-q); + break; + case 2: + pair->info.engine_type = my_strdupn (q, p-q); + break; + case 3: + pair->info.render_type = my_strdupn (q, p-q); + break; + default: + range = g_new (PangoEngineRange, 1); + if (sscanf(q, "%d-%d:", &start, &end) != 2) + { + fprintf(stderr, "Error reading pango.modules"); + return; + } + q = strchr (q, ':'); + if (!q) + { + fprintf(stderr, "Error reading pango.modules"); + return; + } + q++; + range->start = start; + range->end = end; + range->langs = my_strdupn (q, p-q); + + ranges = g_list_prepend (ranges, range); + } + + i++; + + do + p++; + while (*p && isspace(*p)); + + if (!*p) + break; + + q = p; + } + else + p++; + } + + if (i<3) + { + fprintf(stderr, "Error reading pango.modules"); + return; + } + + ranges = g_list_reverse (ranges); + pair->info.n_ranges = g_list_length (ranges); + pair->info.ranges = g_new (PangoEngineRange, pair->info.n_ranges); + + tmp_list = ranges; + for (i=0; i<pair->info.n_ranges; i++) + { + pair->info.ranges[i] = *(PangoEngineRange *)tmp_list->data; + tmp_list = tmp_list->next; + } + + g_list_foreach (ranges, (GFunc)g_free, NULL); + g_list_free (ranges); + g_free (line); + + engines = g_list_prepend (engines, pair); + } + engines = g_list_reverse (engines); +} + +static void +set_entry (PangoMapEntry *entry, gboolean is_exact, PangoEngineInfo *info) +{ + if ((is_exact && !entry->is_exact) || + !entry->info) + { + entry->is_exact = is_exact; + entry->info = info; + } +} + +static PangoMap * +build_map (PangoMapInfo *info) +{ + GList *tmp_list; + int i, j; + PangoMap *map; + + read_modules(); + + map = g_new (PangoMap, 1); + for (i=0; i<256; i++) + { + map->submaps[i].is_leaf = TRUE; + map->submaps[i].d.entry.info = NULL; + map->submaps[i].d.entry.is_exact = FALSE; + } + + tmp_list = engines; + while (tmp_list) + { + PangoEnginePair *pair = tmp_list->data; + tmp_list = tmp_list->next; + + if (strcmp (pair->info.engine_type, info->engine_type) == 0 && + strcmp (pair->info.render_type, info->render_type) == 0) + { + int submap; + + for (i=0; i<pair->info.n_ranges; i++) + { + gchar **langs; + gboolean is_exact = FALSE; + + if (pair->info.ranges[i].langs) + { + langs = g_strsplit (pair->info.ranges[i].langs, ";", -1); + for (j=0; langs[j]; j++) + if (strcmp (langs[j], "*") == 0 || + strcmp (langs[j], info->lang) == 0) + { + is_exact = TRUE; + break; + } + g_strfreev (langs); + } + + for (submap = pair->info.ranges[i].start / 256; + submap <= pair->info.ranges[i].end / 256; + submap ++) + { + GUChar4 start; + GUChar4 end; + + if (submap == pair->info.ranges[i].start / 256) + start = pair->info.ranges[i].start % 256; + else + start = 0; + + if (submap == pair->info.ranges[i].end / 256) + end = pair->info.ranges[i].end % 256; + else + end = 255; + + if (map->submaps[submap].is_leaf && + start == 0 && end == 255) + { + set_entry (&map->submaps[submap].d.entry, + is_exact, &pair->info); + } + else + { + if (map->submaps[submap].is_leaf) + { + map->submaps[submap].is_leaf = FALSE; + map->submaps[submap].d.leaves = g_new (PangoMapEntry, 256); + for (j=0; j<256; j++) + { + map->submaps[submap].d.leaves[j].info = NULL; + map->submaps[submap].d.leaves[j].is_exact = FALSE; + } + } + + for (j=start; j<=end; j++) + set_entry (&map->submaps[submap].d.leaves[j], + is_exact, &pair->info); + + } + } + } + } + } + + return map; +} |