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 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 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 overwriting-data in the directory
33 "~/.m17n.d" or in a directory specified by the environment
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 ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÄɲä·¡¢¤½¤ì¤òưŪ¤Ë¼èÆÀ¤¹¤ë¤³¤È¤¬¤Ç¤¤ë¡£m17n
79 ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤ÏÊ£¿ô¤Î¿Íͤʥǡ¼¥¿¤¬´Þ¤Þ¤ì¤Æ¤ª¤ê¡¢³Æ¥Ç¡¼¥¿¤Ï
80 TAG0, TAG1, TAG2, TAG3¡Ê¤¹¤Ù¤Æ¥·¥ó¥Ü¥ë¡Ë¤Î£´¤Ä¤Î¥¿¥°¤Ë¤è¤Ã¤Æ¼±Ê̤µ¤ì¤ë¡£
82 TAG0 ¤Ë¤è¤Ã¤Æ¡¢¥Ç¡¼¥¿¥Ù¡¼¥¹Æâ¤Î¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ï¼¡¤Î¤è¤¦¤Ë»ØÄꤵ¤ì¤ë¡£
85 TAG0 ¤¬ #Mchar_table ¤Ç¤¢¤ë¥Ç¡¼¥¿¤Ï @e chartable¥¿¥¤¥×
86 ¤È¸Æ¤Ð¤ì¡¢³Æʸ»ú¤Ë´Ø¤¹¤ë¾ðÊó¤òÄ󶡤¹¤ë¡£¤³¤Î¾ì¹ç
87 TAG1 ¤Ï¾ðÊó¤Î¼ïÎà¤ò»ØÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢#Msymbol, #Minteger, #Mstring,
88 #Mtext, #Mplist ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£TAG2 ¤È TAG3 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
91 TAG0 ¤¬ #Mcharset ¤Ç¤¢¤ë¥Ç¡¼¥¿¤Ï @e charset¥¿¥¤¥×
92 ¤È¸Æ¤Ð¤ì¡¢Ê¸»ú¥»¥Ã¥ÈÍѤΥǥ³¡¼¥É¡¿¥¨¥ó¥³¡¼¥É¥Þ¥Ã¥×¤òÄ󶡤¹¤ë¡£¤³¤Î¾ì¹ç TAG1
93 ¤Ïʸ»ú¥»¥Ã¥È¤Î¥·¥ó¥Ü¥ë¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£TAG2 ¤È TAG3
94 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
97 TAG0 ¤¬ #Mchar_table ¤Ç¤â #Mcharset ¤Ç¤â¤Ê¤¤¾ì¹ç¡¢¤½¤Î¥Ç¡¼¥¿¤Ï @e
98 plist¥¿¥¤¥× ¤Ç¤¢¤ë¡£¾ÜºÙ¤Ë´Ø¤·¤Æ¤Ï´Ø¿ô mdatabase_load ()
99 ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£¤³¤Î¾ì¹ç TAG1¡¢TAG2¡¢TAG3 ¤ÏǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
101 ÆÃÄê¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò \<TAG0, TAG1, TAG2, TAG3\>
104 ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¡¢¤Þ¤º´Ø¿ô mdatabase_find ()
105 ¤ò»È¤Ã¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÝ»ý¤¹¤ë¥ª¥Ö¥¸¥§¥¯¥È¡Ê#MDatabase
106 ·¿¡Ë¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÆÀ¤ë¡£¤½¤ì¤ËÀ®¸ù¤·¤¿¤é¡¢ mdatabase_load ()
107 ¤Ë¤è¤Ã¤Æ¼ÂºÝ¤Ë¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¥í¡¼¥É¤¹¤ë¡£¹½Â¤ÂÎ #MDatabase
108 ¼«¿È¤¬¤É¤¦¼ÂÁõ¤µ¤ì¤Æ¤¤¤ë¤«¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤«¤é¤Ï¸«¤¨¤Ê¤¤¡£
110 @latexonly \IPAlabel{database} @endlatexonly
115 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
116 /*** @addtogroup m17nInternal
124 #include <sys/types.h>
125 #include <sys/stat.h>
131 #include "m17n-misc.h"
132 #include "internal.h"
134 #include "character.h"
136 #include "database.h"
140 /** The file containing a list of databases. */
141 #define MDB_DIR "mdb.dir"
142 #define MDB_DIR_LEN 8
144 #define MAX_TIME(TIME1, TIME2) ((TIME1) >= (TIME2) ? (TIME1) : (TIME2))
147 #define PATH_MAX 1024
150 #define PATH_SEPARATOR '/'
152 #define USE_GEN_PATH \
153 char _path_static[PATH_MAX], *_path = _path_static; \
154 int _path_len = PATH_MAX, _this_len
156 #define GEN_PATH(DIR, FILE) \
157 (_this_len = strlen (DIR) + strlen (FILE) + 2, \
158 sprintf (((_this_len > _path_len) \
159 ? (_path_len = _this_len, _path = alloca (_path_len)) : _path), \
160 "%s%c%s", (DIR), PATH_SEPARATOR, (FILE)), \
163 #define GEN_PATH_FROM_MT(DIR, MT) \
164 (mtext_ref_char ((MT), 0) == PATH_SEPARATOR \
165 ? (_this_len = mtext_nbytes (MT) + 1, \
166 (_this_len > _path_len \
167 ? (_path_len = _this_len, _path = alloca (_path_len)) \
168 : _path)[_this_len - 1] = '\0', \
169 memcpy (_path, MTEXT_DATA (MT), mtext_nbytes (MT))) \
170 : (_this_len = strlen (DIR) + mtext_nbytes (MT) + 2, \
171 (_this_len > _path_len \
172 ? (_path_len = _this_len, _path = alloca (_path_len)) \
173 : _path)[_this_len - 1] = '\0', \
174 memcpy (_path + sprintf (_path, "%s%c", (DIR), PATH_SEPARATOR), \
175 MTEXT_DATA (MT), mtext_nbytes (MT)), \
178 static MSymbol Masterisk;
180 /** Structure for a data in the m17n database. */
184 /** Tags to identify the data. <tag>[0] specifies the type of
185 database. If it is #Mchar_table, the type is @e chartable, if
186 it is #Mcharset, the type is @e charset, otherwise the type is
190 void *(*loader) (MSymbol *tags, void *extra_info);
192 /** The meaning of the value is dependent on <loader>. If <loader>
193 is load_database (), the value is a string of the file name that
194 contains the data. */
204 /** List of all data. */
211 static struct MDatabaseList mdb_list;
215 read_number (char *buf, int *i)
224 while (c && isspace (c)) c = buf[idx++];
230 for (idx++, c = 0; (n = hex_mnemonic[(unsigned) buf[idx]]) < 16;
244 n = escape_mnemonic[c];
248 while (buf[idx] && buf[idx++] != '\'');
252 else if (hex_mnemonic[c] < 10)
257 while ((n = hex_mnemonic[(unsigned) buf[idx]]) < 10)
258 c = (c * 10) + n, idx++;
264 /** Load a data of type @c chartable from the file FD, and return the
265 newly created chartable. */
268 load_chartable (FILE *fp, MSymbol type)
276 MERROR (MERROR_DB, NULL);
278 table = mchartable (type, (type == Msymbol ? (void *) Mnil
279 : type == Minteger ? (void *) -1
286 for (len = 0; len < 1023 && (c = getc (fp)) != EOF && c != '\n'; len++)
289 if (hex_mnemonic[(unsigned) buf[0]] >= 10)
290 /* skip comment/invalid line */
293 from = read_number (buf, &i);
295 i++, to = read_number (buf, &i);
298 if (from < 0 || to < from)
301 while (buf[i] && isspace ((unsigned) buf[i])) i++;
308 /* VAL is a C-string. */
309 if (! (val = strdup (buf + i)))
310 MEMORY_FULL (MERROR_DB);
312 else if (type == Minteger)
314 /* VAL is an integer. */
320 n = read_number (buf, &i);
323 val = (void *) (n * positive);
325 else if (type == Mtext)
327 /* VAL is an M-text. */
330 mt = mconv_decode_buffer (Mcoding_utf_8,
331 (unsigned char *) (buf + i),
336 while ((c = read_number (buf, &i)) >= 0)
337 mt = mtext_cat_char (mt, c);
341 else if (type == Msymbol)
345 while (*p && ! isspace (*p))
347 if (*p == '\\' && p[1] != '\0')
349 memmove (p, p + 1, buf + len - (p + 1));
355 if (! strcmp (buf + i, "nil"))
358 val = (void *) msymbol (buf + i);
360 else if (type == Mplist)
362 val = (void *) mplist__from_string ((unsigned char *) buf + i,
369 mchartable_set (table, from, val);
371 mchartable_set_range (table, from, to, val);
376 M17N_OBJECT_UNREF (table);
377 MERROR (MERROR_DB, NULL);
381 /** Load a data of type @c charset from the file FD. */
384 load_charset (FILE *fp, MSymbol charset_name)
386 MCharset *charset = MCHARSET (charset_name);
395 MERROR (MERROR_DB, NULL);
396 size = (charset->code_range[15]
397 - (charset->min_code - charset->code_range_min_code));
398 MTABLE_MALLOC (decoder, size, MERROR_DB);
399 for (i = 0; i < size; i++)
401 encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
403 while ((c = getc (fp)) != EOF)
405 unsigned code1, code2, c1, c2;
410 fgets (buf, 256, fp);
413 if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
415 idx1 = CODE_POINT_TO_INDEX (charset, code1);
418 idx2 = CODE_POINT_TO_INDEX (charset, code2);
421 c2 = c1 + (idx2 - idx1);
423 else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
425 idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
432 if (idx1 >= 0 && idx2 >= 0)
435 mchartable_set (encoder, c1, (void *) code1);
436 for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
438 code1 = INDEX_TO_CODE_POINT (charset, idx1);
440 mchartable_set (encoder, c1, (void *) code1);
450 M17N_OBJECT_UNREF (encoder);
454 mplist_add (plist, Mt, decoder);
455 mplist_add (plist, Mt, encoder);
460 gen_database_name (char *buf, MSymbol *tags)
464 strcpy (buf, msymbol_name (tags[0]));
465 for (i = 1; i < 4; i++)
468 strcat (buf, msymbol_name (tags[i]));
474 get_database_filename (MDatabaseInfo *db_info)
476 char *filename = NULL;
479 if (db_info->filename[0] == '/')
481 if (stat (db_info->filename, &buf) == 0)
483 filename = db_info->filename;
484 db_info->time = MAX_TIME (buf.st_mtime, buf.st_ctime);
492 MPLIST_DO (plist, mdatabase__dir_list)
494 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
495 char *path = GEN_PATH (dir_info->filename, db_info->filename);
497 if (stat (path, &buf) == 0)
499 free (db_info->filename);
500 filename = db_info->filename = strdup (path);
501 db_info->time = MAX_TIME (buf.st_mtime, buf.st_ctime);
510 load_database (MSymbol *tags, void *extra_info)
512 char *filename = get_database_filename ((MDatabaseInfo *) extra_info);
516 if (! filename || ! (fp = fopen (filename, "r")))
517 MERROR (MERROR_DB, NULL);
519 if (tags[0] == Mchar_table)
520 value = load_chartable (fp, tags[1]);
521 else if (tags[0] == Mcharset)
522 value = load_charset (fp, tags[1]);
524 value = mplist__from_file (fp, NULL);
528 MERROR (MERROR_DB, NULL);
533 /** If DIRNAME is a readable directory, allocate MDatabaseInfo and
534 copy DIRNAME to a newly allocated memory and return it. If
535 DIRNAME does not end with a slash, append a slash to the new memory. */
537 static MDatabaseInfo *
538 get_dir_info (char *dirname)
542 MDatabaseInfo *dir_info;
545 || stat (dirname, &buf) < 0
546 || ! (buf.st_mode & S_IFDIR))
549 MSTRUCT_MALLOC (dir_info, MERROR_DB);
550 len = strlen (dirname) + 1;
551 MTABLE_MALLOC (dir_info->filename, len, MERROR_DB);
552 memcpy (dir_info->filename, dirname, len);
553 /* Don't include the last '/' in filename. */
554 if (dir_info->filename[len - 2] == PATH_SEPARATOR)
555 dir_info->filename[len - 2] = '\0';
556 /* Set this to zero so that the first call of update_database_list
557 surely checks this directory. */
563 find_database (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
567 for (i = 0; i < mdb_list.used; i++)
569 MDatabase *mdb = mdb_list.mdbs + i;
571 if (tag0 == mdb->tag[0]
572 && tag1 == mdb->tag[1]
573 && tag2 == mdb->tag[2]
574 && tag3 == mdb->tag[3])
581 register_database (MDatabase *mdb, char *path)
583 if (find_database (mdb->tag[0], mdb->tag[1], mdb->tag[2], mdb->tag[3]))
585 mdb->loader = load_database;
586 mdb->extra_info = calloc (1, sizeof (MDatabaseInfo));
587 if (! mdb->extra_info)
588 MEMORY_FULL (MERROR_DB);
589 ((MDatabaseInfo*) mdb->extra_info)->filename = strdup (path);
590 MLIST_APPEND1 (&mdb_list, mdbs, *mdb, MERROR_DB);
591 if (mdb->tag[0] == Mchar_table
592 && mdb->tag[2] != Mnil
593 && (mdb->tag[1] == Mstring || mdb->tag[1] == Mtext
594 || mdb->tag[1] == Msymbol || mdb->tag[1] == Minteger
595 || mdb->tag[1] == Mplist))
596 mchar__define_prop (mdb->tag[2], mdb->tag[1],
597 mdb_list.mdbs + mdb_list.used - 1);
601 update_database_list ()
607 MPLIST_DO (plist, mdatabase__dir_list)
609 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
616 if (stat (dir_info->filename, &statbuf) < 0)
618 if (dir_info->time >= statbuf.st_ctime
619 && dir_info->time >= statbuf.st_mtime)
621 dir_info->time = MAX_TIME (statbuf.st_ctime, statbuf.st_mtime);
622 path = GEN_PATH (dir_info->filename, MDB_DIR);
623 if (! (fp = fopen (path, "r")))
625 pl = mplist__from_file (fp, NULL);
635 int with_wildcard = 0;
637 if (! MPLIST_PLIST_P (p))
639 p1 = MPLIST_PLIST (p);
640 if (! MPLIST_SYMBOL_P (p1))
642 for (i = 0, p1 = MPLIST_PLIST (p);
643 i < 4 && MPLIST_KEY (p1) == Msymbol;
644 i++, p1 = MPLIST_NEXT (p1))
645 with_wildcard |= ((mdb.tag[i] = MPLIST_SYMBOL (p1)) == Masterisk);
647 || mdb.tag[0] == Masterisk
648 || ! MPLIST_MTEXT_P (p1))
652 mdb.loader = load_database;
653 mt = MPLIST_MTEXT (p1);
654 if (mt->format >= MTEXT_FORMAT_UTF_16LE)
655 mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
656 nbytes = mtext_nbytes (mt);
658 if (nbytes > PATH_MAX)
660 #endif /* PATH_MAX */
662 && mdb.tag[0] != Mchar_table
663 && mdb.tag[0] != Mcharset)
666 MPlist *load_key = mplist ();
668 MPLIST_DO (dlist, mdatabase__dir_list)
670 MDatabaseInfo *d_info = MPLIST_VAL (dlist);
673 path = GEN_PATH_FROM_MT (d_info->filename, mt);
674 if (glob (path, GLOB_NOSORT | GLOB_NOCHECK, NULL, &globbuf))
676 if (path[0] == PATH_SEPARATOR)
680 for (i = 0; i < globbuf.gl_pathc; i++)
682 if (! (fp = fopen (globbuf.gl_pathv[i], "r")))
684 p1 = mplist__from_file (fp, load_key);
688 if (MPLIST_PLIST_P (p1))
693 for (j = 0, p0 = MPLIST_PLIST (p1);
694 j < 4 && MPLIST_SYMBOL_P (p0);
695 j++, p0 = MPLIST_NEXT (p0))
696 mdb2.tag[j] = MPLIST_SYMBOL (p0);
699 for (j = 0; j < 4; j++)
700 if (mdb.tag[j] == Masterisk
701 ? mdb2.tag[j] == Mnil
702 : (mdb.tag[j] != Mnil
703 && mdb.tag[j] != mdb2.tag[j]))
706 register_database (&mdb2, globbuf.gl_pathv[i]);
708 M17N_OBJECT_UNREF (p1);
711 if (MTEXT_DATA (mt)[0] == PATH_SEPARATOR)
715 M17N_OBJECT_UNREF (load_key);
719 path = GEN_PATH_FROM_MT (dir_info->filename, mt);
720 register_database (&mdb, path);
723 M17N_OBJECT_UNREF (pl);
730 /** List of database directories. */
731 MPlist *mdatabase__dir_list;
736 MDatabaseInfo *dir_info;
738 Mchar_table = msymbol ("char-table");
739 Masterisk = msymbol ("*");
741 mdatabase__dir_list = mplist ();
742 /** The macro M17NDIR specifies a directory where the system-wide
743 MDB_DIR file exists. */
744 if ((dir_info = get_dir_info (M17NDIR)))
745 mplist_set (mdatabase__dir_list, Mt, dir_info);
747 /* The variable mdatabase_dir specifies a directory where an
748 application program specific MDB_DIR file exists. */
749 if ((dir_info = get_dir_info (mdatabase_dir)))
750 mplist_push (mdatabase__dir_list, Mt, dir_info);
752 /* The environment variable M17NDIR (if non-NULL) specifies a
753 directory where a user specific MDB_DIR file exists. */
754 if ((dir_info = get_dir_info (getenv ("M17NDIR"))))
755 mplist_push (mdatabase__dir_list, Mt, dir_info);
756 /* If M17NDIR is not set, check "~/.m17n.d". */
759 char *home = getenv ("HOME");
763 && (dir_info = get_dir_info (GEN_PATH (home, ".m17n.d"))))
764 mplist_push (mdatabase__dir_list, Mt, dir_info);
767 MLIST_INIT1 (&mdb_list, mdbs, 256);
768 update_database_list ();
770 mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
772 mdatabase__loader = (void *(*) (void *)) mdatabase_load;
778 mdatabase__fini (void)
783 MPLIST_DO (plist, mdatabase__dir_list)
785 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
787 free (dir_info->filename);
790 M17N_OBJECT_UNREF (mdatabase__dir_list);
792 for (i = 0; i < mdb_list.used; i++)
794 MDatabase *mdb = mdb_list.mdbs + i;
796 if (mdb->loader == load_database)
798 MDatabaseInfo *db_info = mdb->extra_info;
800 free (db_info->filename);
804 MLIST_FREE1 (&mdb_list, mdbs);
808 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
810 int mdebug_mask = MDEBUG_DATABASE;
816 if (mdb->loader != load_database
817 || mdb->tag[0] == Mchar_table
818 || mdb->tag[0] == Mcharset)
819 MERROR (MERROR_DB, NULL);
820 MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
821 gen_database_name (buf, mdb->tag));
822 filename = get_database_filename ((MDatabaseInfo *) mdb->extra_info);
823 if (! filename || ! (fp = fopen (filename, "r")))
824 MERROR (MERROR_DB, NULL);
825 plist = mplist__from_file (fp, keys);
831 /* Check if the database MDB should be reloaded or not. */
834 mdatabase__check (MDatabase *mdb)
836 MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
839 if (stat (db_info->filename, &buf) < 0)
841 return (db_info->time >= buf.st_ctime
842 && db_info->time >= buf.st_mtime);
845 /* Find a file FILENAME in mdatabase__dir_list. If the file exist,
846 return the absolute pathname. If FILENAME is already absolute,
847 return a copy of it. */
850 mdatabase__find_file (char *filename)
852 MDatabaseInfo db_info;
854 db_info.filename = strdup (filename);
856 if (! get_database_filename (&db_info))
858 free (db_info.filename);
861 return db_info.filename;
866 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
871 /*** @addtogroup m17nDatabase */
876 @brief Directory for application specific data.
878 If an application program wants to provide a data specific to the
879 program or a data overriding what supplied by the m17n database,
880 it must set this variable to a name of directory that contains the
881 data files before it calls the macro M17N_INIT (). The directory
882 may contain a file "mdb.dir" which contains a list of data
883 definitions in the format described in @ref mdbDir "mdbDir(5)".
885 The default value is NULL. */
887 @brief ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¸ÇͤΥǡ¼¥¿Íѥǥ£¥ì¥¯¥È¥ê.
889 ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬¡¢¤½¤Î¥×¥í¥°¥é¥à¸ÇͤΥǡ¼¥¿¤ä m17n
890 ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¾å½ñ¤¤¹¤ë¥Ç¡¼¥¿¤òÄ󶡤¹¤ë¾ì¹ç¤Ë¤Ï¡¢¥Þ¥¯¥í M17N_INIT ()
891 ¤ò¸Æ¤ÖÁ°¤Ë¤³¤ÎÊÑ¿ô¤ò¥Ç¡¼¥¿¥Õ¥¡¥¤¥ë¤ò´Þ¤à¥Ç¥£¥ì¥¯¥È¥ê̾¤Ë¥»¥Ã¥È¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤Ï
892 "mdb.dir" ¥Õ¥¡¥¤¥ë¤ò¤ª¤¯¤³¤È¤¬¤Ç¤¤ë¡£¤½¤Î"mdb.dir"¥Õ¥¡¥¤¥ë¤Ë¤Ï¡¢
893 @ref mdbDir "mdbDir(5)" ¤ÇÀâÌÀ¤µ¤ì¤Æ¤¤¤ë¥Õ¥©¡¼¥Þ¥Ã¥È¤Ç¥Ç¡¼¥¿ÄêµÁ¤Î¥ê¥¹¥È¤òµ½Ò¤¹¤ë¡£
895 ¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¤Ï NULL ¤Ç¤¢¤ë¡£ */
901 @brief Look for a data in the database.
903 The mdatabase_find () function searches the m17n database for a
904 data who has tags $TAG0 through $TAG3, and returns a pointer to
905 the data. If such a data is not found, it returns @c NULL. */
908 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹Ãæ¤Î¥Ç¡¼¥¿¤òõ¤¹.
910 ´Ø¿ô mdatabase_find () ¤Ï¡¢ m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ãæ¤Ç $TAG0 ¤«¤é
911 $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤Î¤è¤¦¤Ê¥Ç¡¼¥¿¤¬¤Ê¤±¤ì¤Ð
914 @latexonly \IPAlabel{mdatabase_find} @endlatexonly */
917 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
919 update_database_list ();
920 return find_database (tag0, tag1, tag2, tag3);
925 @brief Return a data list of the m17n database.
927 The mdatabase_list () function searches the m17n database for data
928 who have tags $TAG0 through $TAG3, and returns their list by a
929 plist. The value #Mnil in $TAGn means a wild card that matches
930 any tag. Each element of the plist has key #Mt and value a
931 pointer to type #MDatabase. */
933 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¥ê¥¹¥È¤òÊÖ¤¹.
935 ´Ø¿ô mdatabase_list () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é $TAG0 ¤«¤é$TAG3
936 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤Î¥ê¥¹¥È¤òplist ¤È¤·¤ÆÊÖ¤¹¡£ $TAGn ¤¬ #Mnil
937 ¤Ç¤¢¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥¿¥°¤Ë¥Þ¥Ã¥Á¤¹¤ë¥ï¥¤¥ë¥É¥«¡¼¥É¤È¤·¤Æ¼è¤ê°·¤ï¤ì¤ë¡£ÊÖ¤µ¤ì¤ë
938 plist ¤Î³ÆÍ×ÁǤϥ¡¼ ¤È¤·¤Æ #Mt ¤ò¡¢ÃͤȤ·¤Æ #MDatabase ·¿¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò»ý¤Ä¡£ */
941 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
944 MPlist *plist = NULL, *pl;
946 update_database_list ();
948 for (i = 0; i < mdb_list.used; i++)
950 MDatabase *mdb = mdb_list.mdbs + i;
952 if ((tag0 == Mnil || tag0 == mdb->tag[0])
953 && (tag1 == Mnil || tag1 == mdb->tag[1])
954 && (tag2 == Mnil || tag2 == mdb->tag[2])
955 && (tag3 == Mnil || tag3 == mdb->tag[3]))
958 plist = pl = mplist ();
959 pl = mplist_add (pl, Mt, mdb);
967 @brief Define a data of the m17n database.
969 The mdatabase_define () function defines a data that has tags
970 $TAG0 through $TAG3 and additional information $EXTRA_INFO.
972 $LOADER is a pointer to a function that loads the data from the
973 database. This function is called from the mdatabase_load ()
974 function with the two arguments $TAGS and $EXTRA_INFO. Here,
975 $TAGS is the array of $TAG0 through $TAG3.
977 If $LOADER is @c NULL, the default loader of the m17n library is
978 used. In this case, $EXTRA_INFO must be a string specifying a
979 filename that contains the data.
982 If the operation was successful, mdatabase_define () returns a
983 pointer to the defined data, which can be used as an argument to
984 mdatabase_load (). Otherwise, it returns @c NULL. */
987 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë.
989 ´Ø¿ô mdatabase_define () ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ª¤è¤ÓÉղþðÊó
990 $EXTRA_INFO ¤ò»ý¤Ä¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë¡£
992 $LOADER ¤Ï¤½¤Î¥Ç¡¼¥¿¤Î¥í¡¼¥É¤ËÍѤ¤¤é¤ì¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï
993 mdatabase_load () ¤«¤é $TAGS ¤È $EXTRA_INFO ¤È¤¤¤¦Æó¤Ä¤Î°ú¿ôÉÕ¤¤Ç¸Æ¤Ó½Ð¤µ¤ì¤ë¡£¤³¤³¤Ç
994 $TAGS ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤ÎÇÛÎó¤Ç¤¢¤ë¡£
996 ¤â¤· $LOADER ¤¬ @c NULL ¤Ê¤é¡¢m17n ¥é¥¤¥Ö¥é¥êɸ½à¤Î¥í¡¼¥À¤¬»È¤ï¤ì¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï
997 $EXTRA_INFO ¤Ï¥Ç¡¼¥¿¤ò´Þ¤à¥Õ¥¡¥¤¥ë̾¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1000 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mdatabase_define ()
1001 ¤ÏÄêµÁ¤µ¤ì¤¿¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¥Ý¥¤¥ó¥¿¤Ï´Ø¿ô mdatabase_load ()
1002 ¤Î°ú¿ô¤È¤·¤ÆÍѤ¤¤ë¤³¤È¤¬¤Ç¤¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1004 @latexonly \IPAlabel{mdatabase_define} @endlatexonly */
1008 mdatabase_load (), mdatabase_define () */
1011 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
1012 void *(*loader) (MSymbol *, void *),
1017 mdb = mdatabase_find (tag0, tag1, tag2, tag3);
1022 template.tag[0] = tag0, template.tag[1] = tag1;
1023 template.tag[2] = tag2, template.tag[3] = tag3;
1024 template.extra_info = NULL;
1025 MLIST_APPEND1 (&mdb_list, mdbs, template, MERROR_DB);
1026 mdb = mdb_list.mdbs + (mdb_list.used - 1);
1028 mdb->loader = loader ? loader : load_database;
1029 if (mdb->loader == load_database)
1031 MDatabaseInfo *db_info = mdb->extra_info;
1034 free (db_info->filename);
1036 db_info = mdb->extra_info = malloc (sizeof (MDatabaseInfo));
1037 db_info->filename = strdup ((char *) extra_info);
1041 mdb->extra_info = extra_info;
1042 return (&(mdb_list.mdbs[mdb_list.used - 1]));
1047 @brief Load a data from the database.
1049 The mdatabase_load () function loads a data specified in $MDB and
1050 returns the contents. The type of contents depends on the type of
1053 If the data is of the @e plist @e type, this function returns a
1054 pointer to @e plist.
1056 If the database is of the @e chartable @e type, it returns a
1057 chartable. The default value of the chartable is set according to
1058 the second tag of the data as below:
1060 @li If the tag is #Msymbol, the default value is #Mnil.
1061 @li If the tag is #Minteger, the default value is -1.
1062 @li Otherwise, the default value is @c NULL.
1064 If the data is of the @e charset @e type, it returns a plist of length 2
1065 (keys are both #Mt). The value of the first element is an array
1066 of integers that maps code points to the corresponding character
1067 codes. The value of the second element is a chartable of integers
1068 that does the reverse mapping. The charset must be defined in
1073 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿¤ò¥í¡¼¥É¤¹¤ë.
1075 ´Ø¿ô mdatabase_load () ¤Ï $MDB
1076 ¤¬»Ø¤¹¥Ç¡¼¥¿¤ò¥í¡¼¥É¤·¡¢¤½¤ÎÃæ¿È¤òÊÖ¤¹¡£ÊÖ¤µ¤ì¤ë¤â¤Î¤Ï¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ°Û¤Ê¤ë¡£
1078 ¥Ç¡¼¥¿¤¬ @e plist¥¿¥¤¥× ¤Ê¤é¤Ð¡¢ @e plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1080 ¥Ç¡¼¥¿¤¬ @e chartable¥¿¥¤¥× ¤Ê¤é¤Ðʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£
1081 ʸ»ú¥Æ¡¼¥Ö¥ë¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤϡ¢¥Ç¡¼¥¿¤ÎÂè2¥¿¥°¤Ë¤è¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Ë·è¤Þ¤ë¡£
1083 @li ¥¿¥°¤¬ #Msymbol ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï #Mnil
1084 @li ¥¿¥°¤¬ #Minteger ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï -1
1085 @li ¤½¤ì°Ê³°¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï @c NULL
1087 ¥Ç¡¼¥¿¤¬ @e charset¥¿¥¤¥× ¤Ê¤é¤ÐŤµ 2 ¤Î plist ¤òÊÖ¤¹¡Ê¥¡¼¤Ï¶¦¤Ë#Mt ¡Ë¡£
1088 ºÇ½é¤ÎÍ×ÁǤÎÃͤϥ³¡¼¥É¥Ý¥¤¥ó¥È¤òÂбþ¤¹¤ëʸ»ú¥³¡¼¥É¤Ë¥Þ¥Ã¥×¤¹¤ëÀ°¿ô¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1089 £²ÈÖÌܤÎÍ×ÁǤÎÃͤϵդΥޥåפò¤¹¤ëʸ»ú¥Æ¡¼¥Ö¥ë¤Ç¤¢¤ë¡£
1090 ¤³¤Îʸ»ú¥»¥Ã¥È¤Ïͽ¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
1092 @latexonly \IPAlabel{mdatabase_load} @endlatexonly
1097 mdatabase_load (), mdatabase_define () */
1100 mdatabase_load (MDatabase *mdb)
1102 int mdebug_mask = MDEBUG_DATABASE;
1105 MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
1106 gen_database_name (buf, mdb->tag));
1107 return (*mdb->loader) (mdb->tag, mdb->extra_info);
1112 @brief Get tags of a data.
1114 The mdatabase_tag () function returns an array of tags (symbols)
1115 that identify the data in $MDB. The length of the array is
1119 @brief ¥Ç¡¼¥¿¤Î¥¿¥°¤òÆÀ¤ë.
1121 ´Ø¿ô mdatabase_tag () ¤Ï¡¢¥Ç¡¼¥¿ $MDB ¤Î¥¿¥°¡Ê¥·¥ó¥Ü¥ë¡Ë¤ÎÇÛÎó¤òÊÖ¤¹¡£ÇÛÎó¤ÎŤµ¤Ï
1124 @latexonly \IPAlabel{mdatabase_tag} @endlatexonly */
1127 mdatabase_tag (MDatabase *mdb)