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