(load_chartable): Fix pursing of symbol name.
[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
123 #include "m17n.h"
124 #include "m17n-misc.h"
125 #include "internal.h"
126 #include "mtext.h"
127 #include "character.h"
128 #include "charset.h"
129 #include "database.h"
130 #include "coding.h"
131 #include "plist.h"
132
133 /** The file containing a list of databases.  */
134 #define MDB_DIR "mdb.dir"
135 #define MDB_DIR_LEN 8
136
137 /** Structure for a data in the m17n database.  */
138
139 struct MDatabase
140 {
141   /** Tags to identify the data.  <tag>[0] specifies the type of
142       database.  If it is #Mchar_table, the type is @e chartable, if
143       it is #Mcharset, the type is @e charset, otherwise the type is
144       @e plist.  */
145   MSymbol tag[4];
146
147   void *(*loader) (MSymbol *tags, void *extra_info);
148
149   /** The meaning of the value is dependent on <loader>.  If <loader>
150       is load_database (), the value is a string of the file name that
151       contains the data.  */
152   void *extra_info;
153 };
154
155 /** List of all data.  */
156 struct MDatabaseList
157 {
158   int size, inc, used;
159   MDatabase *mdbs;
160 };
161
162 static struct MDatabaseList mdb_list;
163
164
165 static int
166 read_number (char *buf, int *i)
167 {
168   int idx = *i;
169   int c = buf[idx++];
170   int n;
171
172   if (!c)
173     return -1;
174
175   while (c && isspace (c)) c = buf[idx++];
176
177   if (c == '0')
178     {
179       if (buf[idx] == 'x')
180         {
181           for (idx++, c = 0; (n = hex_mnemonic[(unsigned) buf[idx]]) < 16;
182                idx++)
183             c  = (c << 4) | n;
184           *i = idx;
185           return c;
186         }
187       c = 0;
188     }
189   else if (c == '\'')
190     {
191       c = buf[idx++];
192       if (c == '\\')
193         {
194           c = buf[idx++];
195           n = escape_mnemonic[c];
196           if (n != 255)
197             c = n;
198         }
199       while (buf[idx] && buf[idx++] != '\'');
200       *i = idx;
201       return c;
202     }
203   else if (hex_mnemonic[c] < 10)
204     c -= '0';
205   else
206     return -1;
207
208   while ((n = hex_mnemonic[(unsigned) buf[idx]]) < 10)
209     c = (c * 10) + n, idx++;
210   *i = idx;
211   return c;
212 }
213
214
215 /** Load a data of type @c chartable from the file FD, and return the
216     newly created chartable.  */
217
218 static void *
219 load_chartable (FILE *fp, MSymbol type)
220 {
221   int c, from, to;
222   char buf[1024];
223   void *val;
224   MCharTable *table;
225
226   if (! fp)
227     MERROR (MERROR_DB, NULL);
228
229   table = mchartable (type, (type == Msymbol ? (void *) Mnil
230                              : type == Minteger ? (void *) -1
231                              : NULL));
232
233   while (! feof (fp))
234     {
235       int i, len;
236
237       for (len = 0; len < 1023 && (c = getc (fp)) != EOF && c != '\n'; len++)
238         buf[len] = c;
239       buf[len] = '\0';    
240       if (hex_mnemonic[(unsigned) buf[0]] >= 10)
241         /* skip comment/invalid line */
242         continue;
243       i = 0;
244       from = read_number (buf, &i);
245       if (buf[i] == '-')
246         i++, to = read_number (buf, &i);
247       else
248         to = from;
249       if (from < 0 || to < from)
250         continue;
251
252       while (buf[i] && isspace ((unsigned) buf[i])) i++;
253       c = buf[i];
254       if (!c)
255         continue;
256
257       if (type == Mstring)
258         {
259           /* VAL is a C-string.  */
260           if (! (val = strdup (buf + i)))
261             MEMORY_FULL (MERROR_DB);
262         }
263       else if (type == Minteger)
264         {
265           /* VAL is an integer.  */
266           int positive = 1;
267           int n;
268
269           if (c == '-')
270             i++, positive = -1;
271           n = read_number (buf, &i);
272           if (n < 0)
273             goto label_error;
274           val = (void *) (n * positive);
275         }
276       else if (type == Mtext)
277         {
278           /* VAL is an M-text.  */
279           MText *mt;
280           if (c == '"')
281             mt = mconv_decode_buffer (Mcoding_utf_8,
282                                       (unsigned char *) (buf + i),
283                                       len - i - 1);
284           else
285             {
286               mt = mtext ();
287               while ((c = read_number (buf, &i)) >= 0)
288                 mt = mtext_cat_char (mt, c);
289             }
290           val = (void *) mt;
291         }
292       else if (type == Msymbol)
293         {
294           char *p = buf + i;
295
296           while (! isspace (*p)) 
297             {
298               if (*p == '\\' || p[1] != '\0')
299                 {
300                   memmove (p, p + 1, buf + len - (p + 1));
301                   len--;
302                 }
303               p++;
304             }
305           *p = '\0';
306           if (! strcmp (buf + i, "nil"))
307             val = (void *) Mnil;
308           else
309             val = (void *) msymbol (buf + i);
310         }
311       else if (type == Mplist)
312         {
313           val = (void *) mplist__from_string ((unsigned char *) buf + i,
314                                               strlen (buf + i));
315         }
316       else
317         val = NULL;
318
319       if (from == to)
320         mchartable_set (table, from, val);
321       else
322         mchartable_set_range (table, from, to, val);
323     }
324   return table;
325
326  label_error:
327   M17N_OBJECT_UNREF (table);
328   MERROR (MERROR_DB, NULL);
329 }
330
331
332 /** Load a data of type @c charset from the file FD.  */
333
334 static void *
335 load_charset (FILE *fp, MSymbol charset_name)
336 {
337   MCharset *charset = MCHARSET (charset_name);
338   int *decoder;
339   MCharTable *encoder;
340   int size;
341   int i, c;
342   int found = 0;
343   MPlist *plist;
344
345   if (! charset)
346     MERROR (MERROR_DB, NULL);
347   size = (charset->code_range[15]
348           - (charset->min_code - charset->code_range_min_code));
349   MTABLE_MALLOC (decoder, size, MERROR_DB);
350   for (i = 0; i < size; i++)
351     decoder[i] = -1;
352   encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
353
354   while ((c = getc (fp)) != EOF)
355     {
356       unsigned code1, code2, c1, c2;
357       int idx1, idx2;
358       char buf[256];
359
360       ungetc (c, fp);
361       fgets (buf, 256, fp);
362       if (c != '#')
363         {
364           if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
365             {
366               idx1 = CODE_POINT_TO_INDEX (charset, code1);
367               if (idx1 >= size)
368                 continue;
369               idx2 = CODE_POINT_TO_INDEX (charset, code2);
370               if (idx2 >= size)
371                 idx2 = size - 1;
372               c2 = c1 + (idx2 - idx1);
373             }
374           else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
375             {
376               idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
377               if (idx1 >= size)
378                 continue;
379               c2 = c1;
380             }
381           else
382             continue;
383           if (idx1 >= 0 && idx2 >= 0)
384             {
385               decoder[idx1] = c1;
386               mchartable_set (encoder, c1, (void *) code1);
387               for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
388                 {
389                   code1 = INDEX_TO_CODE_POINT (charset, idx1);
390                   decoder[idx1] = c1;
391                   mchartable_set (encoder, c1, (void *) code1);
392                 }
393               found++;
394             }
395         }
396     }
397
398   if (! found)
399     {
400       free (decoder);
401       M17N_OBJECT_UNREF (encoder);
402       return NULL;
403     }
404   plist = mplist ();
405   mplist_add (plist, Mt, decoder);
406   mplist_add (plist, Mt, encoder);
407   return plist;
408 }
409
410 static char *
411 gen_database_name (char *buf, MSymbol *tags)
412 {
413   int i;
414
415   strcpy (buf, msymbol_name (tags[0]));
416   for (i = 1; i < 4; i++)
417     {
418       strcat (buf, ", ");
419       strcat (buf, msymbol_name (tags[i]));
420     }
421   return buf;
422 }
423
424 static FILE *
425 get_database_stream (char *filename)
426 {
427   FILE *fp = NULL;
428
429   if (filename[0] == '/')
430     fp = fopen (filename, "r");
431   else
432     {
433       MPlist *plist;
434       char path[PATH_MAX];
435
436       MPLIST_DO (plist, mdatabase__dir_list)
437         {
438           strcpy (path, (char *) MPLIST_VAL (plist));
439           strcat (path, filename);
440           fp = fopen (path, "r");
441           if (fp)
442             break;
443         }
444     }
445   return fp;
446 }
447
448 static void *
449 load_database (MSymbol *tags, void *extra_info)
450 {
451   FILE *fp = get_database_stream ((char *) extra_info);
452   void *value;
453
454   if (! fp)
455     MERROR (MERROR_DB, NULL);
456
457   if (tags[0] == Mchar_table)
458     value = load_chartable (fp, tags[1]);
459   else if (tags[0] == Mcharset)
460     value = load_charset (fp, tags[1]);
461   else
462     value = mplist__from_file (fp, NULL);
463   fclose (fp);
464
465   if (! value)
466     MERROR (MERROR_DB, NULL);
467   return value;
468 }
469
470
471 /** Copy DIRNAME to a newly allocated memory and return it.  If
472     DIRNAME does not end with a slash, append a slash to the new memory.  */
473
474 static char *
475 duplicate_dirname (char *dirname)
476 {
477   struct stat buf;
478   int len;
479   char *str;
480
481   if (! dirname
482       || stat (dirname, &buf) < 0)
483     return NULL;
484
485   len = strlen (dirname);
486   MTABLE_MALLOC (str, len + 2, MERROR_DB);
487   memcpy (str, dirname, len + 1);
488   if (str[len - 1] != '/')
489     {
490       str[len] = '/';
491       str[len + 1] = '\0';
492     }
493   return str;
494 }
495
496 \f
497 /* Internal API */
498
499 /** List of database directories.  */ 
500 MPlist *mdatabase__dir_list;
501
502 MSymbol M_database_hook;
503
504 int
505 mdatabase__init ()
506 {
507   char *dir;
508   int i;
509   MPlist *plist;
510   FILE *fp;
511
512   Mchar_table = msymbol ("char-table");
513   M_database_hook = msymbol ("  database-hook");
514
515   mdatabase__dir_list = mplist ();
516   /** The macro M17NDIR specifies a directory where the system-wide
517     MDB_DIR file exists.  */
518   if ((dir = duplicate_dirname (M17NDIR)))
519     mplist_set (mdatabase__dir_list, Mt, dir);
520
521   /* The variable mdatabase_dir specifies a directory where an
522      application program specific MDB_DIR file exists.  */
523   if ((dir = duplicate_dirname (mdatabase_dir)))
524     mplist_push (mdatabase__dir_list, Mt, dir);
525
526   /* The environment variable M17NDIR (if non-NULL) specifies a
527      directory where a user specific MDB_DIR file exists.  */
528   if ((dir = duplicate_dirname (getenv ("M17NDIR"))))
529     mplist_push (mdatabase__dir_list, Mt, dir);
530
531   MLIST_INIT1 (&mdb_list, mdbs, 256);
532   MPLIST_DO (plist, mdatabase__dir_list)
533     {
534       MPlist *pl, *p;
535       int len;
536       char path[PATH_MAX];
537
538       dir = (char *) MPLIST_VAL (plist);
539       len = strlen (dir);
540       if (len + MDB_DIR_LEN >= PATH_MAX)
541         continue;
542       memcpy (path, dir, len);
543       memcpy (path + len, MDB_DIR, MDB_DIR_LEN);
544       if (! (fp = fopen (path, "r")))
545         continue;
546       pl = mplist__from_file (fp, NULL);
547       fclose (fp);
548       if (! pl)
549         continue;
550       MPLIST_DO (p, pl)
551         {
552           MDatabase mdb;
553           MPlist *p1;
554           int nbytes;
555
556           if (! MPLIST_PLIST_P (p))
557             continue;
558           for (i = 0, p1 = MPLIST_PLIST (p);
559                i < 4 && MPLIST_KEY (p1) == Msymbol;
560                i++, p1 = MPLIST_NEXT (p1))
561             mdb.tag[i] = MPLIST_SYMBOL (p1);
562           if (i == 0
563               || ! MPLIST_MTEXT_P (p1))
564             continue;
565           for (; i < 4; i++)
566             mdb.tag[i] = Mnil;
567           if (mdatabase_find (mdb.tag[0], mdb.tag[1],
568                               mdb.tag[2], mdb.tag[3]))
569             continue;
570
571           mdb.loader = load_database;
572           nbytes = mconv_encode_buffer (Mcoding_utf_8,  MPLIST_MTEXT (p1),
573                                         (unsigned char *) path, PATH_MAX);
574           if (nbytes < 0 || nbytes >= PATH_MAX)
575             continue;
576           path[nbytes++] = '\0';
577           mdb.extra_info = (void *) strdup (path);
578           MLIST_APPEND1 (&mdb_list, mdbs, mdb, MERROR_DB);
579         }
580       M17N_OBJECT_UNREF (pl);
581     }
582
583   mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
584                        mdatabase_find);
585   mdatabase__loader = (void *(*) (void *)) mdatabase_load;
586
587   return 0;
588 }
589
590 void
591 mdatabase__fini (void)
592 {
593   int i;
594   MPlist *plist; 
595
596   MPLIST_DO (plist, mdatabase__dir_list)
597     free (MPLIST_VAL (plist));
598   M17N_OBJECT_UNREF (mdatabase__dir_list);
599
600   for (i = 0; i < mdb_list.used; i++)
601     {
602       MDatabase *mdb = mdb_list.mdbs + i;
603
604       if (mdb->loader == load_database)
605         free (mdb->extra_info);
606     }
607   MLIST_FREE1 (&mdb_list, mdbs);
608 }
609
610 MPlist *
611 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
612 {
613   int mdebug_mask = MDEBUG_DATABASE;
614   FILE *fp;
615   MPlist *plist;
616   char buf[256];
617
618   if (mdb->loader != load_database
619       || mdb->tag[0] == Mchar_table
620       || mdb->tag[0] == Mcharset)
621     MERROR (MERROR_DB, NULL);
622   MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
623                  gen_database_name (buf, mdb->tag));
624   fp = get_database_stream ((char *) mdb->extra_info);
625   if (! fp)
626     MERROR (MERROR_DB, NULL);
627   plist = mplist__from_file (fp, keys);
628   fclose (fp);
629   return plist;
630 }
631
632
633 /*** @} */
634 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
635
636 \f
637 /* External API */
638
639 /*** @addtogroup m17nDatabase */
640 /*** @{ */
641
642 /*=*/
643 /***en
644     @brief Directory for application specific data.
645
646     If an application program wants to provide a data specific to the
647     program or a data overriding what supplied by the m17n database,
648     it must set this variable to a name of directory that contains the
649     data files before it calls the macro M17N_INIT ().  The directory
650     may contain a file "mdb.dir" which contains a list of data
651     definitions in the format described in @ref mdbDir "mdbDir(5)".
652
653     The default value is NULL.  */
654 /***ja
655     @brief ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¸ÇÍ­¤Î¥Ç¡¼¥¿Íѥǥ£¥ì¥¯¥È¥ê.
656
657     ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬¡¢¤½¤Î¥×¥í¥°¥é¥à¸ÇÍ­¤Î¥Ç¡¼¥¿¤ä m17n 
658     ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¾å½ñ¤­¤¹¤ë¥Ç¡¼¥¿¤òÄ󶡤¹¤ë¾ì¹ç¤Ë¤Ï¡¢¥Þ¥¯¥í M17N_INIT () 
659     ¤ò¸Æ¤ÖÁ°¤Ë¤³¤ÎÊÑ¿ô¤ò¥Ç¡¼¥¿¥Õ¥¡¥¤¥ë¤ò´Þ¤à¥Ç¥£¥ì¥¯¥È¥ê̾¤Ë¥»¥Ã¥È¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤Ï
660     "mdb.dir" ¥Õ¥¡¥¤¥ë¤ò¤ª¤¯¤³¤È¤¬¤Ç¤­¤ë¡£¤½¤Î"mdb.dir"¥Õ¥¡¥¤¥ë¤Ë¤Ï¡¢ 
661     @ref mdbDir "mdbDir(5)" ¤ÇÀâÌÀ¤µ¤ì¤Æ¤¤¤ë¥Õ¥©¡¼¥Þ¥Ã¥È¤Ç¥Ç¡¼¥¿ÄêµÁ¤Î¥ê¥¹¥È¤òµ­½Ò¤¹¤ë¡£
662
663     ¥Ç¥Õ¥©¥ë¥È¤ÎÃͤϠNULL ¤Ç¤¢¤ë¡£  */
664
665 char *mdatabase_dir;
666
667 /*=*/
668 /***en
669     @brief Look for a data in the database.
670
671     The mdatabase_find () function searches the m17n database for a
672     data who has tags $TAG0 through $TAG3, and returns a pointer to
673     the data.  If such a data is not found, it returns @c NULL.  */
674
675 /***ja
676     @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹Ãæ¤Î¥Ç¡¼¥¿¤òõ¤¹.
677
678     ´Ø¿ô mdatabase_find () ¤Ï¡¢ m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ãæ¤Ç $TAG0 ¤«¤é 
679     $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤Î¤è¤¦¤Ê¥Ç¡¼¥¿¤¬¤Ê¤±¤ì¤Ð
680     @c NULL ¤òÊÖ¤¹¡£
681
682     @latexonly \IPAlabel{mdatabase_find} @endlatexonly  */
683
684 MDatabase *
685 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
686 {
687   int i;
688   MDatabaseHookFunc func
689     = (MDatabaseHookFunc) msymbol_get (tag0, M_database_hook);
690
691   if (func)
692     func (tag0, tag1, tag2, tag3);
693
694   for (i = 0; i < mdb_list.used; i++)
695     {
696       MDatabase *mdb = mdb_list.mdbs + i;
697
698       if (tag0 == mdb->tag[0]
699           && tag1 == mdb->tag[1]
700           && tag2 == mdb->tag[2]
701           && tag3 == mdb->tag[3])
702         return mdb;
703     }
704   return NULL;
705 }
706
707 /*=*/
708 /***en
709     @brief Return a data list of the m17n database.
710
711     The mdatabase_list () function searches the m17n database for data
712     who have tags $TAG0 through $TAG3, and returns their list by a
713     plist.  The value #Mnil in $TAGn means a wild card that matches
714     any tag.  Each element of the plist has key #Mt and value a
715     pointer to type #MDatabase.  */
716 /***ja
717     @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¥ê¥¹¥È¤òÊÖ¤¹.
718
719     ´Ø¿ô mdatabase_list () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é $TAG0 ¤«¤é$TAG3 
720     ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤Î¥ê¥¹¥È¤òplist ¤È¤·¤ÆÊÖ¤¹¡£ $TAGn ¤¬ #Mnil
721     ¤Ç¤¢¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥¿¥°¤Ë¥Þ¥Ã¥Á¤¹¤ë¥ï¥¤¥ë¥É¥«¡¼¥É¤È¤·¤Æ¼è¤ê°·¤ï¤ì¤ë¡£ÊÖ¤µ¤ì¤ë
722     plist ¤Î³ÆÍ×ÁǤϥ­¡¼ ¤È¤·¤Æ #Mt ¤ò¡¢ÃͤȤ·¤Æ #MDatabase ·¿¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò»ý¤Ä¡£  */
723
724
725 MPlist *
726 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
727 {
728   int i;
729   MPlist *plist = NULL, *pl;
730   MDatabaseHookFunc func
731     = (MDatabaseHookFunc) msymbol_get (tag0, M_database_hook);
732
733   if (func)
734     func (tag0, tag1, tag2, tag3);
735
736   for (i = 0; i < mdb_list.used; i++)
737     {
738       MDatabase *mdb = mdb_list.mdbs + i;
739
740       if ((tag0 == Mnil || tag0 == mdb->tag[0])
741           && (tag1 == Mnil || tag1 == mdb->tag[1])
742           && (tag2 == Mnil || tag2 == mdb->tag[2])
743           && (tag3 == Mnil || tag3 == mdb->tag[3]))
744         {
745           if (! plist)
746             plist = pl = mplist ();
747           pl = mplist_add (pl, Mt, mdb);
748         }
749     }
750   return plist;
751 }
752
753
754
755 /*=*/
756 /***en
757     @brief Define a data of the m17n database.
758
759     The mdatabase_define () function defines a data that has tags
760     $TAG0 through $TAG3 and additional information $EXTRA_INFO.
761
762     $LOADER is a pointer to a function that loads the data from the
763     database.  This function is called from the mdatabase_load ()
764     function with the two arguments $TAGS and $EXTRA_INFO.  Here,
765     $TAGS is the array of $TAG0 through $TAG3.
766
767     If $LOADER is @c NULL, the default loader of the m17n library is
768     used.  In this case, $EXTRA_INFO must be a string specifying a
769     filename that contains the data.
770
771     @return
772     If the operation was successful, mdatabase_define () returns a
773     pointer to the defined data, which can be used as an argument to
774     mdatabase_load ().  Otherwise, it returns @c NULL.  */
775
776 /***ja
777     @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë.
778
779     ´Ø¿ô mdatabase_define () ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ª¤è¤ÓÉղþðÊó 
780     $EXTRA_INFO ¤ò»ý¤Ä¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë¡£
781
782     $LOADER ¤Ï¤½¤Î¥Ç¡¼¥¿¤Î¥í¡¼¥É¤ËÍѤ¤¤é¤ì¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï
783     mdatabase_load () ¤«¤é $TAGS ¤È $EXTRA_INFO ¤È¤¤¤¦Æó¤Ä¤Î°ú¿ôÉÕ¤­¤Ç¸Æ¤Ó½Ð¤µ¤ì¤ë¡£¤³¤³¤Ç 
784     $TAGS ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤ÎÇÛÎó¤Ç¤¢¤ë¡£
785
786     ¤â¤· $LOADER ¤¬ @c NULL ¤Ê¤é¡¢m17n ¥é¥¤¥Ö¥é¥êɸ½à¤Î¥í¡¼¥À¤¬»È¤ï¤ì¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï
787     $EXTRA_INFO ¤Ï¥Ç¡¼¥¿¤ò´Þ¤à¥Õ¥¡¥¤¥ë̾¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
788
789     @return
790     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mdatabase_define () 
791     ¤ÏÄêµÁ¤µ¤ì¤¿¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¥Ý¥¤¥ó¥¿¤Ï´Ø¿ô mdatabase_load () 
792     ¤Î°ú¿ô¤È¤·¤ÆÍѤ¤¤ë¤³¤È¤¬¤Ç¤­¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
793
794     @latexonly \IPAlabel{mdatabase_define} @endlatexonly  */
795
796 /***
797     @seealso
798     mdatabase_load (),  mdatabase_define ()  */
799
800 MDatabase *
801 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
802                   void *(*loader) (MSymbol *, void *),
803                   void *extra_info)
804 {
805   MDatabase *mdb;
806   MDatabaseHookFunc func
807     = (MDatabaseHookFunc) msymbol_get (tag0, M_database_hook);
808
809   if (func)
810     func (tag0, tag1, tag2, tag3);
811
812   mdb = mdatabase_find (tag0, tag1, tag2, tag3);
813   if (! mdb)
814     {
815       MDatabase template;
816
817       template.tag[0] = tag0, template.tag[1] = tag1;
818       template.tag[2] = tag2, template.tag[3] = tag3;
819       template.extra_info = NULL;
820       MLIST_APPEND1 (&mdb_list, mdbs, template, MERROR_DB);
821       mdb = mdb_list.mdbs + (mdb_list.used - 1);
822     }
823   mdb->loader = loader ? loader : load_database;
824   if (mdb->loader == load_database)
825     {
826       if (mdb->extra_info)
827         free (mdb->extra_info);
828       mdb->extra_info = strdup ((char *) extra_info);
829     }
830   else
831     mdb->extra_info = extra_info;
832   return (&(mdb_list.mdbs[mdb_list.used - 1]));
833 }
834
835 /*=*/
836 /***en
837     @brief Load a data from the database.
838
839     The mdatabase_load () function loads a data specified in $MDB and
840     returns the contents.  The type of contents depends on the type of
841     the data.
842
843     If the data is of the @e plist @e type, this function returns a
844     pointer to @e plist.
845
846     If the database is of the @e chartable @e type, it returns a
847     chartable.  The default value of the chartable is set according to
848     the second tag of the data as below:
849
850     @li If the tag is #Msymbol, the default value is #Mnil.
851     @li If the tag is #Minteger, the default value is -1.
852     @li Otherwise, the default value is @c NULL.
853
854     If the data is of the @e charset @e type, it returns a plist of length 2
855     (keys are both #Mt).  The value of the first element is an array
856     of integers that maps code points to the corresponding character
857     codes.  The value of the second element is a chartable of integers
858     that does the reverse mapping.  The charset must be defined in
859     advance.  */
860
861
862 /***ja
863     @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿¤ò¥í¡¼¥É¤¹¤ë.
864
865     ´Ø¿ô mdatabase_load () ¤Ï $MDB 
866     ¤¬»Ø¤¹¥Ç¡¼¥¿¤ò¥í¡¼¥É¤·¡¢¤½¤ÎÃæ¿È¤òÊÖ¤¹¡£ÊÖ¤µ¤ì¤ë¤â¤Î¤Ï¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ°Û¤Ê¤ë¡£
867
868     ¥Ç¡¼¥¿¤¬ @e plist¥¿¥¤¥× ¤Ê¤é¤Ð¡¢ @e plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
869
870     ¥Ç¡¼¥¿¤¬ @e chartable¥¿¥¤¥× ¤Ê¤é¤Ðʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£
871     Ê¸»ú¥Æ¡¼¥Ö¥ë¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤϡ¢¥Ç¡¼¥¿¤ÎÂè2¥¿¥°¤Ë¤è¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Ë·è¤Þ¤ë¡£
872
873     @li ¥¿¥°¤¬ #Msymbol ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ#Mnil
874     @li ¥¿¥°¤¬ #Minteger ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ-1
875     @li ¤½¤ì°Ê³°¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ@c NULL
876
877     ¥Ç¡¼¥¿¤¬ @e charset¥¿¥¤¥× ¤Ê¤é¤ÐŤµ 2 ¤Î plist ¤òÊÖ¤¹¡Ê¥­¡¼¤Ï¶¦¤Ë#Mt ¡Ë¡£
878     ºÇ½é¤ÎÍ×ÁǤÎÃͤϥ³¡¼¥É¥Ý¥¤¥ó¥È¤òÂбþ¤¹¤ëʸ»ú¥³¡¼¥É¤Ë¥Þ¥Ã¥×¤¹¤ëÀ°¿ô¤ÎÇÛÎó¤Ç¤¢¤ë¡£
879     £²ÈÖÌܤÎÍ×ÁǤÎÃͤϵդΥޥåפò¤¹¤ëʸ»ú¥Æ¡¼¥Ö¥ë¤Ç¤¢¤ë¡£
880     ¤³¤Îʸ»ú¥»¥Ã¥È¤Ïͽ¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
881
882     @latexonly \IPAlabel{mdatabase_load} @endlatexonly
883   */
884
885 /***
886     @seealso
887     mdatabase_load (),  mdatabase_define ()  */
888
889 void *
890 mdatabase_load (MDatabase *mdb)
891 {
892   int mdebug_mask = MDEBUG_DATABASE;
893   char buf[256];
894
895   MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
896                  gen_database_name (buf, mdb->tag));
897   return (*mdb->loader) (mdb->tag, mdb->extra_info);
898 }
899
900 /*=*/
901 /***en
902     @brief Get tags of a data.
903
904     The mdatabase_tag () function returns an array of tags (symbols)
905     that identify the data in $MDB.  The length of the array is
906     four.  */
907
908 /***ja
909     @brief ¥Ç¡¼¥¿¤Î¥¿¥°¤òÆÀ¤ë.
910
911     ´Ø¿ô mdatabase_tag () ¤Ï¡¢¥Ç¡¼¥¿ $MDB ¤Î¥¿¥°¡Ê¥·¥ó¥Ü¥ë¡Ë¤ÎÇÛÎó¤òÊÖ¤¹¡£ÇÛÎó¤ÎŤµ¤Ï
912     4 ¤Ç¤¢¤ë¡£
913
914     @latexonly \IPAlabel{mdatabase_tag} @endlatexonly  */
915
916 MSymbol *
917 mdatabase_tag (MDatabase *mdb)
918 {
919   return mdb->tag;
920 }
921
922 /*** @} */
923
924 /*
925   Local Variables:
926   coding: euc-japan
927   End:
928 */