*** empty log message ***
[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; TAG1, TAG2, TAG3, TAG4.
32     Each tag must be a symbol.
33
34     TAG1 specifies the type of data stored in the database as below.
35
36     <ul>
37
38     <li> If TAG1 is #Mchar_table, the data is of the @e chartable @e
39     type and provides information about each character.  In this case,
40     TAG2 specifies the type of the information and must be #Msymbol,
41     #Minteger, #Mstring, #Mtext, or #Mplist.  TAG3 and TAG4 can be any
42     symbols.
43
44     <li> If TAG1 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, TAG2 must be a symbol representing a charset.  TAG3 and TAG4
47     can be any symbols.
48
49     <li> If TAG1 is neither #Mchar_table nor #Mcharset, the data is of
50     the @e plist @e type.  See the documentation of the mdatabase_load
51     () function for the details.  In this case, TAG2, TAG3, and TAG4
52     can be any symbols.
53
54     </ul>
55
56     Below, the notation \<TAG1, TAG2, TAG3, TAG4\> means a data with
57     those tags.
58
59     Application programs first calls the mdatabase_find () function to
60     get a pointer to an object of the type #MDatabase.  That object
61     holds information about the specified data.  When it is
62     successfully returned, the mdatabase_load () function loads the
63     data.  The implementation of the structure #MDatabase is
64     concealed from application programs.
65 */
66
67 /***ja
68     @addtogroup m17nDatabase
69     @brief ¸À¸ì¾ðÊó¥Ù¡¼¥¹¤Ë¤È¤½¤ì¤Ë´Ø¤¹¤ë API
70
71     m17n ¥é¥¤¥Ö¥é¥ê¤ÏɬÍפ˱þ¤¸¤ÆưŪ¤Ë m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿
72     ¤ò¼èÆÀ¤¹¤ë¡£¤Þ¤¿¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤âÆȼ«¤Î¥Ç¡¼¥¿¤ò m17n 
73     ¸À¸ì¾ðÊó¥Ù¡¼¥¹¤ËÄɲä·¡¢¤½¤ì¤òưŪ¤Ë¼èÆÀ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£m17n ¸À
74     ¸ì¾ðÊó¥Ù¡¼¥¹¤ÏÊ£¿ô¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¤Ê¤ê¡¢³Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ï£´¤Ä¤Î¥¿
75     ¥° TAG1, TAG2, TAG3, TAG4¡Ê¤¹¤Ù¤Æ¥·¥ó¥Ü¥ë¡Ë¤Ë¤è¤Ã¤Æ¼±Ê̤µ¤ì¤ë¡£
76
77     TAG1 ¤Ï¥Ç¡¼¥¿¥Ù¡¼¥¹Æâ¤Î¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤ò¼¨¤¹¡£
78
79     TAG1 ¤¬ #Mchar_table ¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ï @e chartable¥¿¥¤¥× ¤È¸Æ¤Ð¤ì¡¢
80     ³Æʸ»ú¤Ë´Ø¤¹¤ë¾ðÊó¤òÄ󶡤¹¤ë¡£¤³¤Î¾ì¹ç TAG2 ¤Ï¾ðÊó¤Î¼ïÎà¤ò»ØÄꤹ¤ë
81     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢°Ê²¼¤Î¤¤¤º¤ì¤«¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
82
83     @li #Msymbol @li #Minteger @li #Mstring @li #Mtext @li #Mplist
84
85     TAG3 ¤È TAG4 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
86
87     TAG1 ¤¬ #Mcharset ¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ï @e charset¥¿¥¤¥× ¤È¸Æ¤Ð¤ì¡¢Ê¸
88     »ú¥»¥Ã¥ÈÍѤΥǥ³¡¼¥É¡¿¥¨¥ó¥³¡¼¥É¥Þ¥Ã¥×¤òÄ󶡤¹¤ë¡£¤³¤Î¾ì¹ç TAG2 ¤Ï
89     Ê¸»ú¥»¥Ã¥È¤Î¥·¥ó¥Ü¥ë¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£TAG3 ¤È TAG4 ¤ÏǤ°Õ¤Î¥·¥ó
90     ¥Ü¥ë¤Ç¤è¤¤¡£
91
92     TAG1 ¤¬ #Mchar_table ¤Ç¤â #Mcharset ¤Ç¤â¤Ê¤¤¾ì¹ç¡¢¤½¤Î¥Ç¡¼¥¿¥Ù¡¼
93     ¥¹¤Ï @e plist ¥¿¥¤¥× ¤È¸Æ¤Ð¤ì¤ë¡£¾ÜºÙ¤Ë´Ø¤·¤Æ¤Ï´Ø¿ô mdatabase_load
94     () ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£¤³¤Î¾ì¹ç TAG2¡¢TAG3¡¢TAG4 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë
95     ¤Ç¤è¤¤¡£
96
97     °Ê²¼¡¢ÆÃÄê¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò \<TAG1, TAG2, TAG3, TAG4\> ¤È¤¤
98     ¤¦·Á¼°¤Çɽ¤ï¤¹¡£
99
100     ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¡¢¤Þ¤º´Ø¿ô mdatabase_find () »È¤Ã¤Æ¥Ç¡¼
101     ¥¿¥Ù¡¼¥¹¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÝ»ý¤¹¤ë¥ª¥Ö¥¸¥§¥¯¥È¡Ê#MDatabase ·¿¡Ë¤Ø¤Î
102     ¥Ý¥¤¥ó¥¿¤òÆÀ¤ë¡£¤½¤ì¤ËÀ®¸ù¤·¤¿¤é¡¢ mdatabase_load () ¤Ë¤è¤Ã¤Æ¼ÂºÝ
103     ¤Ë¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¥í¡¼¥É¤¹¤ë¡£¹½Â¤ÂΠ#MDatabase ¼«¿È¤¬¤É¤¦¼ÂÁõ¤µ¤ì
104     ¤Æ¤¤¤ë¤«¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤«¤é¤Ï¸«¤¨¤Ê¤¤¡£
105
106     @latexonly \IPAlabel{database} @endlatexonly
107 */
108
109 /*=*/
110
111 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
112 /*** @addtogroup m17nInternal
113      @{ */
114
115 #include <config.h>
116 #include <stdio.h>
117 #include <stdlib.h>
118 #include <string.h>
119 #include <ctype.h>
120 #include <sys/types.h>
121 #include <sys/stat.h>
122 #include <unistd.h>
123 #include <limits.h>
124
125 #include "m17n.h"
126 #include "m17n-misc.h"
127 #include "internal.h"
128 #include "mtext.h"
129 #include "character.h"
130 #include "charset.h"
131 #include "database.h"
132 #include "coding.h"
133 #include "plist.h"
134
135 /** The file containing a list of databases.  */
136 #define MDB_DIR "mdb.dir"
137 #define MDB_DIR_LEN 8
138
139 /** List of database directories.  */ 
140 static MPlist *mdb_dir_list;
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 < 0)
255         goto label_error;
256
257       while (buf[i] && isspace ((unsigned) buf[i])) i++;
258       c = buf[i];
259       if (!c)
260         break;
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           if (! strcmp (buf + i, "nil"))
300             val = (void *) Mnil;
301           else
302             val = (void *) msymbol (buf + i);
303         }
304       else if (type == Mplist)
305         {
306           val = (void *) mplist__from_string ((unsigned char *) buf + i,
307                                               strlen (buf + i));
308         }
309       else
310         val = NULL;
311
312       if (from == to)
313         mchartable_set (table, from, val);
314       else
315         mchartable_set_range (table, from, to, val);
316     }
317   return table;
318
319  label_error:
320   M17N_OBJECT_UNREF (table);
321   MERROR (MERROR_DB, NULL);
322 }
323
324
325 /** Load a data of type @c charset from the file FD.  */
326
327 static void *
328 load_charset (FILE *fp, MSymbol charset_name)
329 {
330   MCharset *charset = MCHARSET (charset_name);
331   int *decoder;
332   MCharTable *encoder;
333   int size;
334   int i, c;
335   int found = 0;
336   MPlist *plist;
337
338   if (! charset)
339     MERROR (MERROR_DB, NULL);
340   size = (charset->code_range[15]
341           - (charset->min_code - charset->code_range_min_code));
342   MTABLE_MALLOC (decoder, size, MERROR_DB);
343   for (i = 0; i < size; i++)
344     decoder[i] = -1;
345   encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
346
347   while ((c = getc (fp)) != EOF)
348     {
349       unsigned code1, code2, c1, c2;
350       int idx1, idx2;
351       char buf[256];
352
353       ungetc (c, fp);
354       fgets (buf, 256, fp);
355       if (c != '#')
356         {
357           if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
358             {
359               idx1 = CODE_POINT_TO_INDEX (charset, code1);
360               if (idx1 >= size)
361                 continue;
362               idx2 = CODE_POINT_TO_INDEX (charset, code2);
363               if (idx2 >= size)
364                 idx2 = size - 1;
365               c2 = c1 + (idx2 - idx1);
366             }
367           else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
368             {
369               idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
370               if (idx1 >= size)
371                 continue;
372               c2 = c1;
373             }
374           else
375             continue;
376           if (idx1 >= 0 && idx2 >= 0)
377             {
378               decoder[idx1] = c1;
379               mchartable_set (encoder, c1, (void *) code1);
380               for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
381                 {
382                   code1 = INDEX_TO_CODE_POINT (charset, idx1);
383                   decoder[idx1] = c1;
384                   mchartable_set (encoder, c1, (void *) code1);
385                 }
386               found++;
387             }
388         }
389     }
390
391   if (! found)
392     {
393       free (decoder);
394       M17N_OBJECT_UNREF (encoder);
395       return NULL;
396     }
397   plist = mplist ();
398   mplist_add (plist, Mt, decoder);
399   mplist_add (plist, Mt, encoder);
400   return plist;
401 }
402
403 static char *
404 gen_database_name (char *buf, MSymbol *tags)
405 {
406   int i;
407
408   strcpy (buf, msymbol_name (tags[0]));
409   for (i = 1; i < 4; i++)
410     {
411       strcat (buf, ", ");
412       strcat (buf, msymbol_name (tags[i]));
413     }
414   return buf;
415 }
416
417 static void *
418 load_database (MSymbol *tags, void *extra_info)
419 {
420   FILE *fp;
421   char *filename = (char *) extra_info;
422   void *value;
423
424   if (filename[0] == '/')
425     fp = fopen (filename, "r");
426   else
427     {
428       MPlist *plist;
429       char path[PATH_MAX];
430
431       MPLIST_DO (plist, mdb_dir_list)
432         {
433           strcpy (path, (char *) MPLIST_VAL (plist));
434           strcat (path, filename);
435           fp = fopen (path, "r");
436           if (fp)
437             break;
438         }
439     }
440   if (! fp)
441     MERROR (MERROR_DB, NULL);
442
443   if (tags[0] == Mchar_table)
444     value = load_chartable (fp, tags[1]);
445   else if (tags[0] == Mcharset)
446     value = load_charset (fp, tags[1]);
447   else
448     value = mplist__from_file (fp);
449   fclose (fp);
450
451   if (! value)
452     MERROR (MERROR_DB, NULL);
453   return value;
454 }
455
456
457 /** Copy DIRNAME to a newly allocated memory and return it.  If
458     DIRNAME does not end with a slash, append a slash to the new memory.  */
459
460 static char *
461 duplicate_dirname (char *dirname)
462 {
463   struct stat buf;
464   int len;
465   char *str;
466
467   if (! dirname
468       || stat (dirname, &buf) < 0)
469     return NULL;
470
471   len = strlen (dirname);
472   MTABLE_MALLOC (str, len + 2, MERROR_DB);
473   memcpy (str, dirname, len + 1);
474   if (str[len - 1] != '/')
475     {
476       str[len] = '/';
477       str[len + 1] = '\0';
478     }
479   return str;
480 }
481
482 \f
483 /* Internal API */
484
485 int
486 mdatabase__init ()
487 {
488   char *dir;
489   int i;
490   MPlist *plist;
491   FILE *fp;
492
493   Mchar_table = msymbol ("char-table");
494
495   mdb_dir_list = mplist ();
496   /** The macro M17NDIR specifies a directory where the system-wide
497     MDB_DIR file exists.  */
498   if ((dir = duplicate_dirname (M17NDIR)))
499     mplist_set (mdb_dir_list, Mt, dir);
500
501   /* The variable mdatabase_dir specifies a directory where an
502      application program specific MDB_DIR file exists.  */
503   if ((dir = duplicate_dirname (mdatabase_dir)))
504     mplist_push (mdb_dir_list, Mt, dir);
505
506   /* The environment variable M17NDIR (if non-NULL) specifies a
507      directory where a user specific MDB_DIR file exists.  */
508   if ((dir = duplicate_dirname (getenv ("M17NDIR"))))
509     mplist_push (mdb_dir_list, Mt, dir);
510
511   MLIST_INIT1 (&mdb_list, mdbs, 256);
512   MPLIST_DO (plist, mdb_dir_list)
513     {
514       MPlist *pl, *p;
515       int len;
516       char path[PATH_MAX];
517
518       dir = (char *) MPLIST_VAL (plist);
519       len = strlen (dir);
520       if (len + MDB_DIR_LEN >= PATH_MAX)
521         continue;
522       memcpy (path, dir, len);
523       memcpy (path + len, MDB_DIR, MDB_DIR_LEN);
524       if (! (fp = fopen (path, "r")))
525         continue;
526       pl = mplist__from_file (fp);
527       fclose (fp);
528       if (! pl)
529         continue;
530       MPLIST_DO (p, pl)
531         {
532           MDatabase mdb;
533           MPlist *p1;
534           int nbytes;
535
536           if (! MPLIST_PLIST_P (p))
537             continue;
538           for (i = 0, p1 = MPLIST_PLIST (p);
539                i < 4 && MPLIST_KEY (p1) == Msymbol;
540                i++, p1 = MPLIST_NEXT (p1))
541             mdb.tag[i] = MPLIST_SYMBOL (p1);
542           if (i == 0
543               || ! MPLIST_MTEXT_P (p1))
544             continue;
545           for (; i < 4; i++)
546             mdb.tag[i] = Mnil;
547           if (mdatabase_find (mdb.tag[0], mdb.tag[1],
548                               mdb.tag[2], mdb.tag[3]))
549             continue;
550
551           mdb.loader = load_database;
552           nbytes = mconv_encode_buffer (Mcoding_utf_8,  MPLIST_MTEXT (p1),
553                                         (unsigned char *) path, PATH_MAX);
554           if (nbytes < 0 || nbytes >= PATH_MAX)
555             continue;
556           path[nbytes++] = '\0';
557           mdb.extra_info = (void *) strdup (path);
558           MLIST_APPEND1 (&mdb_list, mdbs, mdb, MERROR_DB);
559         }
560       M17N_OBJECT_UNREF (pl);
561     }
562
563   mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
564                        mdatabase_find);
565   mdatabase__loader = (void *(*) (void *)) mdatabase_load;
566
567   return 0;
568 }
569
570 void
571 mdatabase__fini (void)
572 {
573   int i;
574   MPlist *plist; 
575
576   MPLIST_DO (plist, mdb_dir_list)
577     free (MPLIST_VAL (plist));
578   M17N_OBJECT_UNREF (mdb_dir_list);
579
580   for (i = 0; i < mdb_list.used; i++)
581     {
582       MDatabase *mdb = mdb_list.mdbs + i;
583
584       if (mdb->loader == load_database)
585         free (mdb->extra_info);
586     }
587   MLIST_FREE1 (&mdb_list, mdbs);
588 }
589
590 /*** @} */
591 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
592
593 \f
594 /* External API */
595
596 /*** @addtogroup m17nDatabase */
597 /*** @{ */
598
599 /*=*/
600 /***en
601     @brief Directory for application specific data.
602
603     If an application program wants to provide a data specific to the
604     program or a data overriding what supplied by the m17n database,
605     it must set this variable to a name of directory that contains the
606     data files before it calls the macro M17N_INIT ().  The directory
607     may contain a file "mdb.dir" which contains a list of data
608     definitions in the format described in @ref mdbDir "mdbDir(5)".
609
610     The default value is NULL.  */
611
612 char *mdatabase_dir;
613
614 /*=*/
615 /***en
616     @brief Look for a data in the database.
617
618     The mdatabase_find () function searches the m17n database for a
619     data who has tags $TAG1 through $TAG4, and returns a pointer to
620     the data.  If such a database is not found, it returns @c
621     NULL.  */
622
623 /***ja
624     @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤òõ¤¹
625
626     ´Ø¿ô mdatabase_find () ¤Ï¡¢ m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ãæ¤Ç $TAG1 ¤«¤é 
627     $TAG4 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¥Ù¡¼¥¹¤òõ¤·¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
628     ¤½¤Î¤è¤¦¤Ê¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
629
630     @latexonly \IPAlabel{mdatabase_find} @endlatexonly  */
631
632 MDatabase *
633 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
634 {
635   int i;
636
637   for (i = 0; i < mdb_list.used; i++)
638     {
639       MDatabase *mdb = mdb_list.mdbs + i;
640
641       if (tag0 == mdb->tag[0]
642           && tag1 == mdb->tag[1]
643           && tag2 == mdb->tag[2]
644           && tag3 == mdb->tag[3])
645         return mdb;
646     }
647   return NULL;
648 }
649
650 /*=*/
651 /***en
652     @brief Return a data list of the m17n database.
653
654     The mdatabase_list () function searches the m17n database for data
655     who have tags $TAG1 through $TAG4, and returns their list by a
656     plist.  The value #Mnil in $TAGn means a wild card that matches
657     any tag.  Each element of the plist has key #Mt and value a
658     pointer to type #MDatabase.  */
659
660 MPlist *
661 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
662 {
663   int i;
664   MPlist *plist = NULL, *pl;
665
666   for (i = 0; i < mdb_list.used; i++)
667     {
668       MDatabase *mdb = mdb_list.mdbs + i;
669
670       if ((tag0 == Mnil || tag0 == mdb->tag[0])
671           && (tag1 == Mnil || tag1 == mdb->tag[1])
672           && (tag2 == Mnil || tag2 == mdb->tag[2])
673           && (tag3 == Mnil || tag3 == mdb->tag[3]))
674         {
675           if (! plist)
676             plist = pl = mplist ();
677           pl = mplist_add (pl, Mt, mdb);
678         }
679     }
680   return plist;
681 }
682
683
684
685 /*=*/
686 /***en
687     @brief Define a data of the m17n database.
688
689     The mdatabase_define () function defines a data that has tags
690     $TAG1 through $TAG4 and additional information $EXTRA_INFO.
691
692     $LOADER is a pointer to a function that loads the data from the
693     database.  This function is called from the mdatabase_load ()
694     function with the two arguments $TAGS and $EXTRA_INFO.  Here,
695     $TAGS is the array of $TAG1 through $TAG4.
696
697     If $LOADER is @c NULL, the default loader of the m17n library is
698     used.  In this case, $EXTRA_INFO must be a string specifying a
699     filename that contains the data.
700
701     @return
702     If the operation was successful, mdatabase_define () returns a
703     pointer to the defined data, which can be used as an argument to
704     mdatabase_load ().  Otherwise, it returns @c NULL.  */
705
706 /***ja
707     @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÄêµÁ¤¹¤ë
708
709     ´Ø¿ô mdatabase_define () ¤Ï $TAG1 ¤«¤é $TAG4 ¤Þ¤Ç¤Î¥¿¥°¤ª¤è¤ÓÉÕ²Ã
710     ¾ðÊó $EXTRA_INFO ¤ò»ý¤Ä¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÄêµÁ¤¹¤ë¡£
711
712     $LOADER ¤Ï¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥í¡¼¥É¤ËÍѤ¤¤é¤ì¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢
713     ¤ë¡£¤³¤Î´Ø¿ô¤Ï mdatabase_load () ¤«¤é $MDB ¤È $EXTRA_INFO ¤È¤¤¤¦2 
714     ¤Ä¤Î°ú¿ôÉÕ¤­¤Ç¸Æ¤Ó½Ð¤µ¤ì¤ë¡£¤³¤³¤Ç $MDB ¤Ï mdatabase_load () ¤ËÅÏ
715     ¤µ¤ì¤¿°ú¿ô¤Ç¤¢¤ë¡£
716
717     ¤â¤· $LOADER ¤¬ @c NULL ¤Ê¤é¡¢m17n ¥é¥¤¥Ö¥é¥êɸ½à¤Î¥í¡¼¥À¤¬»È¤ï¤ì
718     ¤ë¡£¤³¤Î¥í¡¼¥À¤Ï¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò $EXTRA_INFO ¤Ë»ØÄꤵ¤ì¤¿Ì¾Á°¤Î¥Õ¥¡
719     ¥¤¥ë¤«¤é¥í¡¼¥É¤¹¤ë¡£
720
721     @return
722     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mdatabase_define () ¤ÏÄêµÁ¤µ¤ì¤¿¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î
723     ¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
724
725     @latexonly \IPAlabel{mdatabase_define} @endlatexonly  */
726
727 /***
728     @seealso
729     mdatabase_load (),  mdatabase_define ()  */
730
731 MDatabase *
732 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
733                   void *(*loader) (MSymbol *, void *),
734                   void *extra_info)
735 {
736   MDatabase *mdb;
737
738   mdb = mdatabase_find (tag0, tag1, tag2, tag3);
739   if (! mdb)
740     {
741       MDatabase template;
742
743       template.tag[0] = tag0, template.tag[1] = tag1;
744       template.tag[2] = tag2, template.tag[3] = tag3;
745       MLIST_APPEND1 (&mdb_list, mdbs, template, MERROR_DB);
746       mdb = mdb_list.mdbs + (mdb_list.used - 1);
747     }
748   mdb->loader = loader ? loader : load_database;
749   mdb->extra_info = extra_info;
750   if (mdb->loader == load_database)
751     mdb->extra_info = strdup ((char *) extra_info);
752   return (&(mdb_list.mdbs[mdb_list.used - 1]));
753 }
754
755 /*=*/
756 /***en
757     @brief Load a data from the database.
758
759     The mdatabase_load () function loads a data specified in $MDB and
760     returns the contents.  The type of contents depends on the type of
761     the data.
762
763     If the data is of the @e plist type, this function returns a
764     pointer to @e plist.
765
766     If the database is of the @e chartable type, it returns a
767     chartable.  The default value of the chartable is set according to
768     the second tag of the database as below:
769
770     <ul>
771
772     <li> If the tag is #Msymbol, the default value is #Mnil.
773     <li> If the tag is #Minteger, the default value is -1.
774     <li> Otherwise, the default value is @c NULL.
775
776     </ul>
777
778     If the data is of the charset type, it returns a plist of length 2
779     (keys are both #Mt).  The value of the first element is an array
780     of integers that maps code points to the corresponding character
781     codes.  The value of the second element is a chartable of integers
782     that does the reverse mapping.  The charset must be defined in
783     advance.  */
784
785
786 /***ja
787     @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¥í¡¼¥É¤¹¤ë
788
789     ´Ø¿ô mdatabase_load () ¤Ï $MDB ¤¬»Ø¤¹¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¥í¡¼¥É¤·¡¢¤½¤Î
790     Ãæ¿È¤òÊÖ¤¹¡£ÊÖ¤µ¤ì¤ë¤â¤Î¤Ï¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ°Û¤Ê¤ë¡£
791
792     ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ plist ¥¿¥¤¥×¤Ê¤é¤Ð¡¢ @e plist ¤òÊÖ¤¹¡£
793
794     ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ chartable ¥¿¥¤¥×¤Ê¤é¤Ðʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£Ê¸»ú
795     ¥Æ¡¼¥Ö¥ë¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤϡ¢Âè2¥¿¥°¤Ë¤è¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Ë·è¤Þ¤ë¡£
796
797     @li ¥¿¥°¤¬ #Msymbol ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ#Mnil
798     @li ¥¿¥°¤¬ #Minteger ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ-1
799     @li ¤½¤ì°Ê³°¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤϠ@c NULL
800
801     ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ charset ¥¿¥¤¥×¤Ê¤é¤ÐŤµ 2 ¤Î @c plist ¤òÊÖ¤¹¡Ê¥­¡¼
802     ¤Ï¶¦¤Ë #Mt ¡Ë¡£ºÇ½é¤ÎÍ×ÁǤÎÃͤϥ³¡¼¥É¥Ý¥¤¥ó¥È¤òʸ»ú¥³¡¼¥É¤Ë¥Þ¥Ã
803     ¥×¤¹¤ëÀ°¿ô¤ÎÇÛÎó¤Ç¤¢¤ë¡££²ÈÖÌܤÎÍ×ÁǤÎÃͤϤ½¤ÎµÕ¤Î¥Þ¥Ã¥×¤ò¤¹¤ëʸ»ú
804     ¥Æ¡¼¥Ö¥ë¤Ç¤¢¤ë¡£¤³¤Îʸ»ú¥»¥Ã¥È¤Ïͽ¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
805
806     @latexonly \IPAlabel{mdatabase_load} @endlatexonly
807   */
808
809 /***
810     @seealso
811     mdatabase_load (),  mdatabase_define ()  */
812
813 void *
814 mdatabase_load (MDatabase *mdb)
815 {
816   int mdebug_mask = MDEBUG_DATABASE;
817   char buf[256];
818
819   MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
820                  gen_database_name (buf, mdb->tag));
821   return (*mdb->loader) (mdb->tag, mdb->extra_info);
822 }
823
824 /*=*/
825 /***en
826     @brief Get tags of a data.
827
828     The mdatabase_tag () function returns an array of tags (symbols)
829     that identify the data in $MDB.  The length of the array is
830     four.  */
831
832 /***ja
833     @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥¿¥°¤òÆÀ¤ë
834
835     ´Ø¿ô mdatabase_tag () ¤Ï¡¢¥Ç¡¼¥¿¥Ù¡¼¥¹ $MDB ¤Î¥¿¥°¡Ê¥·¥ó¥Ü¥ë¡Ë¤ÎÇÛ
836     Îó¤òÊÖ¤¹¡£ÇÛÎó¤ÎŤµ¤Ï 4 ¤Ç¤¢¤ë¡£
837
838     @latexonly \IPAlabel{mdatabase_tag} @endlatexonly  */
839
840 MSymbol *
841 mdatabase_tag (MDatabase *mdb)
842 {
843   return mdb->tag;
844 }
845
846 /*** @} */
847
848 /*
849   Local Variables:
850   coding: euc-japan
851   End:
852 */