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