Back to index

lightning-sunbird  0.9+nobinonly
modules.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  * Pango
00003  * modules.c:
00004  *
00005  * ***** BEGIN LICENSE BLOCK *****
00006  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00007  *
00008  * The contents of this file are subject to the Mozilla Public License Version
00009  * 1.1 (the "License"); you may not use this file except in compliance with
00010  * the License. You may obtain a copy of the License at
00011  * http://www.mozilla.org/MPL/
00012  *
00013  * Software distributed under the License is distributed on an "AS IS" basis,
00014  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00015  * for the specific language governing rights and limitations under the
00016  * License.
00017  *
00018  * The Original Code is the Pango Library (www.pango.org).
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Red Hat Software.
00022  * Portions created by the Initial Developer are Copyright (C) 1999
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 #include <ctype.h>
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include <limits.h>
00044 #include <errno.h>
00045 
00046 #include <gmodule.h>
00047 
00048 #include "pango-modules.h"
00049 #include "pango-utils.h"
00050 
00051 typedef struct _PangoliteMapInfo    PangoliteMapInfo;
00052 typedef struct _PangoliteEnginePair PangoliteEnginePair;
00053 typedef struct _PangoliteSubmap     PangoliteSubmap;
00054 
00055 struct _PangoliteSubmap
00056 {
00057   gboolean is_leaf;
00058   union {
00059     PangoliteMapEntry entry;
00060     PangoliteMapEntry *leaves;
00061   } d;
00062 };
00063 
00064 struct _PangoliteMap
00065 {
00066   gint        n_submaps;
00067   PangoliteSubmap submaps[256];
00068 };
00069 
00070 struct _PangoliteMapInfo
00071 {
00072   const gchar *lang;
00073   guint       engine_type_id;
00074   guint       render_type_id;
00075   PangoliteMap    *map;
00076 };
00077 
00078 struct _PangoliteEnginePair
00079 {
00080   PangoliteEngineInfo info;
00081   gboolean        included;
00082   void            *load_info;
00083   PangoliteEngine     *engine;
00084 };
00085 
00086 static GList *maps = NULL;
00087 
00088 static GSList *builtin_engines = NULL;
00089 static GSList *registered_engines = NULL;
00090 static GSList *dlloaded_engines = NULL;
00091 
00092 static void build_map(PangoliteMapInfo *info);
00093 static void init_modules(void);
00094 
00108 PangoliteMap*
00109 pangolite_find_map(const char *lang, guint engine_type_id, guint render_type_id)
00110 {
00111   GList        *tmp_list = maps;
00112   PangoliteMapInfo *map_info = NULL;
00113   gboolean     found_earlier = FALSE;
00114 
00115   while (tmp_list) {
00116     map_info = tmp_list->data;
00117     if (map_info->engine_type_id == engine_type_id &&
00118         map_info->render_type_id == render_type_id) {
00119       if (strcmp(map_info->lang, lang) == 0)
00120         break;
00121       else
00122         found_earlier = TRUE;
00123     }
00124     tmp_list = tmp_list->next;
00125   }
00126   
00127   if (!tmp_list) {
00128     map_info = g_new(PangoliteMapInfo, 1);
00129     map_info->lang = g_strdup(lang);
00130     map_info->engine_type_id = engine_type_id;
00131     map_info->render_type_id = render_type_id;
00132     
00133     build_map(map_info);    
00134     maps = g_list_prepend(maps, map_info);
00135   }
00136   else if (found_earlier) {
00137     /* Move the found map to the beginning of the list
00138      * for speed next time around if we had to do
00139      * any failing strcmps.
00140      */
00141     maps = g_list_remove_link(maps, tmp_list);
00142     maps = g_list_prepend(maps, tmp_list->data);
00143     g_list_free_1(tmp_list);
00144   }  
00145   return map_info->map;
00146 }
00147 
00148 static PangoliteEngine *
00149 pangolite_engine_pair_get_engine(PangoliteEnginePair *pair)
00150 {
00151   if (!pair->engine) {
00152     if (pair->included) {
00153       PangoliteIncludedModule *included_module = pair->load_info;
00154       
00155       pair->engine = included_module->load(pair->info.id);
00156     }
00157     else {
00158       GModule *module;
00159       char    *module_name = pair->load_info;
00160       PangoliteEngine *(*load)(const gchar *id);
00161          
00162       module = g_module_open(module_name, 0);
00163       if (!module) {
00164              fprintf(stderr, "Cannot load module %s: %s\n",
00165                 module_name, g_module_error());
00166              return NULL;
00167            }
00168       
00169       g_module_symbol(module, "script_engine_load", (gpointer)&load);
00170       if (!load) {
00171              fprintf(stderr, "cannot retrieve script_engine_load from %s: %s\n",
00172                 module_name, g_module_error());
00173              g_module_close(module);
00174              return NULL;
00175            }
00176       
00177       pair->engine = (*load)(pair->info.id);
00178     }
00179   }
00180   return pair->engine;
00181 }
00182 
00183 static void
00184 handle_included_module(PangoliteIncludedModule *module, GSList **engine_list)
00185 {
00186   PangoliteEngineInfo *engine_info;
00187   int             n_engines, i;
00188 
00189   module->list(&engine_info, &n_engines);
00190   
00191   for (i = 0; i < n_engines; i++) {
00192     PangoliteEnginePair *pair = g_new(PangoliteEnginePair, 1);
00193     
00194     pair->info = engine_info[i];
00195     pair->included = TRUE;
00196     pair->load_info = module;
00197     pair->engine = NULL;
00198     
00199     *engine_list = g_slist_prepend(*engine_list, pair);
00200   }
00201 }
00202 
00203 static gboolean /* Returns true if succeeded, false if failed */
00204 process_module_file(FILE *module_file)
00205 {
00206   GString  *line_buf = g_string_new(NULL);
00207   GString  *tmp_buf = g_string_new(NULL);
00208   gboolean have_error = FALSE;
00209 
00210   while (pangolite_read_line(module_file, line_buf)) {
00211     PangoliteEnginePair *pair = g_new(PangoliteEnginePair, 1);
00212     PangoliteEngineRange *range;
00213     GList *ranges = NULL;
00214     GList *tmp_list;
00215     
00216     const char *p, *q;
00217     int        i, start, end;
00218     
00219     pair->included = FALSE;
00220     
00221     p = line_buf->str;
00222     
00223     if (!pangolite_skip_space(&p)) {
00224       g_free(pair);
00225       continue;
00226     }
00227     
00228     i = 0;
00229     while (1) {
00230          if (!pangolite_scan_string(&p, tmp_buf)) {
00231       have_error = TRUE;
00232       goto error;
00233     }
00234     
00235          switch (i) {
00236     case 0:
00237       pair->load_info = g_strdup(tmp_buf->str);
00238       break;
00239     case 1:
00240       pair->info.id = g_strdup(tmp_buf->str);
00241       break;
00242     case 2:
00243       pair->info.engine_type = g_strdup(tmp_buf->str);
00244       break;
00245     case 3:
00246       pair->info.render_type = g_strdup(tmp_buf->str);
00247       break;
00248     default:
00249       range = g_new(PangoliteEngineRange, 1);
00250       if (sscanf(tmp_buf->str, "%d-%d:", &start, &end) != 2) {
00251         fprintf(stderr, "Error reading modules file");
00252         have_error = TRUE;
00253         goto error;
00254       }
00255       q = strchr(tmp_buf->str, ':');
00256       if (!q) {
00257         fprintf(stderr, "Error reading modules file");
00258         have_error = TRUE;
00259         goto error;
00260       }
00261       q++;
00262       range->start = start;
00263       range->end = end;
00264       range->langs = g_strdup(q);
00265       
00266       ranges = g_list_prepend(ranges, range);
00267     }
00268     
00269          if (!pangolite_skip_space(&p))
00270            break;      
00271          i++;
00272     }
00273     
00274     if (i<3) {
00275       fprintf(stderr, "Error reading modules file");
00276       have_error = TRUE;
00277       goto error;
00278     }
00279     
00280     ranges = g_list_reverse(ranges);
00281     pair->info.n_ranges = g_list_length(ranges);
00282     pair->info.ranges = g_new(PangoliteEngineRange, pair->info.n_ranges);
00283     
00284     tmp_list = ranges;
00285     for (i=0; i<pair->info.n_ranges; i++) {
00286       pair->info.ranges[i] = *(PangoliteEngineRange *)tmp_list->data;
00287       tmp_list = tmp_list->next;
00288     }
00289     
00290     pair->engine = NULL;    
00291     dlloaded_engines = g_slist_prepend(dlloaded_engines, pair);
00292     
00293   error:
00294     g_list_foreach(ranges, (GFunc)g_free, NULL);
00295     g_list_free(ranges);
00296     
00297     if (have_error) {
00298       g_free(pair);
00299       break;
00300     }
00301   }
00302   
00303   g_string_free(line_buf, TRUE);
00304   g_string_free(tmp_buf, TRUE);  
00305   return !have_error;
00306 }
00307 
00308 static void
00309 read_modules(void)
00310 {
00311   FILE *module_file;  
00312   char *file_str = pangolite_config_key_get("Pangolite/ModuleFiles");
00313   char **files;
00314   int  n;
00315 
00316   if (!file_str)
00317     file_str = g_strconcat(pangolite_get_sysconf_subdirectory(),
00318                            G_DIR_SEPARATOR_S "pango.modules", NULL);
00319 
00320   files = pangolite_split_file_list(file_str);
00321 
00322   n = 0;
00323   while (files[n])
00324     n++;
00325   
00326   while (n-- > 0) {
00327     module_file = fopen(files[n], "r");
00328     if (!module_file)
00329       g_warning("Error opening module file '%s': %s\n", files[n], g_strerror(errno));
00330     else {
00331       process_module_file(module_file);
00332       fclose(module_file);
00333     }
00334   }
00335   
00336   g_strfreev(files);
00337   g_free(file_str);  
00338   dlloaded_engines = g_slist_reverse(dlloaded_engines);
00339 }
00340 
00341 static void
00342 set_entry(PangoliteMapEntry *entry, gboolean is_exact, PangoliteEngineInfo *info)
00343 {
00344   if ((is_exact && !entry->is_exact) || !entry->info) {
00345     entry->is_exact = is_exact;
00346     entry->info = info;
00347   }
00348 }
00349 
00350 static void
00351 init_modules(void)
00352 {
00353   static gboolean init = FALSE;
00354   
00355   if (init)
00356     return;
00357   else
00358     init = TRUE;
00359   
00360   read_modules();
00361 }
00362 
00363 static void
00364 map_add_engine(PangoliteMapInfo *info, PangoliteEnginePair *pair)
00365 {
00366   int      i, j, submap;
00367   PangoliteMap *map = info->map;
00368  
00369   for (i=0; i<pair->info.n_ranges; i++) {
00370     gchar    **langs;
00371     gboolean is_exact = FALSE;
00372     
00373     if (pair->info.ranges[i].langs) {
00374       langs = g_strsplit(pair->info.ranges[i].langs, ";", -1);
00375       for (j=0; langs[j]; j++)
00376         if (strcmp(langs[j], "*") == 0 || strcmp(langs[j], info->lang) == 0) {
00377           is_exact = TRUE;
00378           break;
00379              }
00380       g_strfreev(langs);
00381     }
00382     
00383     for (submap = pair->info.ranges[i].start / 256;
00384          submap <= pair->info.ranges[i].end / 256; submap ++) {
00385       gunichar start;
00386       gunichar end;
00387       
00388       if (submap == pair->info.ranges[i].start / 256)
00389         start = pair->info.ranges[i].start % 256;
00390       else
00391         start = 0;
00392       
00393       if (submap == pair->info.ranges[i].end / 256)
00394         end = pair->info.ranges[i].end % 256;
00395       else
00396         end = 255;
00397       
00398       if (map->submaps[submap].is_leaf && start == 0 && end == 255) {
00399         set_entry(&map->submaps[submap].d.entry, is_exact, &pair->info);
00400            }
00401       else {
00402              if (map->submaps[submap].is_leaf) {
00403           map->submaps[submap].is_leaf = FALSE;
00404           map->submaps[submap].d.leaves = g_new(PangoliteMapEntry, 256);
00405           for (j=0; j<256; j++) {
00406             map->submaps[submap].d.leaves[j].info = NULL;
00407             map->submaps[submap].d.leaves[j].is_exact = FALSE;
00408           }
00409         }
00410              
00411              for (j=start; j<=end; j++)
00412           set_entry(&map->submaps[submap].d.leaves[j], is_exact, &pair->info);
00413            }
00414     }
00415   }
00416 }
00417 
00418 static void
00419 map_add_engine_list(PangoliteMapInfo *info,
00420                     GSList       *engines,
00421                     const char   *engine_type,
00422                     const char   *render_type)  
00423 {
00424   GSList *tmp_list = engines;
00425   
00426   while (tmp_list) {
00427     PangoliteEnginePair *pair = tmp_list->data;
00428     tmp_list = tmp_list->next;
00429     
00430     if (strcmp(pair->info.engine_type, engine_type) == 0 &&
00431         strcmp(pair->info.render_type, render_type) == 0) {
00432       map_add_engine(info, pair);
00433     }
00434   }
00435 }
00436 
00437 static void
00438 build_map(PangoliteMapInfo *info)
00439 {
00440   int      i;
00441   PangoliteMap *map;
00442 
00443   const char *engine_type = g_quark_to_string(info->engine_type_id);
00444   const char *render_type = g_quark_to_string(info->render_type_id);
00445   
00446   init_modules();
00447 
00448   info->map = map = g_new(PangoliteMap, 1);
00449   map->n_submaps = 0;
00450   for (i=0; i<256; i++) {
00451     map->submaps[i].is_leaf = TRUE;
00452     map->submaps[i].d.entry.info = NULL;
00453     map->submaps[i].d.entry.is_exact = FALSE;
00454   }
00455   
00456   map_add_engine_list(info, dlloaded_engines, engine_type, render_type);  
00457   map_add_engine_list(info, registered_engines, engine_type, render_type);  
00458   map_add_engine_list(info, builtin_engines, engine_type, render_type);  
00459 }
00460 
00474 PangoliteMapEntry *
00475 pangolite_map_get_entry(PangoliteMap *map, guint32 wc)
00476 {
00477   PangoliteSubmap *submap = &map->submaps[wc / 256];
00478   return submap->is_leaf ? &submap->d.entry : &submap->d.leaves[wc % 256];
00479 }
00480 
00492 PangoliteEngine *
00493 pangolite_map_get_engine(PangoliteMap *map, guint32 wc)
00494 {
00495   PangoliteSubmap *submap = &map->submaps[wc / 256];
00496   PangoliteMapEntry *entry = submap->is_leaf ? &submap->d.entry : 
00497     &submap->d.leaves[wc % 256];
00498   
00499   if (entry->info)
00500     return pangolite_engine_pair_get_engine((PangoliteEnginePair *)entry->info);
00501   else
00502     return NULL;
00503 }
00504 
00514 void
00515 pangolite_module_register(PangoliteIncludedModule *module)
00516 {
00517   GSList *tmp_list = NULL;
00518   
00519   handle_included_module(module, &tmp_list);  
00520   registered_engines = g_slist_concat(registered_engines, 
00521                                       g_slist_reverse(tmp_list));
00522 }