Include <glob.h>.
[m17n/m17n-lib.git] / src / database.c
1 /* database.c -- database module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nDatabase
25     @brief The m17n database and API for it.
26
27     The m17n library dynamically acquires various kinds of information
28     in need from data in the <i> m17n database</i>.  Application
29     programs can also add/load their original data to/from the m17n
30     database.  The m17n database contains multiple heterogeneous data,
31     and each data is identified by four tags; TAG0, TAG1, TAG2, TAG3.
32     Each tag must be a symbol.
33
34     TAG0 specifies the type of data stored in the database as below.
35
36     @li
37     If TAG0 is #Mchar_table, the data is of the @e chartable @e
38     type and provides information about each character.  In this case,
39     TAG1 specifies the type of the information and must be #Msymbol,
40     #Minteger, #Mstring, #Mtext, or #Mplist.  TAG2 and TAG3 can be any
41     symbols.
42
43     @li
44     If TAG0 is #Mcharset, the data is of the @e charset @e type
45     and provides a decode/encode mapping table for a charset.  In this
46     case, TAG1 must be a symbol representing a charset.  TAG2 and TAG3
47     can be any symbols.
48
49     @li 
50     If TAG0 is neither #Mchar_table nor #Mcharset, the data is of
51     the @e plist @e type.  See the documentation of the 
52     mdatabase_load () function for the details.  
53     In this case, TAG1, TAG2, and TAG3 can be any symbols.
54
55     The notation \<TAG0, TAG1, TAG2, TAG3\> means a data with those
56     tags.
57
58     Application programs first calls the mdatabase_find () function to
59     get a pointer to an object of the type #MDatabase.  That object
60     holds information about the specified data.  When it is
61     successfully returned, the mdatabase_load () function loads the
62     data.  The implementation of the structure #MDatabase is
63     concealed from application programs.
64 */
65
66 /***ja
67     @addtogroup m17nDatabase
68     @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤È¤½¤ì¤Ë´Ø¤¹¤ë API.
69
70     m17n ¥é¥¤¥Ö¥é¥ê¤ÏɬÍפ˱þ¤¸¤ÆưŪ¤Ë @e m17n @e ¥Ç¡¼¥¿¥Ù¡¼¥¹ 
71     ¤«¤é¾ðÊó¤ò¼èÆÀ¤¹¤ë¡£¤Þ¤¿¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤âÆȼ«¤Î¥Ç¡¼¥¿¤ò 
72     m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÄɲä·¡¢¤½¤ì¤òưŪ¤Ë¼èÆÀ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£m17n 
73     ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤ÏÊ£¿ô¤Î¿Íͤʥǡ¼¥¿¤¬´Þ¤Þ¤ì¤Æ¤ª¤ê¡¢³Æ¥Ç¡¼¥¿¤Ï
74     TAG0, TAG1, TAG2, TAG3¡Ê¤¹¤Ù¤Æ¥·¥ó¥Ü¥ë¡Ë¤Î£´¤Ä¤Î¥¿¥°¤Ë¤è¤Ã¤Æ¼±Ê̤µ¤ì¤ë¡£
75
76     TAG0 ¤Ë¤è¤Ã¤Æ¡¢¥Ç¡¼¥¿¥Ù¡¼¥¹Æâ¤Î¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ï¼¡¤Î¤è¤¦¤Ë»ØÄꤵ¤ì¤ë¡£
77
78     @li 
79     TAG0 ¤¬ #Mchar_table ¤Ç¤¢¤ë¥Ç¡¼¥¿¤Ï @e chartable¥¿¥¤¥× 
80     ¤È¸Æ¤Ð¤ì¡¢³Æʸ»ú¤Ë´Ø¤¹¤ë¾ðÊó¤òÄ󶡤¹¤ë¡£¤³¤Î¾ì¹ç
81     TAG1 ¤Ï¾ðÊó¤Î¼ïÎà¤ò»ØÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢#Msymbol, #Minteger, #Mstring,
82     #Mtext, #Mplist ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£TAG2 ¤È TAG3 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
83
84     @li 
85     TAG0 ¤¬ #Mcharset ¤Ç¤¢¤ë¥Ç¡¼¥¿¤Ï @e charset¥¿¥¤¥× 
86     ¤È¸Æ¤Ð¤ì¡¢Ê¸»ú¥»¥Ã¥ÈÍѤΥǥ³¡¼¥É¡¿¥¨¥ó¥³¡¼¥É¥Þ¥Ã¥×¤òÄ󶡤¹¤ë¡£¤³¤Î¾ì¹ç TAG1
87     ¤Ïʸ»ú¥»¥Ã¥È¤Î¥·¥ó¥Ü¥ë¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£TAG2 ¤È TAG3
88     ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
89
90     @li
91     TAG0 ¤¬ #Mchar_table ¤Ç¤â #Mcharset ¤Ç¤â¤Ê¤¤¾ì¹ç¡¢¤½¤Î¥Ç¡¼¥¿¤Ï @e
92     plist¥¿¥¤¥× ¤Ç¤¢¤ë¡£¾ÜºÙ¤Ë´Ø¤·¤Æ¤Ï´Ø¿ô mdatabase_load () 
93     ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£¤³¤Î¾ì¹ç TAG1¡¢TAG2¡¢TAG3 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
94
95     ÆÃÄê¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò \<TAG0, TAG1, TAG2, TAG3\> 
96     ¤È¤¤¤¦·Á¼°¤Çɽ¤¹¡£
97
98     ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¡¢¤Þ¤º´Ø¿ô mdatabase_find () 
99     ¤ò»È¤Ã¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÝ»ý¤¹¤ë¥ª¥Ö¥¸¥§¥¯¥È¡Ê#MDatabase
100     ·¿¡Ë¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÆÀ¤ë¡£¤½¤ì¤ËÀ®¸ù¤·¤¿¤é¡¢ mdatabase_load () 
101     ¤Ë¤è¤Ã¤Æ¼ÂºÝ¤Ë¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¥í¡¼¥É¤¹¤ë¡£¹½Â¤ÂΠ#MDatabase 
102     ¼«¿È¤¬¤É¤¦¼ÂÁõ¤µ¤ì¤Æ¤¤¤ë¤«¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤«¤é¤Ï¸«¤¨¤Ê¤¤¡£
103
104     @latexonly \IPAlabel{database} @endlatexonly
105 */
106
107 /*=*/
108
109 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
110 /*** @addtogroup m17nInternal
111      @{ */
112
113 #include <config.h>
114 #include <stdio.h>
115 #include <stdlib.h>
116 #include <string.h>
117 #include <ctype.h>
118 #include <sys/types.h>
119 #include <sys/stat.h>
120 #include <unistd.h>
121 #include <limits.h>
122 #include <glob.h>
123
124 #include "m17n.h"
125 #include "m17n-misc.h"
126 #include "internal.h"
127 #include "mtext.h"
128 #include "character.h"
129 #include "charset.h"
130 #include "database.h"
131 #include "coding.h"
132 #include "plist.h"
133
134 /** The file containing a list of databases.  */
135 #define MDB_DIR "mdb.dir"
136 #define MDB_DIR_LEN 8
137
138 #define MAX_TIME(TIME1, TIME2) ((TIME1) >= (TIME2) ? (TIME1) : (TIME2))
139
140 static MSymbol Masterisk;
141
142 /** Structure for a data in the m17n database.  */
143
144 struct MDatabase
145 {
146   /** Tags to identify the data.  <tag>[0] specifies the type of
147       database.  If it is #Mchar_table, the type is @e chartable, if
148       it is #Mcharset, the type is @e charset, otherwise the type is
149       @e plist.  */
150   MSymbol tag[4];
151
152   void *(*loader) (MSymbol *tags, void *extra_info);
153
154   /** The meaning of the value is dependent on <loader>.  If <loader>
155       is load_database (), the value is a string of the file name that
156       contains the data.  */
157   void *extra_info;
158 };
159
160 /** List of all data.  */
161 struct MDatabaseList
162 {
163   int size, inc, used;
164   MDatabase *mdbs;
165 };
166
167 static struct MDatabaseList mdb_list;
168
169
170 static int
171 read_number (char *buf, int *i)
172 {
173   int idx = *i;
174   int c = buf[idx++];
175   int n;
176
177   if (!c)
178     return -1;
179
180   while (c && isspace (c)) c = buf[idx++];
181
182   if (c == '0')
183     {
184       if (buf[idx] == 'x')
185         {
186           for (idx++, c = 0; (n = hex_mnemonic[(unsigned) buf[idx]]) < 16;
187                idx++)
188             c  = (c << 4) | n;
189           *i = idx;
190           return c;
191         }
192       c = 0;
193     }
194   else if (c == '\'')
195     {
196       c = buf[idx++];
197       if (c == '\\')
198         {
199           c = buf[idx++];
200           n = escape_mnemonic[c];
201           if (n != 255)
202             c = n;
203         }
204       while (buf[idx] && buf[idx++] != '\'');
205       *i = idx;
206       return c;
207     }
208   else if (hex_mnemonic[c] < 10)
209     c -= '0';
210   else
211     return -1;
212
213   while ((n = hex_mnemonic[(unsigned) buf[idx]]) < 10)
214     c = (c * 10) + n, idx++;
215   *i = idx;
216   return c;
217 }
218
219
220 /** Load a data of type @c chartable from the file FD, and return the
221     newly created chartable.  */
222
223 static void *
224 load_chartable (FILE *fp, MSymbol type)
225 {
226   int c, from, to;
227   char buf[1024];
228   void *val;
229   MCharTable *table;
230
231   if (! fp)
232     MERROR (MERROR_DB, NULL);
233
234   table = mchartable (type, (type == Msymbol ? (void *) Mnil
235                              : type == Minteger ? (void *) -1
236                              : NULL));
237
238   while (! feof (fp))
239     {
240       int i, len;
241
242       for (len = 0; len < 1023 && (c = getc (fp)) != EOF && c != '\n'; len++)
243         buf[len] = c;
244       buf[len] = '\0';    
245       if (hex_mnemonic[(unsigned) buf[0]] >= 10)
246         /* skip comment/invalid line */
247         continue;
248       i = 0;
249       from = read_number (buf, &i);
250       if (buf[i] == '-')
251         i++, to = read_number (buf, &i);
252       else
253         to = from;
254       if (from < 0 || to < from)
255         continue;
256
257       while (buf[i] && isspace ((unsigned) buf[i])) i++;
258       c = buf[i];
259       if (!c)
260         continue;
261
262       if (type == Mstring)
263         {
264           /* VAL is a C-string.  */
265           if (! (val = strdup (buf + i)))
266             MEMORY_FULL (MERROR_DB);
267         }
268       else if (type == Minteger)
269         {
270           /* VAL is an integer.  */
271           int positive = 1;
272           int n;
273
274           if (c == '-')
275             i++, positive = -1;
276           n = read_number (buf, &i);
277           if (n < 0)
278             goto label_error;
279           val = (void *) (n * positive);
280         }
281       else if (type == Mtext)
282         {
283           /* VAL is an M-text.  */
284           MText *mt;
285           if (c == '"')
286             mt = mconv_decode_buffer (Mcoding_utf_8,
287                                       (unsigned char *) (buf + i),
288                                       len - i - 1);
289           else
290             {
291               mt = mtext ();
292               while ((c = read_number (buf, &i)) >= 0)
293                 mt = mtext_cat_char (mt, c);
294             }
295           val = (void *) mt;
296         }
297       else if (type == Msymbol)
298         {
299           char *p = buf + i;
300
301           while (*p && ! isspace (*p)) 
302             {
303               if (*p == '\\' && p[1] != '\0')
304                 {
305                   memmove (p, p + 1, buf + len - (p + 1));
306                   len--;
307                 }
308               p++;
309             }
310           *p = '\0';
311           if (! strcmp (buf + i, "nil"))
312             val = (void *) Mnil;
313           else
314             val = (void *) msymbol (buf + i);
315         }
316       else if (type == Mplist)
317         {
318           val = (void *) mplist__from_string ((unsigned char *) buf + i,
319                                               strlen (buf + i));
320         }
321       else
322         val = NULL;
323
324       if (from == to)
325         mchartable_set (table, from, val);
326       else
327         mchartable_set_range (table, from, to, val);
328     }
329   return table;
330
331  label_error:
332   M17N_OBJECT_UNREF (table);
333   MERROR (MERROR_DB, NULL);
334 }
335
336
337 /** Load a data of type @c charset from the file FD.  */
338
339 static void *
340 load_charset (FILE *fp, MSymbol charset_name)
341 {
342   MCharset *charset = MCHARSET (charset_name);
343   int *decoder;
344   MCharTable *encoder;
345   int size;
346   int i, c;
347   int found = 0;
348   MPlist *plist;
349
350   if (! charset)
351     MERROR (MERROR_DB, NULL);
352   size = (charset->code_range[15]
353           - (charset->min_code - charset->code_range_min_code));
354   MTABLE_MALLOC (decoder, size, MERROR_DB);
355   for (i = 0; i < size; i++)
356     decoder[i] = -1;
357   encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
358
359   while ((c = getc (fp)) != EOF)
360     {
361       unsigned code1, code2, c1, c2;
362       int idx1, idx2;
363       char buf[256];
364
365       ungetc (c, fp);
366       fgets (buf, 256, fp);
367       if (c != '#')
368         {
369           if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
370             {
371               idx1 = CODE_POINT_TO_INDEX (charset, code1);
372               if (idx1 >= size)
373                 continue;
374               idx2 = CODE_POINT_TO_INDEX (charset, code2);
375               if (idx2 >= size)
376                 idx2 = size - 1;
377               c2 = c1 + (idx2 - idx1);
378             }
379           else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
380             {
381               idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
382               if (idx1 >= size)
383                 continue;
384               c2 = c1;
385             }
386           else
387             continue;
388           if (idx1 >= 0 && idx2 >= 0)
389             {
390               decoder[idx1] = c1;
391               mchartable_set (encoder, c1, (void *) code1);
392               for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
393                 {
394                   code1 = INDEX_TO_CODE_POINT (charset, idx1);
395                   decoder[idx1] = c1;
396                   mchartable_set (encoder, c1, (void *) code1);
397                 }
398               found++;
399             }
400         }
401     }
402
403   if (! found)
404     {
405       free (decoder);
406       M17N_OBJECT_UNREF (encoder);
407       return NULL;
408     }
409   plist = mplist ();
410   mplist_add (plist, Mt, decoder);
411   mplist_add (plist, Mt, encoder);
412   return plist;
413 }
414
415 static char *
416 gen_database_name (char *buf, MSymbol *tags)
417 {
418   int i;
419
420   strcpy (buf, msymbol_name (tags[0]));
421   for (i = 1; i < 4; i++)
422     {
423       strcat (buf, ", ");
424       strcat (buf, msymbol_name (tags[i]));
425     }
426   return buf;
427 }
428
429 static FILE *
430 get_database_stream (MDatabaseInfo *db_info)
431 {
432   FILE *fp = NULL;
433   struct stat buf;
434
435   if (db_info->filename[0] == '/')
436     {
437       if (stat (db_info->filename, &buf) == 0
438           && (fp = fopen (db_info->filename, "r")))
439         db_info->time = MAX_TIME (buf.st_mtime, buf.st_ctime);
440     }
441   else
442     {
443       MPlist *plist;
444       char *path;
445       int filelen = strlen (db_info->filename);
446       USE_SAFE_ALLOCA;
447
448       MPLIST_DO (plist, mdatabase__dir_list)
449         {
450           MDatabaseInfo *dir_info = MPLIST_VAL (plist);
451           int require = strlen (dir_info->filename) + filelen + 1;
452
453           SAFE_ALLOCA (path, require);
454           strcpy (path, dir_info->filename);
455           strcat (path, db_info->filename);
456           if (stat (path, &buf) == 0
457               && (fp = fopen (path, "r")))
458             {
459               free (db_info->filename);
460               db_info->filename = strdup (path);
461               db_info->time = MAX_TIME (buf.st_mtime, buf.st_ctime);
462               break;
463             }
464         }
465       SAFE_FREE (path);
466     }
467   return fp;
468 }
469
470 static void *
471 load_database (MSymbol *tags, void *extra_info)
472 {
473   FILE *fp = get_database_stream ((MDatabaseInfo *) extra_info);
474   void *value;
475
476   if (! fp)
477     MERROR (MERROR_DB, NULL);
478
479   if (tags[0] == Mchar_table)
480     value = load_chartable (fp, tags[1]);
481   else if (tags[0] == Mcharset)
482     value = load_charset (fp, tags[1]);
483   else
484     value = mplist__from_file (fp, NULL);
485   fclose (fp);
486
487   if (! value)
488     MERROR (MERROR_DB, NULL);
489   return value;
490 }
491
492
493 /** If DIRNAME is a readable directory, allocate MDatabaseInfo and
494     copy DIRNAME to a newly allocated memory and return it.  If
495     DIRNAME does not end with a slash, append a slash to the new memory.  */
496
497 static MDatabaseInfo *
498 get_dir_info (char *dirname)
499 {
500   struct stat buf;
501   int len;
502   MDatabaseInfo *dir_info;
503
504   if (! dirname
505       || stat (dirname, &buf) < 0
506       || ! (buf.st_mode & S_IFDIR))
507     return NULL;
508
509   MSTRUCT_MALLOC (dir_info, MERROR_DB);
510   len = strlen (dirname);
511   MTABLE_MALLOC (dir_info->filename, len + 2, MERROR_DB);
512   memcpy (dir_info->filename, dirname, len + 1);
513   if (dir_info->filename[len - 1] != '/')
514     {
515       dir_info->filename[len] = '/';
516       dir_info->filename[len + 1] = '\0';
517     }
518   /* Set this to zero so that the first call of update_database_list
519      surely checks this directory.  */
520   dir_info->time = 0;
521   return dir_info;
522 }
523
524 static MDatabase *
525 find_database (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
526 {
527   int i;
528
529   for (i = 0; i < mdb_list.used; i++)
530     {
531       MDatabase *mdb = mdb_list.mdbs + i;
532
533       if (tag0 == mdb->tag[0]
534           && tag1 == mdb->tag[1]
535           && tag2 == mdb->tag[2]
536           && tag3 == mdb->tag[3])
537         return mdb;
538     }
539   return NULL;
540 }
541
542 static void
543 update_database_list ()
544 {
545   MPlist *plist;
546   char *path;
547   USE_SAFE_ALLOCA;
548
549   /* Usually this avoids path to be reallocated.  */
550   SAFE_ALLOCA (path, 256);
551
552   MPLIST_DO (plist, mdatabase__dir_list)
553     {
554       MDatabaseInfo *dir_info = MPLIST_VAL (plist);
555       struct stat statbuf;
556       MPlist *pl, *p;
557       int i, j, len;
558       FILE *fp;
559
560       if (stat (dir_info->filename, &statbuf) < 0)
561         continue;
562       if (dir_info->time >= statbuf.st_ctime
563           && dir_info->time >= statbuf.st_mtime)
564         continue;
565       dir_info->time = MAX_TIME (statbuf.st_ctime, statbuf.st_mtime);
566       len = strlen (dir_info->filename);
567 #ifdef PATH_MAX
568       if (len + MDB_DIR_LEN >= PATH_MAX)
569         continue;
570 #endif  /* PATH_MAX */
571       SAFE_ALLOCA (path, len + MDB_DIR_LEN + 1);
572       memcpy (path, dir_info->filename, len);
573       memcpy (path + len, MDB_DIR, MDB_DIR_LEN);
574       path[len + MDB_DIR_LEN] = '\0';
575       if (! (fp = fopen (path, "r")))
576         continue;
577       pl = mplist__from_file (fp, NULL);
578       fclose (fp);
579       if (! pl)
580         continue;
581       MPLIST_DO (p, pl)
582         {
583           MDatabase mdb;
584           MPlist *p1;
585           MText *mt;
586           int nbytes;
587           int with_wildcard = 0;
588
589           if (! MPLIST_PLIST_P (p))
590             continue;
591           p1 = MPLIST_PLIST (p);
592           if (! MPLIST_SYMBOL_P (p1))
593               continue;
594           for (i = 0, p1 = MPLIST_PLIST (p);
595                i < 4 && MPLIST_KEY (p1) == Msymbol;
596                i++, p1 = MPLIST_NEXT (p1))
597             with_wildcard |= ((mdb.tag[i] = MPLIST_SYMBOL (p1)) == Masterisk);
598           if (i == 0
599               || mdb.tag[0] == Masterisk
600               || ! MPLIST_MTEXT_P (p1))
601             continue;
602           for (; i < 4; i++)
603             mdb.tag[i] = Mnil;
604           mdb.loader = load_database;
605           mt = MPLIST_MTEXT (p1);
606           if (mt->format >= MTEXT_FORMAT_UTF_16LE)
607             mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
608           nbytes = mtext_nbytes (mt);
609 #ifdef PATH_MAX
610           if (nbytes > PATH_MAX)
611             continue;
612 #endif  /* PATH_MAX */
613           if (with_wildcard
614               && mdb.tag[0] != Mchar_table
615               && mdb.tag[0] != Mcharset)
616             {
617               glob_t globbuf;
618               MPlist *load_key;
619
620               SAFE_ALLOCA (path, len + nbytes + 1);
621               memcpy (path, dir_info->filename, len);
622               memcpy (path + len, mt->data, nbytes);
623               path[len + nbytes] = '\0';
624
625               if (glob (path, GLOB_NOSORT | GLOB_NOCHECK, NULL, &globbuf) != 0)
626                 continue;
627               load_key = mplist ();
628               for (i = 0; i < globbuf.gl_pathc; i++)
629                 {
630                   if (! (fp = fopen (globbuf.gl_pathv[i], "r")))
631                     continue;
632                   p1 = mplist__from_file (fp, load_key);
633                   fclose (fp);
634                   if (! p1)
635                     continue;
636                   if (MPLIST_PLIST_P (p1))
637                     {
638                       MPlist *p0;
639                       MDatabase mdb2;
640
641                       for (j = 0, p0 = MPLIST_PLIST (p1);
642                            j < 4 && MPLIST_SYMBOL_P (p0);
643                            j++, p0 = MPLIST_NEXT (p0))
644                         mdb2.tag[j] = MPLIST_SYMBOL (p0);
645                       for (; j < 4; j++)
646                         mdb2.tag[j] = Mnil;
647                       for (j = 0; j < 4; j++)
648                         if (mdb.tag[j] == Masterisk
649                             ? mdb2.tag[j] == Mnil
650                             : (mdb.tag[j] != Mnil && mdb.tag[j] != mdb2.tag[j]))
651                           break;
652                       if (j == 4
653                           && ! find_database (mdb2.tag[0], mdb2.tag[1],
654                                               mdb2.tag[2], mdb2.tag[3]))
655                         {
656                           mdb2.loader = load_database;
657                           mdb2.extra_info = calloc (1, sizeof (MDatabaseInfo));
658                           if (! mdb2.extra_info)
659                             MEMORY_FULL (MERROR_DB);
660                           ((MDatabaseInfo*) mdb2.extra_info)->filename
661                             = strdup (globbuf.gl_pathv[i]);
662                           MLIST_APPEND1 (&mdb_list, mdbs, mdb2, MERROR_DB);
663                         }
664                     }
665                   M17N_OBJECT_UNREF (p1);
666                 }
667               M17N_OBJECT_UNREF (load_key);
668               globfree (&globbuf);
669             }
670           else
671             {
672               if (find_database (mdb.tag[0], mdb.tag[1],
673                                  mdb.tag[2], mdb.tag[3]))
674                 continue;
675               SAFE_ALLOCA (path, nbytes + 1);
676               memcpy (path, mt->data, nbytes);
677               path[nbytes] = '\0';
678               mdb.extra_info = calloc (1, sizeof (MDatabaseInfo));
679               if (! mdb.extra_info)
680                 MEMORY_FULL (MERROR_DB);
681               ((MDatabaseInfo*) mdb.extra_info)->filename = strdup (path);
682               MLIST_APPEND1 (&mdb_list, mdbs, mdb, MERROR_DB);
683             }
684         }
685       M17N_OBJECT_UNREF (pl);
686     }
687
688   SAFE_FREE (path);
689 }
690
691 \f
692 /* Internal API */
693
694 /** List of database directories.  */ 
695 MPlist *mdatabase__dir_list;
696
697 int
698 mdatabase__init ()
699 {
700   MDatabaseInfo *dir_info;
701
702   Mchar_table = msymbol ("char-table");
703   Masterisk = msymbol ("*");
704
705   mdatabase__dir_list = mplist ();
706   /** The macro M17NDIR specifies a directory where the system-wide
707     MDB_DIR file exists.  */
708   if ((dir_info = get_dir_info (M17NDIR)))
709     mplist_set (mdatabase__dir_list, Mt, dir_info);
710
711   /* The variable mdatabase_dir specifies a directory where an
712      application program specific MDB_DIR file exists.  */
713   if ((dir_info = get_dir_info (mdatabase_dir)))
714     mplist_push (mdatabase__dir_list, Mt, dir_info);
715
716   /* The environment variable M17NDIR (if non-NULL) specifies a
717      directory where a user specific MDB_DIR file exists.  */
718   if ((dir_info = get_dir_info (getenv ("M17NDIR"))))
719     mplist_push (mdatabase__dir_list, Mt, dir_info);
720
721   MLIST_INIT1 (&mdb_list, mdbs, 256);
722   update_database_list ();
723
724   mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
725                        mdatabase_find);
726   mdatabase__loader = (void *(*) (void *)) mdatabase_load;
727
728   return 0;
729 }
730
731 void
732 mdatabase__fini (void)
733 {
734   int i;
735   MPlist *plist; 
736
737   MPLIST_DO (plist, mdatabase__dir_list)
738     free (MPLIST_VAL (plist));
739   M17N_OBJECT_UNREF (mdatabase__dir_list);
740
741   for (i = 0; i < mdb_list.used; i++)
742     {
743       MDatabase *mdb = mdb_list.mdbs + i;
744
745       if (mdb->loader == load_database)
746         {
747           MDatabaseInfo *db_info = mdb->extra_info;
748
749           free (db_info->filename);
750           free (db_info);
751         }
752     }
753   MLIST_FREE1 (&mdb_list, mdbs);
754 }
755
756 MPlist *
757 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
758 {
759   int mdebug_mask = MDEBUG_DATABASE;
760   FILE *fp;
761   MPlist *plist;
762   char buf[256];
763
764   if (mdb->loader != load_database
765       || mdb->tag[0] == Mchar_table
766       || mdb->tag[0] == Mcharset)
767     MERROR (MERROR_DB, NULL);
768   MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
769                  gen_database_name (buf, mdb->tag));
770   fp = get_database_stream ((MDatabaseInfo *) mdb->extra_info);
771   if (! fp)
772     MERROR (MERROR_DB, NULL);
773   plist = mplist__from_file (fp, keys);
774   fclose (fp);
775   return plist;
776 }
777
778
779 /* Check if the database MDB should be reloaded or not.  */
780
781 int
782 mdatabase__check (MDatabase *mdb)
783 {
784   MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
785   struct stat buf;
786
787   if (stat (db_info->filename, &buf) < 0)
788     return -1;
789   return (db_info->time >= buf.st_ctime
790           && db_info->time >= buf.st_mtime);
791 }
792
793 /*** @} */
794 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
795
796 \f
797 /* External API */
798
799 /*** @addtogroup m17nDatabase */
800 /*** @{ */
801
802 /*=*/
803 /***en
804     @brief Directory for application specific data.
805
806     If an application program wants to provide a data specific to the
807     program or a data overriding what supplied by the m17n database,
808     it must set this variable to a name of directory that contains the
809     data files before it calls the macro M17N_INIT ().  The directory
810     may contain a file "mdb.dir" which contains a list of data
811     definitions in the format described in @ref mdbDir "mdbDir(5)".
812
813     The default value is NULL.  */
814 /***ja
815     @brief ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¸ÇÍ­¤Î¥Ç¡¼¥¿Íѥǥ£¥ì¥¯¥È¥ê.
816
817     ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬¡¢¤½¤Î¥×¥í¥°¥é¥à¸ÇÍ­¤Î¥Ç¡¼¥¿¤ä m17n 
818     ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¾å½ñ¤­¤¹¤ë¥Ç¡¼¥¿¤òÄ󶡤¹¤ë¾ì¹ç¤Ë¤Ï¡¢¥Þ¥¯¥í M17N_INIT () 
819     ¤ò¸Æ¤ÖÁ°¤Ë¤³¤ÎÊÑ¿ô¤ò¥Ç¡¼¥¿¥Õ¥¡¥¤¥ë¤ò´Þ¤à¥Ç¥£¥ì¥¯¥È¥ê̾¤Ë¥»¥Ã¥È¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤Ï
820     "mdb.dir" ¥Õ¥¡¥¤¥ë¤ò¤ª¤¯¤³¤È¤¬¤Ç¤­¤ë¡£¤½¤Î"mdb.dir"¥Õ¥¡¥¤¥ë¤Ë¤Ï¡¢ 
821     @ref mdbDir "mdbDir(5)" ¤ÇÀâÌÀ¤µ¤ì¤Æ¤¤¤ë¥Õ¥©¡¼¥Þ¥Ã¥È¤Ç¥Ç¡¼¥¿ÄêµÁ¤Î¥ê¥¹¥È¤òµ­½Ò¤¹¤ë¡£
822
823     ¥Ç¥Õ¥©¥ë¥È¤ÎÃͤϠNULL ¤Ç¤¢¤ë¡£  */
824
825 char *mdatabase_dir;
826
827 /*=*/
828 /***en
829     @brief Look for a data in the database.
830
831     The mdatabase_find () function searches the m17n database for a
832     data who has tags $TAG0 through $TAG3, and returns a pointer to
833     the data.  If such a data is not found, it returns @c NULL.  */
834
835 /***ja
836     @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹Ãæ¤Î¥Ç¡¼¥¿¤òõ¤¹.
837
838     ´Ø¿ô mdatabase_find () ¤Ï¡¢ m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ãæ¤Ç $TAG0 ¤«¤é 
839     $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤Î¤è¤¦¤Ê¥Ç¡¼¥¿¤¬¤Ê¤±¤ì¤Ð
840     @c NULL ¤òÊÖ¤¹¡£
841
842     @latexonly \IPAlabel{mdatabase_find} @endlatexonly  */
843
844 MDatabase *
845 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
846 {
847   update_database_list ();
848   return find_database (tag0, tag1, tag2, tag3);
849 }
850
851 /*=*/
852 /***en
853     @brief Return a data list of the m17n database.
854
855     The mdatabase_list () function searches the m17n database for data
856     who have tags $TAG0 through $TAG3, and returns their list by a
857     plist.  The value #Mnil in $TAGn means a wild card that matches
858     any tag.  Each element of the plist has key #Mt and value a
859     pointer to type #MDatabase.  */
860 /***ja
861     @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¥ê¥¹¥È¤òÊÖ¤¹.
862
863     ´Ø¿ô mdatabase_list () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é $TAG0 ¤«¤é$TAG3 
864     ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤Î¥ê¥¹¥È¤òplist ¤È¤·¤ÆÊÖ¤¹¡£ $TAGn ¤¬ #Mnil
865     ¤Ç¤¢¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥¿¥°¤Ë¥Þ¥Ã¥Á¤¹¤ë¥ï¥¤¥ë¥É¥«¡¼¥É¤È¤·¤Æ¼è¤ê°·¤ï¤ì¤ë¡£ÊÖ¤µ¤ì¤ë
866     plist ¤Î³ÆÍ×ÁǤϥ­¡¼ ¤È¤·¤Æ #Mt ¤ò¡¢ÃͤȤ·¤Æ #MDatabase ·¿¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò»ý¤Ä¡£  */
867
868 MPlist *
869 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
870 {
871   int i;
872   MPlist *plist = NULL, *pl;
873
874   update_database_list ();
875
876   for (i = 0; i < mdb_list.used; i++)
877     {
878       MDatabase *mdb = mdb_list.mdbs + i;
879
880       if ((tag0 == Mnil || tag0 == mdb->tag[0])
881           && (tag1 == Mnil || tag1 == mdb->tag[1])
882           && (tag2 == Mnil || tag2 == mdb->tag[2])
883           && (tag3 == Mnil || tag3 == mdb->tag[3]))
884         {
885           if (! plist)
886             plist = pl = mplist ();
887           pl = mplist_add (pl, Mt, mdb);
888         }
889     }
890   return plist;
891 }
892
893 /*=*/
894 /***en
895     @brief Define a data of the m17n database.
896
897     The mdatabase_define () function defines a data that has tags
898     $TAG0 through $TAG3 and additional information $EXTRA_INFO.
899
900     $LOADER is a pointer to a function that loads the data from the
901     database.  This function is called from the mdatabase_load ()
902     function with the two arguments $TAGS and $EXTRA_INFO.  Here,
903     $TAGS is the array of $TAG0 through $TAG3.
904
905     If $LOADER is @c NULL, the default loader of the m17n library is
906     used.  In this case, $EXTRA_INFO must be a string specifying a
907     filename that contains the data.
908
909     @return
910     If the operation was successful, mdatabase_define () returns a
911     pointer to the defined data, which can be used as an argument to
912     mdatabase_load ().  Otherwise, it returns @c NULL.  */
913
914 /***ja
915     @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë.
916
917     ´Ø¿ô mdatabase_define () ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ª¤è¤ÓÉղþðÊó 
918     $EXTRA_INFO ¤ò»ý¤Ä¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë¡£
919
920     $LOADER ¤Ï¤½¤Î¥Ç¡¼¥¿¤Î¥í¡¼¥É¤ËÍѤ¤¤é¤ì¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï
921     mdatabase_load () ¤«¤é $TAGS ¤È $EXTRA_INFO ¤È¤¤¤¦Æó¤Ä¤Î°ú¿ôÉÕ¤­¤Ç¸Æ¤Ó½Ð¤µ¤ì¤ë¡£¤³¤³¤Ç 
922     $TAGS ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤ÎÇÛÎó¤Ç¤¢¤ë¡£
923
924     ¤â¤· $LOADER ¤¬ @c NULL ¤Ê¤é¡¢m17n ¥é¥¤¥Ö¥é¥êɸ½à¤Î¥í¡¼¥À¤¬»È¤ï¤ì¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï
925     $EXTRA_INFO ¤Ï¥Ç¡¼¥¿¤ò´Þ¤à¥Õ¥¡¥¤¥ë̾¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
926
927     @return
928     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mdatabase_define () 
929     ¤ÏÄêµÁ¤µ¤ì¤¿¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¥Ý¥¤¥ó¥¿¤Ï´Ø¿ô mdatabase_load () 
930     ¤Î°ú¿ô¤È¤·¤ÆÍѤ¤¤ë¤³¤È¤¬¤Ç¤­¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
931
932     @latexonly \IPAlabel{mdatabase_define} @endlatexonly  */
933
934 /***
935     @seealso
936     mdatabase_load (),  mdatabase_define ()  */
937
938 MDatabase *
939 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
940                   void *(*loader) (MSymbol *, void *),
941                   void *extra_info)
942 {
943   MDatabase *mdb;
944
945   mdb = mdatabase_find (tag0, tag1, tag2, tag3);
946   if (! mdb)
947     {
948       MDatabase template;
949
950       template.tag[0] = tag0, template.tag[1] = tag1;
951       template.tag[2] = tag2, template.tag[3] = tag3;
952       template.extra_info = NULL;
953       MLIST_APPEND1 (&mdb_list, mdbs, template, MERROR_DB);
954       mdb = mdb_list.mdbs + (mdb_list.used - 1);
955     }
956   mdb->loader = loader ? loader : load_database;
957   if (mdb->loader == load_database)
958     {
959       MDatabaseInfo *db_info = mdb->extra_info;
960
961       if (db_info)
962         free (db_info->filename);
963       else
964         db_info = mdb->extra_info = malloc (sizeof (MDatabaseInfo));
965       db_info->filename = strdup ((char *) extra_info);
966       db_info->time = 0;
967     }
968   else
969     mdb->extra_info = extra_info;
970   return (&(mdb_list.mdbs[mdb_list.used - 1]));
971 }
972
973 /*=*/
974 /***en
975     @brief Load a data from the database.
976
977     The mdatabase_load () function loads a data specified in $MDB and
978     returns the contents.  The type of contents depends on the type of
979     the data.
980
981     If the data is of the @e plist @e type, this function returns a
982     pointer to @e plist.
983
984     If the database is of the @e chartable @e type, it returns a
985     chartable.  The default value of the chartable is set according to
986     the second tag of the data as below:
987
988     @li If the tag is #Msymbol, the default value is #Mnil.
989     @li If the tag is #Minteger, the default value is -1.
990     @li Otherwise, the default value is @c NULL.
991
992     If the data is of the @e charset @e type, it returns a plist of length 2
993     (keys are both #Mt).  The value of the first element is an array
994     of integers that maps code points to the corresponding character
995     codes.  The value of the second element is a chartable of integers
996     that does the reverse mapping.  The charset must be defined in
997     advance.  */
998
999
1000 /***ja
1001     @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿¤ò¥í¡¼¥É¤¹¤ë.
1002
1003     ´Ø¿ô mdatabase_load () ¤Ï $MDB 
1004     ¤¬»Ø¤¹¥Ç¡¼¥¿¤ò¥í¡¼¥É¤·¡¢¤½¤ÎÃæ¿È¤òÊÖ¤¹¡£ÊÖ¤µ¤ì¤ë¤â¤Î¤Ï¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ°Û¤Ê¤ë¡£
1005
1006     ¥Ç¡¼¥¿¤¬ @e plist¥¿¥¤¥× ¤Ê¤é¤Ð¡¢ @e plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1007
1008     ¥Ç¡¼¥¿¤¬ @e chartable¥¿¥¤¥× ¤Ê¤é¤Ðʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£
1009     Ê¸»ú¥Æ¡¼¥Ö¥ë¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤϡ¢¥Ç¡¼¥¿¤ÎÂè2¥¿¥°¤Ë¤è¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Ë·è¤Þ¤ë¡£
1010
1011     @li ¥¿¥°¤¬ #Msymbol ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ#Mnil
1012     @li ¥¿¥°¤¬ #Minteger ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ-1
1013     @li ¤½¤ì°Ê³°¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ@c NULL
1014
1015     ¥Ç¡¼¥¿¤¬ @e charset¥¿¥¤¥× ¤Ê¤é¤ÐŤµ 2 ¤Î plist ¤òÊÖ¤¹¡Ê¥­¡¼¤Ï¶¦¤Ë#Mt ¡Ë¡£
1016     ºÇ½é¤ÎÍ×ÁǤÎÃͤϥ³¡¼¥É¥Ý¥¤¥ó¥È¤òÂбþ¤¹¤ëʸ»ú¥³¡¼¥É¤Ë¥Þ¥Ã¥×¤¹¤ëÀ°¿ô¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1017     £²ÈÖÌܤÎÍ×ÁǤÎÃͤϵդΥޥåפò¤¹¤ëʸ»ú¥Æ¡¼¥Ö¥ë¤Ç¤¢¤ë¡£
1018     ¤³¤Îʸ»ú¥»¥Ã¥È¤Ïͽ¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
1019
1020     @latexonly \IPAlabel{mdatabase_load} @endlatexonly
1021   */
1022
1023 /***
1024     @seealso
1025     mdatabase_load (),  mdatabase_define ()  */
1026
1027 void *
1028 mdatabase_load (MDatabase *mdb)
1029 {
1030   int mdebug_mask = MDEBUG_DATABASE;
1031   char buf[256];
1032
1033   MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
1034                  gen_database_name (buf, mdb->tag));
1035   return (*mdb->loader) (mdb->tag, mdb->extra_info);
1036 }
1037
1038 /*=*/
1039 /***en
1040     @brief Get tags of a data.
1041
1042     The mdatabase_tag () function returns an array of tags (symbols)
1043     that identify the data in $MDB.  The length of the array is
1044     four.  */
1045
1046 /***ja
1047     @brief ¥Ç¡¼¥¿¤Î¥¿¥°¤òÆÀ¤ë.
1048
1049     ´Ø¿ô mdatabase_tag () ¤Ï¡¢¥Ç¡¼¥¿ $MDB ¤Î¥¿¥°¡Ê¥·¥ó¥Ü¥ë¡Ë¤ÎÇÛÎó¤òÊÖ¤¹¡£ÇÛÎó¤ÎŤµ¤Ï
1050     4 ¤Ç¤¢¤ë¡£
1051
1052     @latexonly \IPAlabel{mdatabase_tag} @endlatexonly  */
1053
1054 MSymbol *
1055 mdatabase_tag (MDatabase *mdb)
1056 {
1057   return mdb->tag;
1058 }
1059
1060 /*** @} */
1061
1062 /*
1063   Local Variables:
1064   coding: euc-japan
1065   End:
1066 */