1 /* database.c -- database module.
2 Copyright (C) 2003, 2004
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
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.
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.
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
24 @addtogroup m17nDatabase
25 @brief The m17n database and API for it.
27 The m17n library acquires various kinds of information
28 from data in the <i> m17n database</i> on demand. Application
29 programs can also add/load their original data to/from the m17n
30 database by setting the variable #mdatabase_dir to an
31 application-specific directory and storing data in it. Users can
32 overwrite those data by storing preferable data in the directory
33 specified by the environment variable "M17NDIR", or if it is not
34 set, in the directory "~/.m17n.d".
36 The m17n database contains multiple heterogeneous data, and each
37 data is identified by four tags; TAG0, TAG1, TAG2, TAG3. Each tag
40 TAG0 specifies the type of data stored in the database as below.
43 If TAG0 is #Mchar_table, the data is of the @e chartable @e
44 type and provides information about each character. In this case,
45 TAG1 specifies the type of the information and must be #Msymbol,
46 #Minteger, #Mstring, #Mtext, or #Mplist. TAG2 and TAG3 can be any
50 If TAG0 is #Mcharset, the data is of the @e charset @e type
51 and provides a decode/encode mapping table for a charset. In this
52 case, TAG1 must be a symbol representing a charset. TAG2 and TAG3
56 If TAG0 is neither #Mchar_table nor #Mcharset, the data is of
57 the @e plist @e type. See the documentation of the
58 mdatabase_load () function for the details.
59 In this case, TAG1, TAG2, and TAG3 can be any symbols.
61 The notation \<TAG0, TAG1, TAG2, TAG3\> means a data with those
64 Application programs first calls the mdatabase_find () function to
65 get a pointer to an object of the type #MDatabase. That object
66 holds information about the specified data. When it is
67 successfully returned, the mdatabase_load () function loads the
68 data. The implementation of the structure #MDatabase is
69 concealed from application programs.
73 @addtogroup m17nDatabase
74 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤È¤½¤ì¤Ë´Ø¤¹¤ë API.
76 m17n ¥é¥¤¥Ö¥é¥ê¤ÏɬÍפ˱þ¤¸¤ÆưŪ¤Ë @e m17n @e ¥Ç¡¼¥¿¥Ù¡¼¥¹
77 ¤«¤é¾ðÊó¤ò¼èÆÀ¤¹¤ë¡£¤Þ¤¿¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤â¡¢Æȼ«¤Î¥Ç¡¼¥¿¤ò
78 m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÄɲä·¡¢¤½¤ì¤òưŪ¤Ë¼èÆÀ¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¡£
79 ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬Æȼ«¤Î¥Ç¡¼¥¿¤òÄɲᦼèÆÀ¤¹¤ë¤Ë¤Ï¡¢ÊÑ¿ô
80 #mdatabase_dir ¤Ë¤½¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¸ÇͤΥǥ£¥ì¥¯¥È¥ê¤ò¥»¥Ã¥È¤·¡¢
81 ¤½¤ÎÃæ¤Ë¥Ç¡¼¥¿¤ò³ÊǼ¤¹¤ë¡£¥æ¡¼¥¶¤¬¤½¤Î¥Ç¡¼¥¿¤ò¥ª¡¼¥Ð¡¼¥é¥¤¥È¤·¤¿¤¤
82 ¤È¤¤Ï¡¢´Ä¶ÊÑ¿ô "M17NDIR" ¤Ç»ØÄꤵ¤ì¤ë¥Ç¥£¥ì¥¯¥È¥ê¡Ê»ØÄꤵ¤ì¤Æ¤¤¤Ê
83 ¤¤¤È¤¤Ï "~/.m17n.d" ¤È¤¤¤¦¥Ç¥£¥ì¥¯¥È¥ê¡Ë¤ËÊ̤Υǡ¼¥¿¤òÃÖ¤¯¡£
86 ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤ÏÊ£¿ô¤Î¿Íͤʥǡ¼¥¿¤¬´Þ¤Þ¤ì¤Æ¤ª¤ê¡¢³Æ¥Ç¡¼¥¿¤Ï
87 TAG0, TAG1, TAG2, TAG3¡Ê¤¹¤Ù¤Æ¥·¥ó¥Ü¥ë¡Ë¤Î£´¤Ä¤Î¥¿¥°¤Ë¤è¤Ã¤Æ¼±Ê̤µ¤ì¤ë¡£
89 TAG0 ¤Ë¤è¤Ã¤Æ¡¢¥Ç¡¼¥¿¥Ù¡¼¥¹Æâ¤Î¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ï¼¡¤Î¤è¤¦¤Ë»ØÄꤵ¤ì¤ë¡£
92 TAG0 ¤¬ #Mchar_table ¤Ç¤¢¤ë¥Ç¡¼¥¿¤Ï @e chartable¥¿¥¤¥×
93 ¤È¸Æ¤Ð¤ì¡¢³Æʸ»ú¤Ë´Ø¤¹¤ë¾ðÊó¤òÄ󶡤¹¤ë¡£¤³¤Î¾ì¹ç
94 TAG1 ¤Ï¾ðÊó¤Î¼ïÎà¤ò»ØÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢#Msymbol, #Minteger, #Mstring,
95 #Mtext, #Mplist ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£TAG2 ¤È TAG3 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
98 TAG0 ¤¬ #Mcharset ¤Ç¤¢¤ë¥Ç¡¼¥¿¤Ï @e charset¥¿¥¤¥×
99 ¤È¸Æ¤Ð¤ì¡¢Ê¸»ú¥»¥Ã¥ÈÍѤΥǥ³¡¼¥É¡¿¥¨¥ó¥³¡¼¥É¥Þ¥Ã¥×¤òÄ󶡤¹¤ë¡£¤³¤Î¾ì¹ç TAG1
100 ¤Ïʸ»ú¥»¥Ã¥È¤Î¥·¥ó¥Ü¥ë¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£TAG2 ¤È TAG3
101 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
104 TAG0 ¤¬ #Mchar_table ¤Ç¤â #Mcharset ¤Ç¤â¤Ê¤¤¾ì¹ç¡¢¤½¤Î¥Ç¡¼¥¿¤Ï @e
105 plist¥¿¥¤¥× ¤Ç¤¢¤ë¡£¾ÜºÙ¤Ë´Ø¤·¤Æ¤Ï´Ø¿ô mdatabase_load ()
106 ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£¤³¤Î¾ì¹ç TAG1¡¢TAG2¡¢TAG3 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
108 ÆÃÄê¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò \<TAG0, TAG1, TAG2, TAG3\>
111 ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¡¢¤Þ¤º´Ø¿ô mdatabase_find ()
112 ¤ò»È¤Ã¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÝ»ý¤¹¤ë¥ª¥Ö¥¸¥§¥¯¥È¡Ê#MDatabase
113 ·¿¡Ë¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÆÀ¤ë¡£¤½¤ì¤ËÀ®¸ù¤·¤¿¤é¡¢ mdatabase_load ()
114 ¤Ë¤è¤Ã¤Æ¼ÂºÝ¤Ë¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¥í¡¼¥É¤¹¤ë¡£¹½Â¤ÂÎ #MDatabase
115 ¼«¿È¤¬¤É¤¦¼ÂÁõ¤µ¤ì¤Æ¤¤¤ë¤«¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤«¤é¤Ï¸«¤¨¤Ê¤¤¡£
117 @latexonly \IPAlabel{database} @endlatexonly
122 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
123 /*** @addtogroup m17nInternal
131 #include <sys/types.h>
132 #include <sys/stat.h>
138 #include "m17n-misc.h"
139 #include "internal.h"
141 #include "character.h"
143 #include "database.h"
147 /** The file containing a list of databases. */
148 #define MDB_DIR "mdb.dir"
149 #define MDB_DIR_LEN 8
151 #define MAX_TIME(TIME1, TIME2) ((TIME1) >= (TIME2) ? (TIME1) : (TIME2))
154 #define PATH_MAX 1024
157 #define PATH_SEPARATOR '/'
159 #define USE_GEN_PATH \
160 char _path_static[PATH_MAX], *_path = _path_static; \
161 int _path_len = PATH_MAX, _this_len
163 #define GEN_PATH(DIR, FILE) \
164 (_this_len = strlen (DIR) + strlen (FILE) + 2, \
165 sprintf (((_this_len > _path_len) \
166 ? (_path_len = _this_len, _path = alloca (_path_len)) : _path), \
167 "%s%c%s", (DIR), PATH_SEPARATOR, (FILE)), \
170 #define GEN_PATH_FROM_MT(DIR, MT) \
171 (mtext_ref_char ((MT), 0) == PATH_SEPARATOR \
172 ? (_this_len = mtext_nbytes (MT) + 1, \
173 (_this_len > _path_len \
174 ? (_path_len = _this_len, _path = alloca (_path_len)) \
175 : _path)[_this_len - 1] = '\0', \
176 memcpy (_path, MTEXT_DATA (MT), mtext_nbytes (MT))) \
177 : (_this_len = strlen (DIR) + mtext_nbytes (MT) + 2, \
178 (_this_len > _path_len \
179 ? (_path_len = _this_len, _path = alloca (_path_len)) \
180 : _path)[_this_len - 1] = '\0', \
181 memcpy (_path + sprintf (_path, "%s%c", (DIR), PATH_SEPARATOR), \
182 MTEXT_DATA (MT), mtext_nbytes (MT)), \
185 static MSymbol Masterisk;
187 /** Structure for a data in the m17n database. */
191 /** Tags to identify the data. <tag>[0] specifies the type of
192 database. If it is #Mchar_table, the type is @e chartable, if
193 it is #Mcharset, the type is @e charset, otherwise the type is
197 void *(*loader) (MSymbol *tags, void *extra_info);
199 /** The meaning of the value is dependent on <loader>. If <loader>
200 is load_database (), the value is a string of the file name that
201 contains the data. */
211 /** List of all data. */
218 static struct MDatabaseList mdb_list;
222 read_number (char *buf, int *i)
231 while (c && isspace (c)) c = buf[idx++];
237 for (idx++, c = 0; (n = hex_mnemonic[(unsigned) buf[idx]]) < 16;
251 n = escape_mnemonic[c];
255 while (buf[idx] && buf[idx++] != '\'');
259 else if (hex_mnemonic[c] < 10)
264 while ((n = hex_mnemonic[(unsigned) buf[idx]]) < 10)
265 c = (c * 10) + n, idx++;
271 /** Load a data of type @c chartable from the file FD, and return the
272 newly created chartable. */
275 load_chartable (FILE *fp, MSymbol type)
283 MERROR (MERROR_DB, NULL);
285 table = mchartable (type, (type == Msymbol ? (void *) Mnil
286 : type == Minteger ? (void *) -1
293 for (len = 0; len < 1023 && (c = getc (fp)) != EOF && c != '\n'; len++)
296 if (hex_mnemonic[(unsigned) buf[0]] >= 10)
297 /* skip comment/invalid line */
300 from = read_number (buf, &i);
302 i++, to = read_number (buf, &i);
305 if (from < 0 || to < from)
308 while (buf[i] && isspace ((unsigned) buf[i])) i++;
315 /* VAL is a C-string. */
316 if (! (val = strdup (buf + i)))
317 MEMORY_FULL (MERROR_DB);
319 else if (type == Minteger)
321 /* VAL is an integer. */
327 n = read_number (buf, &i);
330 val = (void *) (n * positive);
332 else if (type == Mtext)
334 /* VAL is an M-text. */
337 mt = mconv_decode_buffer (Mcoding_utf_8,
338 (unsigned char *) (buf + i),
343 while ((c = read_number (buf, &i)) >= 0)
344 mt = mtext_cat_char (mt, c);
348 else if (type == Msymbol)
352 while (*p && ! isspace (*p))
354 if (*p == '\\' && p[1] != '\0')
356 memmove (p, p + 1, buf + len - (p + 1));
362 if (! strcmp (buf + i, "nil"))
365 val = (void *) msymbol (buf + i);
367 else if (type == Mplist)
369 val = (void *) mplist__from_string ((unsigned char *) buf + i,
376 mchartable_set (table, from, val);
378 mchartable_set_range (table, from, to, val);
383 M17N_OBJECT_UNREF (table);
384 MERROR (MERROR_DB, NULL);
388 /** Load a data of type @c charset from the file FD. */
391 load_charset (FILE *fp, MSymbol charset_name)
393 MCharset *charset = MCHARSET (charset_name);
402 MERROR (MERROR_DB, NULL);
403 size = (charset->code_range[15]
404 - (charset->min_code - charset->code_range_min_code));
405 MTABLE_MALLOC (decoder, size, MERROR_DB);
406 for (i = 0; i < size; i++)
408 encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
410 while ((c = getc (fp)) != EOF)
412 unsigned code1, code2, c1, c2;
417 fgets (buf, 256, fp);
420 if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
422 idx1 = CODE_POINT_TO_INDEX (charset, code1);
425 idx2 = CODE_POINT_TO_INDEX (charset, code2);
428 c2 = c1 + (idx2 - idx1);
430 else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
432 idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
439 if (idx1 >= 0 && idx2 >= 0)
442 mchartable_set (encoder, c1, (void *) code1);
443 for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
445 code1 = INDEX_TO_CODE_POINT (charset, idx1);
447 mchartable_set (encoder, c1, (void *) code1);
457 M17N_OBJECT_UNREF (encoder);
461 mplist_add (plist, Mt, decoder);
462 mplist_add (plist, Mt, encoder);
467 gen_database_name (char *buf, MSymbol *tags)
471 strcpy (buf, msymbol_name (tags[0]));
472 for (i = 1; i < 4; i++)
475 strcat (buf, msymbol_name (tags[i]));
481 get_database_filename (MDatabaseInfo *db_info)
483 char *filename = NULL;
486 if (db_info->filename[0] == '/')
488 if (stat (db_info->filename, &buf) == 0)
490 filename = db_info->filename;
491 db_info->time = MAX_TIME (buf.st_mtime, buf.st_ctime);
499 MPLIST_DO (plist, mdatabase__dir_list)
501 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
502 char *path = GEN_PATH (dir_info->filename, db_info->filename);
504 if (stat (path, &buf) == 0)
506 free (db_info->filename);
507 filename = db_info->filename = strdup (path);
508 db_info->time = MAX_TIME (buf.st_mtime, buf.st_ctime);
517 load_database (MSymbol *tags, void *extra_info)
519 char *filename = get_database_filename ((MDatabaseInfo *) extra_info);
523 if (! filename || ! (fp = fopen (filename, "r")))
524 MERROR (MERROR_DB, NULL);
526 if (tags[0] == Mchar_table)
527 value = load_chartable (fp, tags[1]);
528 else if (tags[0] == Mcharset)
529 value = load_charset (fp, tags[1]);
531 value = mplist__from_file (fp, NULL);
535 MERROR (MERROR_DB, NULL);
540 /** If DIRNAME is a readable directory, allocate MDatabaseInfo and
541 copy DIRNAME to a newly allocated memory and return it. If
542 DIRNAME does not end with a slash, append a slash to the new memory. */
544 static MDatabaseInfo *
545 get_dir_info (char *dirname)
549 MDatabaseInfo *dir_info;
552 || stat (dirname, &buf) < 0
553 || ! (buf.st_mode & S_IFDIR))
556 MSTRUCT_MALLOC (dir_info, MERROR_DB);
557 len = strlen (dirname) + 1;
558 MTABLE_MALLOC (dir_info->filename, len, MERROR_DB);
559 memcpy (dir_info->filename, dirname, len);
560 /* Don't include the last '/' in filename. */
561 if (dir_info->filename[len - 2] == PATH_SEPARATOR)
562 dir_info->filename[len - 2] = '\0';
563 /* Set this to zero so that the first call of update_database_list
564 surely checks this directory. */
570 find_database (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
574 for (i = 0; i < mdb_list.used; i++)
576 MDatabase *mdb = mdb_list.mdbs + i;
578 if (tag0 == mdb->tag[0]
579 && tag1 == mdb->tag[1]
580 && tag2 == mdb->tag[2]
581 && tag3 == mdb->tag[3])
588 register_database (MDatabase *mdb, char *path)
590 if (find_database (mdb->tag[0], mdb->tag[1], mdb->tag[2], mdb->tag[3]))
592 mdb->loader = load_database;
593 mdb->extra_info = calloc (1, sizeof (MDatabaseInfo));
594 if (! mdb->extra_info)
595 MEMORY_FULL (MERROR_DB);
596 ((MDatabaseInfo*) mdb->extra_info)->filename = strdup (path);
597 MLIST_APPEND1 (&mdb_list, mdbs, *mdb, MERROR_DB);
598 if (mdb->tag[0] == Mchar_table
599 && mdb->tag[2] != Mnil
600 && (mdb->tag[1] == Mstring || mdb->tag[1] == Mtext
601 || mdb->tag[1] == Msymbol || mdb->tag[1] == Minteger
602 || mdb->tag[1] == Mplist))
603 mchar__define_prop (mdb->tag[2], mdb->tag[1],
604 mdb_list.mdbs + mdb_list.used - 1);
608 update_database_list ()
614 MPLIST_DO (plist, mdatabase__dir_list)
616 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
622 if (stat (dir_info->filename, &statbuf) < 0)
624 if (dir_info->time >= statbuf.st_ctime
625 && dir_info->time >= statbuf.st_mtime)
627 dir_info->time = MAX_TIME (statbuf.st_ctime, statbuf.st_mtime);
628 path = GEN_PATH (dir_info->filename, MDB_DIR);
629 if (! (fp = fopen (path, "r")))
631 pl = mplist__from_file (fp, NULL);
641 int with_wildcard = 0;
643 if (! MPLIST_PLIST_P (p))
645 p1 = MPLIST_PLIST (p);
646 if (! MPLIST_SYMBOL_P (p1))
648 for (i = 0, p1 = MPLIST_PLIST (p);
649 i < 4 && MPLIST_KEY (p1) == Msymbol;
650 i++, p1 = MPLIST_NEXT (p1))
651 with_wildcard |= ((mdb.tag[i] = MPLIST_SYMBOL (p1)) == Masterisk);
653 || mdb.tag[0] == Masterisk
654 || ! MPLIST_MTEXT_P (p1))
658 mdb.loader = load_database;
659 mt = MPLIST_MTEXT (p1);
660 if (mt->format >= MTEXT_FORMAT_UTF_16LE)
661 mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
662 nbytes = mtext_nbytes (mt);
664 if (nbytes > PATH_MAX)
666 #endif /* PATH_MAX */
668 && mdb.tag[0] != Mchar_table
669 && mdb.tag[0] != Mcharset)
672 MPlist *load_key = mplist ();
674 MPLIST_DO (dlist, mdatabase__dir_list)
676 MDatabaseInfo *d_info = MPLIST_VAL (dlist);
679 path = GEN_PATH_FROM_MT (d_info->filename, mt);
680 if (glob (path, GLOB_NOSORT | GLOB_NOCHECK, NULL, &globbuf))
682 if (path[0] == PATH_SEPARATOR)
686 for (i = 0; i < globbuf.gl_pathc; i++)
688 if (! (fp = fopen (globbuf.gl_pathv[i], "r")))
690 p1 = mplist__from_file (fp, load_key);
694 if (MPLIST_PLIST_P (p1))
699 for (j = 0, p0 = MPLIST_PLIST (p1);
700 j < 4 && MPLIST_SYMBOL_P (p0);
701 j++, p0 = MPLIST_NEXT (p0))
702 mdb2.tag[j] = MPLIST_SYMBOL (p0);
705 for (j = 0; j < 4; j++)
706 if (mdb.tag[j] == Masterisk
707 ? mdb2.tag[j] == Mnil
708 : (mdb.tag[j] != Mnil
709 && mdb.tag[j] != mdb2.tag[j]))
712 register_database (&mdb2, globbuf.gl_pathv[i]);
714 M17N_OBJECT_UNREF (p1);
717 if (MTEXT_DATA (mt)[0] == PATH_SEPARATOR)
721 M17N_OBJECT_UNREF (load_key);
725 path = GEN_PATH_FROM_MT (dir_info->filename, mt);
726 register_database (&mdb, path);
729 M17N_OBJECT_UNREF (pl);
736 /** List of database directories. */
737 MPlist *mdatabase__dir_list;
742 MDatabaseInfo *dir_info;
744 Mchar_table = msymbol ("char-table");
745 Masterisk = msymbol ("*");
747 mdatabase__dir_list = mplist ();
748 /** The macro M17NDIR specifies a directory where the system-wide
749 MDB_DIR file exists. */
750 if ((dir_info = get_dir_info (M17NDIR)))
751 mplist_set (mdatabase__dir_list, Mt, dir_info);
753 /* The variable mdatabase_dir specifies a directory where an
754 application program specific MDB_DIR file exists. */
755 if ((dir_info = get_dir_info (mdatabase_dir)))
756 mplist_push (mdatabase__dir_list, Mt, dir_info);
758 /* The environment variable M17NDIR (if non-NULL) specifies a
759 directory where a user specific MDB_DIR file exists. */
760 if ((dir_info = get_dir_info (getenv ("M17NDIR"))))
761 mplist_push (mdatabase__dir_list, Mt, dir_info);
762 /* If M17NDIR is not set, check "~/.m17n.d". */
765 char *home = getenv ("HOME");
769 && (dir_info = get_dir_info (GEN_PATH (home, ".m17n.d"))))
770 mplist_push (mdatabase__dir_list, Mt, dir_info);
773 MLIST_INIT1 (&mdb_list, mdbs, 256);
774 update_database_list ();
776 mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
778 mdatabase__loader = (void *(*) (void *)) mdatabase_load;
784 mdatabase__fini (void)
789 MPLIST_DO (plist, mdatabase__dir_list)
791 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
793 free (dir_info->filename);
796 M17N_OBJECT_UNREF (mdatabase__dir_list);
798 for (i = 0; i < mdb_list.used; i++)
800 MDatabase *mdb = mdb_list.mdbs + i;
802 if (mdb->loader == load_database)
804 MDatabaseInfo *db_info = mdb->extra_info;
806 free (db_info->filename);
810 MLIST_FREE1 (&mdb_list, mdbs);
814 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
816 int mdebug_mask = MDEBUG_DATABASE;
822 if (mdb->loader != load_database
823 || mdb->tag[0] == Mchar_table
824 || mdb->tag[0] == Mcharset)
825 MERROR (MERROR_DB, NULL);
826 MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
827 gen_database_name (buf, mdb->tag));
828 filename = get_database_filename ((MDatabaseInfo *) mdb->extra_info);
829 if (! filename || ! (fp = fopen (filename, "r")))
830 MERROR (MERROR_DB, NULL);
831 plist = mplist__from_file (fp, keys);
837 /* Check if the database MDB should be reloaded or not. Return -1 if
838 the database became not reloadable. */
841 mdatabase__check (MDatabase *mdb)
843 MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
846 if (stat (db_info->filename, &buf) < 0)
848 return (db_info->time >= buf.st_ctime
849 && db_info->time >= buf.st_mtime);
852 /* Find a file FILENAME in mdatabase__dir_list. If the file exist,
853 return the absolute pathname. If FILENAME is already absolute,
854 return a copy of it. */
857 mdatabase__find_file (char *filename)
859 MDatabaseInfo db_info;
861 db_info.filename = strdup (filename);
863 if (! get_database_filename (&db_info))
865 free (db_info.filename);
868 return db_info.filename;
873 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
878 /*** @addtogroup m17nDatabase */
883 @brief Directory for application specific data.
885 If an application program wants to provide a data specific to the
886 program or a data overriding what supplied by the m17n database,
887 it must set this variable to a name of directory that contains the
888 data files before it calls the macro M17N_INIT (). The directory
889 may contain a file "mdb.dir" which contains a list of data
890 definitions in the format described in @ref mdbDir "mdbDir(5)".
892 The default value is NULL. */
894 @brief ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¸ÇͤΥǡ¼¥¿Íѥǥ£¥ì¥¯¥È¥ê.
896 ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬¡¢¤½¤Î¥×¥í¥°¥é¥à¸ÇͤΥǡ¼¥¿¤ä m17n
897 ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¾å½ñ¤¤¹¤ë¥Ç¡¼¥¿¤òÄ󶡤¹¤ë¾ì¹ç¤Ë¤Ï¡¢¥Þ¥¯¥í M17N_INIT ()
898 ¤ò¸Æ¤ÖÁ°¤Ë¤³¤ÎÊÑ¿ô¤ò¥Ç¡¼¥¿¥Õ¥¡¥¤¥ë¤ò´Þ¤à¥Ç¥£¥ì¥¯¥È¥ê̾¤Ë¥»¥Ã¥È¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤Ï
899 "mdb.dir" ¥Õ¥¡¥¤¥ë¤ò¤ª¤¯¤³¤È¤¬¤Ç¤¤ë¡£¤½¤Î"mdb.dir"¥Õ¥¡¥¤¥ë¤Ë¤Ï¡¢
900 @ref mdbDir "mdbDir(5)" ¤ÇÀâÌÀ¤µ¤ì¤Æ¤¤¤ë¥Õ¥©¡¼¥Þ¥Ã¥È¤Ç¥Ç¡¼¥¿ÄêµÁ¤Î¥ê¥¹¥È¤òµ½Ò¤¹¤ë¡£
902 ¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¤Ï NULL ¤Ç¤¢¤ë¡£ */
908 @brief Look for a data in the database.
910 The mdatabase_find () function searches the m17n database for a
911 data who has tags $TAG0 through $TAG3, and returns a pointer to
912 the data. If such a data is not found, it returns @c NULL. */
915 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹Ãæ¤Î¥Ç¡¼¥¿¤òõ¤¹.
917 ´Ø¿ô mdatabase_find () ¤Ï¡¢ m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ãæ¤Ç $TAG0 ¤«¤é
918 $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤Î¤è¤¦¤Ê¥Ç¡¼¥¿¤¬¤Ê¤±¤ì¤Ð
921 @latexonly \IPAlabel{mdatabase_find} @endlatexonly */
924 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
926 update_database_list ();
927 return find_database (tag0, tag1, tag2, tag3);
932 @brief Return a data list of the m17n database.
934 The mdatabase_list () function searches the m17n database for data
935 who have tags $TAG0 through $TAG3, and returns their list by a
936 plist. The value #Mnil in $TAGn means a wild card that matches
937 any tag. Each element of the plist has key #Mt and value a
938 pointer to type #MDatabase. */
940 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¥ê¥¹¥È¤òÊÖ¤¹.
942 ´Ø¿ô mdatabase_list () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é $TAG0 ¤«¤é$TAG3
943 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤Î¥ê¥¹¥È¤òplist ¤È¤·¤ÆÊÖ¤¹¡£ $TAGn ¤¬ #Mnil
944 ¤Ç¤¢¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥¿¥°¤Ë¥Þ¥Ã¥Á¤¹¤ë¥ï¥¤¥ë¥É¥«¡¼¥É¤È¤·¤Æ¼è¤ê°·¤ï¤ì¤ë¡£ÊÖ¤µ¤ì¤ë
945 plist ¤Î³ÆÍ×ÁǤϥ¡¼ ¤È¤·¤Æ #Mt ¤ò¡¢ÃͤȤ·¤Æ #MDatabase ·¿¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò»ý¤Ä¡£ */
948 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
951 MPlist *plist = NULL, *pl;
953 update_database_list ();
955 for (i = 0; i < mdb_list.used; i++)
957 MDatabase *mdb = mdb_list.mdbs + i;
959 if ((tag0 == Mnil || tag0 == mdb->tag[0])
960 && (tag1 == Mnil || tag1 == mdb->tag[1])
961 && (tag2 == Mnil || tag2 == mdb->tag[2])
962 && (tag3 == Mnil || tag3 == mdb->tag[3]))
965 plist = pl = mplist ();
966 pl = mplist_add (pl, Mt, mdb);
974 @brief Define a data of the m17n database.
976 The mdatabase_define () function defines a data that has tags
977 $TAG0 through $TAG3 and additional information $EXTRA_INFO.
979 $LOADER is a pointer to a function that loads the data from the
980 database. This function is called from the mdatabase_load ()
981 function with the two arguments $TAGS and $EXTRA_INFO. Here,
982 $TAGS is the array of $TAG0 through $TAG3.
984 If $LOADER is @c NULL, the default loader of the m17n library is
985 used. In this case, $EXTRA_INFO must be a string specifying a
986 filename that contains the data.
989 If the operation was successful, mdatabase_define () returns a
990 pointer to the defined data, which can be used as an argument to
991 mdatabase_load (). Otherwise, it returns @c NULL. */
994 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë.
996 ´Ø¿ô mdatabase_define () ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ª¤è¤ÓÉղþðÊó
997 $EXTRA_INFO ¤ò»ý¤Ä¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë¡£
999 $LOADER ¤Ï¤½¤Î¥Ç¡¼¥¿¤Î¥í¡¼¥É¤ËÍѤ¤¤é¤ì¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï
1000 mdatabase_load () ¤«¤é $TAGS ¤È $EXTRA_INFO ¤È¤¤¤¦Æó¤Ä¤Î°ú¿ôÉÕ¤¤Ç¸Æ¤Ó½Ð¤µ¤ì¤ë¡£¤³¤³¤Ç
1001 $TAGS ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1003 ¤â¤· $LOADER ¤¬ @c NULL ¤Ê¤é¡¢m17n ¥é¥¤¥Ö¥é¥êɸ½à¤Î¥í¡¼¥À¤¬»È¤ï¤ì¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï
1004 $EXTRA_INFO ¤Ï¥Ç¡¼¥¿¤ò´Þ¤à¥Õ¥¡¥¤¥ë̾¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1007 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mdatabase_define ()
1008 ¤ÏÄêµÁ¤µ¤ì¤¿¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¥Ý¥¤¥ó¥¿¤Ï´Ø¿ô mdatabase_load ()
1009 ¤Î°ú¿ô¤È¤·¤ÆÍѤ¤¤ë¤³¤È¤¬¤Ç¤¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1011 @latexonly \IPAlabel{mdatabase_define} @endlatexonly */
1015 mdatabase_load (), mdatabase_define () */
1018 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
1019 void *(*loader) (MSymbol *, void *),
1024 mdb = mdatabase_find (tag0, tag1, tag2, tag3);
1029 template.tag[0] = tag0, template.tag[1] = tag1;
1030 template.tag[2] = tag2, template.tag[3] = tag3;
1031 template.extra_info = NULL;
1032 MLIST_APPEND1 (&mdb_list, mdbs, template, MERROR_DB);
1033 mdb = mdb_list.mdbs + (mdb_list.used - 1);
1035 mdb->loader = loader ? loader : load_database;
1036 if (mdb->loader == load_database)
1038 MDatabaseInfo *db_info = mdb->extra_info;
1041 free (db_info->filename);
1043 db_info = mdb->extra_info = malloc (sizeof (MDatabaseInfo));
1044 db_info->filename = strdup ((char *) extra_info);
1048 mdb->extra_info = extra_info;
1049 return (&(mdb_list.mdbs[mdb_list.used - 1]));
1054 @brief Load a data from the database.
1056 The mdatabase_load () function loads a data specified in $MDB and
1057 returns the contents. The type of contents depends on the type of
1060 If the data is of the @e plist @e type, this function returns a
1061 pointer to @e plist.
1063 If the database is of the @e chartable @e type, it returns a
1064 chartable. The default value of the chartable is set according to
1065 the second tag of the data as below:
1067 @li If the tag is #Msymbol, the default value is #Mnil.
1068 @li If the tag is #Minteger, the default value is -1.
1069 @li Otherwise, the default value is @c NULL.
1071 If the data is of the @e charset @e type, it returns a plist of length 2
1072 (keys are both #Mt). The value of the first element is an array
1073 of integers that maps code points to the corresponding character
1074 codes. The value of the second element is a chartable of integers
1075 that does the reverse mapping. The charset must be defined in
1080 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿¤ò¥í¡¼¥É¤¹¤ë.
1082 ´Ø¿ô mdatabase_load () ¤Ï $MDB
1083 ¤¬»Ø¤¹¥Ç¡¼¥¿¤ò¥í¡¼¥É¤·¡¢¤½¤ÎÃæ¿È¤òÊÖ¤¹¡£ÊÖ¤µ¤ì¤ë¤â¤Î¤Ï¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ°Û¤Ê¤ë¡£
1085 ¥Ç¡¼¥¿¤¬ @e plist¥¿¥¤¥× ¤Ê¤é¤Ð¡¢ @e plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1087 ¥Ç¡¼¥¿¤¬ @e chartable¥¿¥¤¥× ¤Ê¤é¤Ðʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£
1088 ʸ»ú¥Æ¡¼¥Ö¥ë¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤϡ¢¥Ç¡¼¥¿¤ÎÂè2¥¿¥°¤Ë¤è¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Ë·è¤Þ¤ë¡£
1090 @li ¥¿¥°¤¬ #Msymbol ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï #Mnil
1091 @li ¥¿¥°¤¬ #Minteger ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï -1
1092 @li ¤½¤ì°Ê³°¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï @c NULL
1094 ¥Ç¡¼¥¿¤¬ @e charset¥¿¥¤¥× ¤Ê¤é¤ÐŤµ 2 ¤Î plist ¤òÊÖ¤¹¡Ê¥¡¼¤Ï¶¦¤Ë#Mt ¡Ë¡£
1095 ºÇ½é¤ÎÍ×ÁǤÎÃͤϥ³¡¼¥É¥Ý¥¤¥ó¥È¤òÂбþ¤¹¤ëʸ»ú¥³¡¼¥É¤Ë¥Þ¥Ã¥×¤¹¤ëÀ°¿ô¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1096 £²ÈÖÌܤÎÍ×ÁǤÎÃͤϵդΥޥåפò¤¹¤ëʸ»ú¥Æ¡¼¥Ö¥ë¤Ç¤¢¤ë¡£
1097 ¤³¤Îʸ»ú¥»¥Ã¥È¤Ïͽ¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
1099 @latexonly \IPAlabel{mdatabase_load} @endlatexonly
1104 mdatabase_load (), mdatabase_define () */
1107 mdatabase_load (MDatabase *mdb)
1109 int mdebug_mask = MDEBUG_DATABASE;
1112 MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
1113 gen_database_name (buf, mdb->tag));
1114 return (*mdb->loader) (mdb->tag, mdb->extra_info);
1119 @brief Get tags of a data.
1121 The mdatabase_tag () function returns an array of tags (symbols)
1122 that identify the data in $MDB. The length of the array is
1126 @brief ¥Ç¡¼¥¿¤Î¥¿¥°¤òÆÀ¤ë.
1128 ´Ø¿ô mdatabase_tag () ¤Ï¡¢¥Ç¡¼¥¿ $MDB ¤Î¥¿¥°¡Ê¥·¥ó¥Ü¥ë¡Ë¤ÎÇÛÎó¤òÊÖ¤¹¡£ÇÛÎó¤ÎŤµ¤Ï
1131 @latexonly \IPAlabel{mdatabase_tag} @endlatexonly */
1134 mdatabase_tag (MDatabase *mdb)