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., 51 Franklin Street, Fifth Floor,
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>
140 #include "m17n-misc.h"
141 #include "internal.h"
143 #include "character.h"
145 #include "database.h"
149 /** The file containing a list of databases. */
150 #define MDB_DIR "mdb.dir"
151 /** Length of MDB_DIR. */
152 #define MDB_DIR_LEN 7
154 #define MAX_TIME(TIME1, TIME2) ((TIME1) >= (TIME2) ? (TIME1) : (TIME2))
156 #define GEN_PATH(path, dir, dir_len, file, file_len) \
157 (dir_len + file_len > PATH_MAX ? 0 \
158 : (memcpy (path, dir, dir_len), \
159 memcpy (path + dir_len, file, file_len), \
160 path[dir_len + file_len] = '\0', 1))
162 static MSymbol Masterisk;
163 static MSymbol Mversion;
165 /** Structure for a data in the m17n database. */
169 /** Tags to identify the data. <tag>[0] specifies the type of
170 database. If it is #Mchar_table, the type is @e chartable, if
171 it is #Mcharset, the type is @e charset, otherwise the type is
175 void *(*loader) (MSymbol *tags, void *extra_info);
177 /** The meaning of the value is dependent on <loader>. If <loader>
178 is load_database (), the value is a string of the file name that
179 contains the data. */
183 static MPlist *mdatabase__list;
186 read_number (char *buf, int *i)
195 while (c && isspace (c)) c = buf[idx++];
201 for (idx++, c = 0; (n = hex_mnemonic[(unsigned) buf[idx]]) < 16;
215 n = escape_mnemonic[c];
219 while (buf[idx] && buf[idx++] != '\'');
223 else if (hex_mnemonic[c] < 10)
228 while ((n = hex_mnemonic[(unsigned) buf[idx]]) < 10)
229 c = (c * 10) + n, idx++;
235 /** Load a data of type @c chartable from the file FD, and return the
236 newly created chartable. */
239 load_chartable (FILE *fp, MSymbol type)
247 MERROR (MERROR_DB, NULL);
249 table = mchartable (type, (type == Msymbol ? (void *) Mnil
250 : type == Minteger ? (void *) -1
257 for (len = 0; len < 1023 && (c = getc (fp)) != EOF && c != '\n'; len++)
260 if (hex_mnemonic[(unsigned) buf[0]] >= 10)
261 /* skip comment/invalid line */
264 from = read_number (buf, &i);
266 i++, to = read_number (buf, &i);
269 if (from < 0 || to < from)
272 while (buf[i] && isspace ((unsigned) buf[i])) i++;
279 /* VAL is a C-string. */
280 if (! (val = strdup (buf + i)))
281 MEMORY_FULL (MERROR_DB);
283 else if (type == Minteger)
285 /* VAL is an integer. */
291 n = read_number (buf, &i);
294 val = (void *) (n * positive);
296 else if (type == Mtext)
298 /* VAL is an M-text. */
301 mt = mconv_decode_buffer (Mcoding_utf_8,
302 (unsigned char *) (buf + i),
307 while ((c = read_number (buf, &i)) >= 0)
308 mt = mtext_cat_char (mt, c);
312 else if (type == Msymbol)
316 while (*p && ! isspace (*p))
318 if (*p == '\\' && p[1] != '\0')
320 memmove (p, p + 1, buf + len - (p + 1));
326 if (! strcmp (buf + i, "nil"))
329 val = (void *) msymbol (buf + i);
331 else if (type == Mplist)
333 val = (void *) mplist__from_string ((unsigned char *) buf + i,
340 mchartable_set (table, from, val);
342 mchartable_set_range (table, from, to, val);
347 M17N_OBJECT_UNREF (table);
348 MERROR (MERROR_DB, NULL);
352 /** Load a data of type @c charset from the file FD. */
355 load_charset (FILE *fp, MSymbol charset_name)
357 MCharset *charset = MCHARSET (charset_name);
366 MERROR (MERROR_DB, NULL);
367 size = (charset->code_range[15]
368 - (charset->min_code - charset->code_range_min_code));
369 MTABLE_MALLOC (decoder, size, MERROR_DB);
370 for (i = 0; i < size; i++)
372 encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
374 while ((c = getc (fp)) != EOF)
376 unsigned code1, code2, c1, c2;
381 fgets (buf, 256, fp);
384 if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
386 idx1 = CODE_POINT_TO_INDEX (charset, code1);
389 idx2 = CODE_POINT_TO_INDEX (charset, code2);
392 c2 = c1 + (idx2 - idx1);
394 else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
396 idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
403 if (idx1 >= 0 && idx2 >= 0)
406 mchartable_set (encoder, c1, (void *) code1);
407 for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
409 code1 = INDEX_TO_CODE_POINT (charset, idx1);
411 mchartable_set (encoder, c1, (void *) code1);
421 M17N_OBJECT_UNREF (encoder);
425 mplist_add (plist, Mt, decoder);
426 mplist_add (plist, Mt, encoder);
431 gen_database_name (char *buf, MSymbol *tags)
435 strcpy (buf, msymbol_name (tags[0]));
436 for (i = 1; i < 4; i++)
439 strcat (buf, msymbol_name (tags[i]));
445 find_file (MDatabaseInfo *db_info, struct stat *buf)
448 char path[PATH_MAX + 1];
450 MPLIST_DO (plist, mdatabase__dir_list)
452 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
454 if (dir_info->status != MDB_STATUS_DISABLED
455 && GEN_PATH (path, dir_info->filename, dir_info->len,
456 db_info->filename, db_info->len)
457 && stat (path, buf) == 0)
458 return strdup (path);
464 /* Return the absolute file name for DB_INFO->filename. If BUF is
465 non-NULL, store the result of `stat' call in it. It returns NULL
466 if no absolute file name was found. */
469 get_database_file (MDatabaseInfo *db_info, struct stat *buf)
471 if (db_info->status == MDB_STATUS_DISABLED)
473 if (db_info->absolute_filename)
476 stat (db_info->absolute_filename, buf);
480 struct stat stat_buf;
481 struct stat *statbuf = buf ? buf : &stat_buf;
483 db_info->absolute_filename = find_file (db_info, statbuf);
486 return db_info->absolute_filename;
490 load_database (MSymbol *tags, void *extra_info)
492 MDatabaseInfo *db_info = extra_info;
494 char *filename = get_database_file (db_info, NULL);
496 int mdebug_mask = MDEBUG_DATABASE;
499 MDEBUG_PRINT1 (" [DB] <%s>", gen_database_name (buf, tags));
500 if (! filename || ! (fp = fopen (filename, "r")))
503 MDEBUG_PRINT1 (" open fail: %s\n", filename);
505 MDEBUG_PRINT1 (" not found: %s\n", db_info->filename);
506 MERROR (MERROR_DB, NULL);
509 MDEBUG_PRINT1 (" from %s\n", filename);
511 if (tags[0] == Mchar_table)
512 value = load_chartable (fp, tags[1]);
513 else if (tags[0] == Mcharset)
514 value = load_charset (fp, tags[1]);
516 value = mplist__from_file (fp, NULL);
520 MERROR (MERROR_DB, NULL);
521 db_info->time = time (NULL);
526 /** Return a newly allocated MDatabaseInfo for DIRNAME. */
528 static MDatabaseInfo *
529 get_dir_info (char *dirname)
531 MDatabaseInfo *dir_info;
533 MSTRUCT_CALLOC (dir_info, MERROR_DB);
536 int len = strlen (dirname);
538 if (len + MDB_DIR_LEN < PATH_MAX)
540 MTABLE_MALLOC (dir_info->filename, len + 2, MERROR_DB);
541 memcpy (dir_info->filename, dirname, len + 1);
542 /* Append PATH_SEPARATOR if DIRNAME doesn't end with it. */
543 if (dir_info->filename[len - 1] != PATH_SEPARATOR)
545 dir_info->filename[len] = PATH_SEPARATOR;
546 dir_info->filename[++len] = '\0';
549 dir_info->status = MDB_STATUS_OUTDATED;
552 dir_info->status = MDB_STATUS_DISABLED;
555 dir_info->status = MDB_STATUS_DISABLED;
560 find_database (MSymbol tags[4])
565 if (! mdatabase__list)
567 for (i = 0, plist = mdatabase__list; i < 4; i++)
569 plist = mplist__assq (plist, tags[i]);
572 plist = MPLIST_PLIST (plist);
573 plist = MPLIST_NEXT (plist);
575 return MPLIST_VAL (plist);
579 free_db_info (MDatabaseInfo *db_info)
581 free (db_info->filename);
582 if (db_info->absolute_filename
583 && db_info->filename != db_info->absolute_filename)
584 free (db_info->absolute_filename);
589 check_version (MText *version)
591 char *verstr = (char *) MTEXT_DATA (version);
592 char *endp = verstr + mtext_nbytes (version);
596 ver[0] = ver[1] = ver[2] = 0;
597 for (i = 0; verstr < endp; verstr++)
606 if (! isdigit (*verstr))
608 ver[i] = ver[i] * 10 + (*verstr - '0');
610 return (ver[0] < M17NLIB_MAJOR_VERSION
611 || (ver[0] == M17NLIB_MAJOR_VERSION
612 && (ver[1] < M17NLIB_MINOR_VERSION
613 || (ver[1] == M17NLIB_MINOR_VERSION
614 && ver[2] <= M17NLIB_PATCH_LEVEL))));
618 register_database (MSymbol tags[4],
619 void *(*loader) (MSymbol *, void *),
620 void *extra_info, enum MDatabaseStatus status,
624 MDatabaseInfo *db_info;
630 MPLIST_DO (plist, properties)
631 if (MPLIST_PLIST_P (plist))
633 MPlist *p = MPLIST_PLIST (pl);
635 if (MPLIST_SYMBOL_P (p)
636 && MPLIST_SYMBOL (p) == Mversion
637 && MPLIST_MTEXT_P (MPLIST_NEXT (p)))
639 if (check_version (MPLIST_MTEXT (MPLIST_NEXT (p))))
646 if (! mdatabase__list)
647 mdatabase__list = mplist ();
649 for (i = 0, plist = mdatabase__list; i < 4; i++)
651 MPlist *pl = mplist__assq (plist, tags[i]);
654 pl = MPLIST_PLIST (pl);
658 mplist_add (pl, Msymbol, tags[i]);
659 mplist_push (plist, Mplist, pl);
660 M17N_OBJECT_UNREF (pl);
662 plist = MPLIST_NEXT (pl);
665 if (MPLIST_TAIL_P (plist))
667 MSTRUCT_MALLOC (mdb, MERROR_DB);
668 for (i = 0; i < 4; i++)
669 mdb->tag[i] = tags[i];
670 mdb->loader = loader;
671 if (loader == load_database)
673 MSTRUCT_CALLOC (db_info, MERROR_DB);
674 mdb->extra_info = db_info;
679 mdb->extra_info = extra_info;
681 mplist_push (plist, Mt, mdb);
685 mdb = MPLIST_VAL (plist);
686 if (loader == load_database)
687 db_info = mdb->extra_info;
694 db_info->status = status;
695 if (! db_info->filename
696 || strcmp (db_info->filename, (char *) extra_info) != 0)
698 if (db_info->filename)
699 free (db_info->filename);
700 if (db_info->absolute_filename
701 && db_info->filename != db_info->absolute_filename)
702 free (db_info->absolute_filename);
703 db_info->filename = strdup ((char *) extra_info);
704 db_info->len = strlen ((char *) extra_info);
707 if (db_info->filename[0] == PATH_SEPARATOR)
708 db_info->absolute_filename = db_info->filename;
710 db_info->absolute_filename = NULL;
713 if (mdb->tag[0] == Mchar_table
714 && mdb->tag[2] != Mnil
715 && (mdb->tag[1] == Mstring || mdb->tag[1] == Mtext
716 || mdb->tag[1] == Msymbol || mdb->tag[1] == Minteger
717 || mdb->tag[1] == Mplist))
718 mchar__define_prop (mdb->tag[2], mdb->tag[1], mdb);
723 register_databases_in_files (MSymbol tags[4], glob_t *globbuf, int headlen)
726 MPlist *load_key = mplist ();
730 for (i = 0; i < globbuf->gl_pathc; i++)
732 if (! (fp = fopen (globbuf->gl_pathv[i], "r")))
734 plist = mplist__from_file (fp, load_key);
738 if (MPLIST_PLIST_P (plist))
743 for (j = 0, pl = MPLIST_PLIST (plist); j < 4 && MPLIST_SYMBOL_P (pl);
744 j++, pl = MPLIST_NEXT (pl))
745 tags2[j] = MPLIST_SYMBOL (pl);
748 for (j = 0; j < 4; j++)
749 if (tags[j] == Masterisk ? tags2[j] == Mnil
750 : (tags[j] != Mnil && tags[j] != tags2[j]))
753 register_database (tags2, load_database,
754 globbuf->gl_pathv[i] + headlen,
755 MDB_STATUS_AUTO, pl);
757 M17N_OBJECT_UNREF (plist);
759 M17N_OBJECT_UNREF (load_key);
765 /** List of database directories. */
766 MPlist *mdatabase__dir_list;
771 MDatabaseInfo *dir_info;
774 Mchar_table = msymbol ("char-table");
775 Masterisk = msymbol ("*");
776 Mversion = msymbol ("version");
778 mdatabase__dir_list = mplist ();
779 /** The macro M17NDIR specifies a directory where the system-wide
780 MDB_DIR file exists. */
781 mplist_set (mdatabase__dir_list, Mt, get_dir_info (M17NDIR));
783 /* The variable mdatabase_dir specifies a directory where an
784 application program specific MDB_DIR file exists. */
785 if (mdatabase_dir && strlen (mdatabase_dir) > 0)
786 mplist_push (mdatabase__dir_list, Mt, get_dir_info (mdatabase_dir));
788 /* The environment variable M17NDIR specifies a directory where a
789 user specific MDB_DIR file exists. */
790 path = getenv ("M17NDIR");
791 if (path && strlen (path) > 0)
792 mplist_push (mdatabase__dir_list, Mt, get_dir_info (path));
795 /* If the env var M17NDIR is not set, check "~/.m17n.d". */
796 char *home = getenv ("HOME");
800 && (len = strlen (home))
801 && (path = alloca (len + 9)))
804 if (path[len - 1] != PATH_SEPARATOR)
805 path[len++] = PATH_SEPARATOR;
806 strcpy (path + len, ".m17n.d");
807 dir_info = get_dir_info (path);
808 mplist_push (mdatabase__dir_list, Mt, dir_info);
811 mplist_push (mdatabase__dir_list, Mt, get_dir_info (NULL));
814 mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
816 mdatabase__loader = (void *(*) (void *)) mdatabase_load;
818 mdatabase__list = mplist ();
819 mdatabase__update ();
824 mdatabase__fini (void)
826 MPlist *plist, *p0, *p1, *p2, *p3;
828 MPLIST_DO (plist, mdatabase__dir_list)
829 free_db_info (MPLIST_VAL (plist));
830 M17N_OBJECT_UNREF (mdatabase__dir_list);
832 /* MDATABASE_LIST ::= ((TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) ...) */
833 MPLIST_DO (plist, mdatabase__list)
835 p0 = MPLIST_PLIST (plist);
836 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) */
837 MPLIST_DO (p0, MPLIST_NEXT (p0))
839 p1 = MPLIST_PLIST (p0);
840 /* P1 ::= (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) */
841 MPLIST_DO (p1, MPLIST_NEXT (p1))
843 p2 = MPLIST_PLIST (p1);
844 /* P2 ::= (TAG2 (TAG3 t:MDB) ...) */
845 MPLIST_DO (p2, MPLIST_NEXT (p2))
849 p3 = MPLIST_PLIST (p2); /* P3 ::= (TAG3 t:MDB) */
850 p3 = MPLIST_NEXT (p3);
851 mdb = MPLIST_VAL (p3);
852 if (mdb->loader == load_database)
853 free_db_info (mdb->extra_info);
859 M17N_OBJECT_UNREF (mdatabase__list);
863 mdatabase__update (void)
865 MPlist *plist, *p0, *p1, *p2, *p3;
866 char path[PATH_MAX + 1];
867 MDatabaseInfo *dir_info;
871 /* Update elements of mdatabase__dir_list. */
872 MPLIST_DO (plist, mdatabase__dir_list)
874 dir_info = MPLIST_VAL (plist);
875 if (dir_info->filename)
877 if (stat (dir_info->filename, &statbuf) == 0
878 && (statbuf.st_mode & S_IFDIR))
880 if (dir_info->time < statbuf.st_mtime)
883 dir_info->time = statbuf.st_mtime;
885 if (GEN_PATH (path, dir_info->filename, dir_info->len,
886 MDB_DIR, MDB_DIR_LEN)
887 && stat (path, &statbuf) >= 0
888 && dir_info->time < statbuf.st_mtime)
891 dir_info->time = statbuf.st_mtime;
893 dir_info->status = MDB_STATUS_UPDATED;
897 if (dir_info->status != MDB_STATUS_DISABLED)
901 dir_info->status = MDB_STATUS_DISABLED;
910 /* At first, mark all databases defined automatically from mdb.dir
911 file(s) as "disabled". */
912 MPLIST_DO (plist, mdatabase__list)
914 p0 = MPLIST_PLIST (plist);
915 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
916 MPLIST_DO (p0, MPLIST_NEXT (p0))
918 p1 = MPLIST_PLIST (p0);
919 MPLIST_DO (p1, MPLIST_NEXT (p1))
921 p2 = MPLIST_PLIST (p1);
922 MPLIST_DO (p2, MPLIST_NEXT (p2))
925 MDatabaseInfo *db_info;
927 p3 = MPLIST_PLIST (p2);
928 p3 = MPLIST_NEXT (p3);
929 mdb = MPLIST_VAL (p3);
930 db_info = mdb->extra_info;
931 if (db_info->status == MDB_STATUS_AUTO)
932 db_info->status = MDB_STATUS_DISABLED;
939 MPLIST_DO (p0, mdatabase__dir_list)
940 mplist_push (plist, MPLIST_KEY (p0), MPLIST_VAL (p0));
942 while (! MPLIST_TAIL_P (plist))
944 MDatabaseInfo *dir_info = mplist_pop (plist);
949 if (dir_info->status == MDB_STATUS_DISABLED)
951 if (! GEN_PATH (path, dir_info->filename, dir_info->len,
952 MDB_DIR, MDB_DIR_LEN))
954 if (! (fp = fopen (path, "r")))
956 pl = mplist__from_file (fp, NULL);
966 int with_wildcard = 0;
968 if (! MPLIST_PLIST_P (p))
970 for (i = 0, p1 = MPLIST_PLIST (p); i < 4 && MPLIST_SYMBOL_P (p1);
971 i++, p1 = MPLIST_NEXT (p1))
972 with_wildcard |= ((tags[i] = MPLIST_SYMBOL (p1)) == Masterisk);
974 || tags[0] == Masterisk
975 || ! MPLIST_MTEXT_P (p1))
979 mt = MPLIST_MTEXT (p1);
980 nbytes = mtext_nbytes (mt);
981 if (nbytes > PATH_MAX)
983 memcpy (path, MTEXT_DATA (mt), nbytes);
990 if (tags[0] == Mchar_table || tags[0] == Mcharset)
992 if (path[0] == PATH_SEPARATOR)
994 if (glob (path, GLOB_NOSORT, NULL, &globbuf))
996 register_databases_in_files (tags, &globbuf, 0);
1000 MPLIST_DO (dlist, mdatabase__dir_list)
1002 MDatabaseInfo *d_info = MPLIST_VAL (dlist);
1004 if (d_info->status == MDB_STATUS_DISABLED)
1006 if (! GEN_PATH (path, d_info->filename, d_info->len,
1007 MTEXT_DATA (mt), nbytes))
1009 if (glob (path, GLOB_NOSORT, NULL, &globbuf))
1011 register_databases_in_files (tags, &globbuf, d_info->len);
1012 globfree (&globbuf);
1016 register_database (tags, load_database, path, MDB_STATUS_AUTO, pl);
1018 M17N_OBJECT_UNREF (pl);
1020 M17N_OBJECT_UNREF (plist);
1024 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
1026 int mdebug_mask = MDEBUG_DATABASE;
1027 MDatabaseInfo *db_info;
1033 if (mdb->loader != load_database
1034 || mdb->tag[0] == Mchar_table
1035 || mdb->tag[0] == Mcharset)
1036 MERROR (MERROR_DB, NULL);
1037 MDEBUG_PRINT1 (" [DB] <%s>.\n",
1038 gen_database_name (name, mdb->tag));
1039 db_info = mdb->extra_info;
1040 filename = get_database_file (db_info, NULL);
1041 if (! filename || ! (fp = fopen (filename, "r")))
1042 MERROR (MERROR_DB, NULL);
1043 plist = mplist__from_file (fp, keys);
1049 /* Check if the database MDB should be reloaded or not. It returns:
1051 1: The database has not been updated since it was loaded last
1054 0: The database has never been loaded or has been updated
1055 since it was loaded last time.
1057 -1: The database is not loadable at the moment. */
1060 mdatabase__check (MDatabase *mdb)
1062 MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
1065 if (! get_database_file (db_info, &buf))
1067 if (db_info->time < buf.st_mtime)
1069 if (db_info->status == MDB_STATUS_AUTO
1070 && db_info->filename != db_info->absolute_filename)
1074 mdatabase__update ();
1075 new = find_database (mdb->tag);
1083 /* Search directories in mdatabase__dir_list for file FILENAME. If
1084 the file exist, return the absolute pathname. If FILENAME is
1085 already absolute, return a copy of it. */
1088 mdatabase__find_file (char *filename)
1091 MDatabaseInfo db_info;
1093 if (filename[0] == PATH_SEPARATOR)
1094 return (stat (filename, &buf) == 0 ? filename : NULL);
1095 db_info.filename = filename;
1096 db_info.len = strlen (filename);
1098 db_info.absolute_filename = NULL;
1099 if (! get_database_file (&db_info, &buf)
1100 || stat (db_info.absolute_filename, &buf) < 0)
1102 return db_info.absolute_filename;
1106 mdatabase__file (MDatabase *mdb)
1108 MDatabaseInfo *db_info;
1110 if (mdb->loader != load_database)
1112 db_info = mdb->extra_info;
1113 return get_database_file (db_info, NULL);
1117 mdatabase__lock (MDatabase *mdb)
1119 MDatabaseInfo *db_info;
1125 if (mdb->loader != load_database)
1127 db_info = mdb->extra_info;
1128 if (db_info->lock_file)
1130 file = get_database_file (db_info, NULL);
1133 len = strlen (file);
1134 db_info->uniq_file = malloc (len + 35);
1135 if (! db_info->uniq_file)
1137 db_info->lock_file = malloc (len + 5);
1138 if (! db_info->lock_file)
1140 free (db_info->uniq_file);
1143 sprintf (db_info->uniq_file, "%s.%X.%X", db_info->absolute_filename,
1144 (unsigned) time (NULL), (unsigned) getpid ());
1145 sprintf (db_info->lock_file, "%s.LCK", db_info->absolute_filename);
1147 fp = fopen (db_info->uniq_file, "w");
1150 char *str = strdup (db_info->uniq_file);
1151 char *dir = dirname (str);
1153 if (stat (dir, &buf) == 0
1154 || mkdir (dir, 0777) < 0
1155 || ! (fp = fopen (db_info->uniq_file, "w")))
1157 free (db_info->uniq_file);
1158 free (db_info->lock_file);
1159 db_info->lock_file = NULL;
1166 if (link (db_info->uniq_file, db_info->lock_file) < 0
1167 && (stat (db_info->uniq_file, &buf) < 0
1168 || buf.st_nlink != 2))
1170 unlink (db_info->uniq_file);
1171 unlink (db_info->lock_file);
1172 free (db_info->uniq_file);
1173 free (db_info->lock_file);
1174 db_info->lock_file = NULL;
1181 mdatabase__save (MDatabase *mdb, MPlist *data)
1183 MDatabaseInfo *db_info;
1189 if (mdb->loader != load_database)
1191 db_info = mdb->extra_info;
1192 if (! db_info->lock_file)
1194 file = get_database_file (db_info, NULL);
1198 if (mplist__serialize (mt, data, 1) < 0)
1200 M17N_OBJECT_UNREF (mt);
1203 fp = fopen (db_info->uniq_file, "w");
1206 M17N_OBJECT_UNREF (mt);
1209 mconv_encode_stream (msymbol ("utf-8"), mt, fp);
1210 M17N_OBJECT_UNREF (mt);
1212 if ((ret = rename (db_info->uniq_file, file)) < 0)
1213 unlink (db_info->uniq_file);
1214 free (db_info->uniq_file);
1215 db_info->uniq_file = NULL;
1220 mdatabase__unlock (MDatabase *mdb)
1222 MDatabaseInfo *db_info;
1224 if (mdb->loader != load_database)
1226 db_info = mdb->extra_info;
1227 if (! db_info->lock_file)
1229 unlink (db_info->lock_file);
1230 free (db_info->lock_file);
1231 db_info->lock_file = NULL;
1232 if (db_info->uniq_file)
1234 unlink (db_info->uniq_file);
1235 free (db_info->uniq_file);
1241 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1246 /*** @addtogroup m17nDatabase */
1251 @brief Directory for application specific data.
1253 If an application program wants to provide a data specific to the
1254 program or a data overriding what supplied by the m17n database,
1255 it must set this variable to a name of directory that contains the
1256 data files before it calls the macro M17N_INIT (). The directory
1257 may contain a file "mdb.dir" which contains a list of data
1258 definitions in the format described in @ref mdbDir "mdbDir(5)".
1260 The default value is NULL. */
1262 @brief ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¸ÇͤΥǡ¼¥¿Íѥǥ£¥ì¥¯¥È¥ê.
1264 ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬¡¢¤½¤Î¥×¥í¥°¥é¥à¸ÇͤΥǡ¼¥¿¤ä m17n
1265 ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¾å½ñ¤¤¹¤ë¥Ç¡¼¥¿¤òÄ󶡤¹¤ë¾ì¹ç¤Ë¤Ï¡¢¥Þ¥¯¥í M17N_INIT ()
1266 ¤ò¸Æ¤ÖÁ°¤Ë¤³¤ÎÊÑ¿ô¤ò¥Ç¡¼¥¿¥Õ¥¡¥¤¥ë¤ò´Þ¤à¥Ç¥£¥ì¥¯¥È¥ê̾¤Ë¥»¥Ã¥È¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤Ï
1267 "mdb.dir" ¥Õ¥¡¥¤¥ë¤ò¤ª¤¯¤³¤È¤¬¤Ç¤¤ë¡£¤½¤Î"mdb.dir"¥Õ¥¡¥¤¥ë¤Ë¤Ï¡¢
1268 @ref mdbDir "mdbDir(5)" ¤ÇÀâÌÀ¤µ¤ì¤Æ¤¤¤ë¥Õ¥©¡¼¥Þ¥Ã¥È¤Ç¥Ç¡¼¥¿ÄêµÁ¤Î¥ê¥¹¥È¤òµ½Ò¤¹¤ë¡£
1270 ¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¤Ï NULL ¤Ç¤¢¤ë¡£ */
1272 char *mdatabase_dir;
1276 @brief Look for a data in the database.
1278 The mdatabase_find () function searches the m17n database for a
1279 data who has tags $TAG0 through $TAG3, and returns a pointer to
1280 the data. If such a data is not found, it returns @c NULL. */
1283 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹Ãæ¤Î¥Ç¡¼¥¿¤òõ¤¹.
1285 ´Ø¿ô mdatabase_find () ¤Ï¡¢ m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ãæ¤Ç $TAG0 ¤«¤é
1286 $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤Î¤è¤¦¤Ê¥Ç¡¼¥¿¤¬¤Ê¤±¤ì¤Ð
1289 @latexonly \IPAlabel{mdatabase_find} @endlatexonly */
1292 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
1296 mdatabase__update ();
1297 tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
1298 return find_database (tags);
1303 @brief Return a data list of the m17n database.
1305 The mdatabase_list () function searches the m17n database for data
1306 who have tags $TAG0 through $TAG3, and returns their list by a
1307 plist. The value #Mnil in $TAGn means a wild card that matches
1308 any tag. Each element of the plist has key #Mt and value a
1309 pointer to type #MDatabase. */
1311 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¥ê¥¹¥È¤òÊÖ¤¹.
1313 ´Ø¿ô mdatabase_list () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é $TAG0 ¤«¤é$TAG3
1314 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤Î¥ê¥¹¥È¤òplist ¤È¤·¤ÆÊÖ¤¹¡£ $TAGn ¤¬ #Mnil
1315 ¤Ç¤¢¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥¿¥°¤Ë¥Þ¥Ã¥Á¤¹¤ë¥ï¥¤¥ë¥É¥«¡¼¥É¤È¤·¤Æ¼è¤ê°·¤ï¤ì¤ë¡£ÊÖ¤µ¤ì¤ë
1316 plist ¤Î³ÆÍ×ÁǤϥ¡¼ ¤È¤·¤Æ #Mt ¤ò¡¢ÃͤȤ·¤Æ #MDatabase ·¿¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò»ý¤Ä¡£ */
1319 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
1321 MPlist *plist = mplist (), *pl = plist;
1322 MPlist *p, *p0, *p1, *p2, *p3;
1324 mdatabase__update ();
1326 MPLIST_DO (p, mdatabase__list)
1328 p0 = MPLIST_PLIST (p);
1329 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
1330 if (tag0 != Mnil && MPLIST_SYMBOL (p0) != tag0)
1332 MPLIST_DO (p0, MPLIST_NEXT (p0))
1334 p1 = MPLIST_PLIST (p0);
1335 if (tag1 != Mnil && MPLIST_SYMBOL (p1) != tag1)
1337 MPLIST_DO (p1, MPLIST_NEXT (p1))
1339 p2 = MPLIST_PLIST (p1);
1340 if (tag2 != Mnil && MPLIST_SYMBOL (p2) != tag2)
1342 MPLIST_DO (p2, MPLIST_NEXT (p2))
1344 p3 = MPLIST_PLIST (p2);
1345 if (tag3 != Mnil && MPLIST_SYMBOL (p3) != tag3)
1347 p3 = MPLIST_NEXT (p3);
1348 pl = mplist_add (pl, Mt, MPLIST_VAL (p3));
1353 if (MPLIST_TAIL_P (plist))
1355 M17N_OBJECT_UNREF (plist);
1363 @brief Define a data of the m17n database.
1365 The mdatabase_define () function defines a data that has tags
1366 $TAG0 through $TAG3 and additional information $EXTRA_INFO.
1368 $LOADER is a pointer to a function that loads the data from the
1369 database. This function is called from the mdatabase_load ()
1370 function with the two arguments $TAGS and $EXTRA_INFO. Here,
1371 $TAGS is the array of $TAG0 through $TAG3.
1373 If $LOADER is @c NULL, the default loader of the m17n library is
1374 used. In this case, $EXTRA_INFO must be a string specifying a
1375 filename that contains the data.
1378 If the operation was successful, mdatabase_define () returns a
1379 pointer to the defined data, which can be used as an argument to
1380 mdatabase_load (). Otherwise, it returns @c NULL. */
1383 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë.
1385 ´Ø¿ô mdatabase_define () ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ª¤è¤ÓÉղþðÊó
1386 $EXTRA_INFO ¤ò»ý¤Ä¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë¡£
1388 $LOADER ¤Ï¤½¤Î¥Ç¡¼¥¿¤Î¥í¡¼¥É¤ËÍѤ¤¤é¤ì¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï
1389 mdatabase_load () ¤«¤é $TAGS ¤È $EXTRA_INFO ¤È¤¤¤¦Æó¤Ä¤Î°ú¿ôÉÕ¤¤Ç¸Æ¤Ó½Ð¤µ¤ì¤ë¡£¤³¤³¤Ç
1390 $TAGS ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1392 ¤â¤· $LOADER ¤¬ @c NULL ¤Ê¤é¡¢m17n ¥é¥¤¥Ö¥é¥êɸ½à¤Î¥í¡¼¥À¤¬»È¤ï¤ì¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï
1393 $EXTRA_INFO ¤Ï¥Ç¡¼¥¿¤ò´Þ¤à¥Õ¥¡¥¤¥ë̾¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1396 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mdatabase_define ()
1397 ¤ÏÄêµÁ¤µ¤ì¤¿¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¥Ý¥¤¥ó¥¿¤Ï´Ø¿ô mdatabase_load ()
1398 ¤Î°ú¿ô¤È¤·¤ÆÍѤ¤¤ë¤³¤È¤¬¤Ç¤¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1400 @latexonly \IPAlabel{mdatabase_define} @endlatexonly */
1404 mdatabase_load (), mdatabase_define () */
1407 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
1408 void *(*loader) (MSymbol *, void *),
1414 tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
1416 loader = load_database;
1417 mdb = register_database (tags, loader, extra_info, MDB_STATUS_EXPLICIT, NULL);
1423 @brief Load a data from the database.
1425 The mdatabase_load () function loads a data specified in $MDB and
1426 returns the contents. The type of contents depends on the type of
1429 If the data is of the @e plist @e type, this function returns a
1430 pointer to @e plist.
1432 If the database is of the @e chartable @e type, it returns a
1433 chartable. The default value of the chartable is set according to
1434 the second tag of the data as below:
1436 @li If the tag is #Msymbol, the default value is #Mnil.
1437 @li If the tag is #Minteger, the default value is -1.
1438 @li Otherwise, the default value is @c NULL.
1440 If the data is of the @e charset @e type, it returns a plist of length 2
1441 (keys are both #Mt). The value of the first element is an array
1442 of integers that maps code points to the corresponding character
1443 codes. The value of the second element is a chartable of integers
1444 that does the reverse mapping. The charset must be defined in
1449 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿¤ò¥í¡¼¥É¤¹¤ë.
1451 ´Ø¿ô mdatabase_load () ¤Ï $MDB
1452 ¤¬»Ø¤¹¥Ç¡¼¥¿¤ò¥í¡¼¥É¤·¡¢¤½¤ÎÃæ¿È¤òÊÖ¤¹¡£ÊÖ¤µ¤ì¤ë¤â¤Î¤Ï¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ°Û¤Ê¤ë¡£
1454 ¥Ç¡¼¥¿¤¬ @e plist¥¿¥¤¥× ¤Ê¤é¤Ð¡¢ @e plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1456 ¥Ç¡¼¥¿¤¬ @e chartable¥¿¥¤¥× ¤Ê¤é¤Ðʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£
1457 ʸ»ú¥Æ¡¼¥Ö¥ë¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤϡ¢¥Ç¡¼¥¿¤ÎÂè2¥¿¥°¤Ë¤è¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Ë·è¤Þ¤ë¡£
1459 @li ¥¿¥°¤¬ #Msymbol ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï #Mnil
1460 @li ¥¿¥°¤¬ #Minteger ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï -1
1461 @li ¤½¤ì°Ê³°¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï @c NULL
1463 ¥Ç¡¼¥¿¤¬ @e charset¥¿¥¤¥× ¤Ê¤é¤ÐŤµ 2 ¤Î plist ¤òÊÖ¤¹¡Ê¥¡¼¤Ï¶¦¤Ë#Mt ¡Ë¡£
1464 ºÇ½é¤ÎÍ×ÁǤÎÃͤϥ³¡¼¥É¥Ý¥¤¥ó¥È¤òÂбþ¤¹¤ëʸ»ú¥³¡¼¥É¤Ë¥Þ¥Ã¥×¤¹¤ëÀ°¿ô¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1465 £²ÈÖÌܤÎÍ×ÁǤÎÃͤϵդΥޥåפò¤¹¤ëʸ»ú¥Æ¡¼¥Ö¥ë¤Ç¤¢¤ë¡£
1466 ¤³¤Îʸ»ú¥»¥Ã¥È¤Ïͽ¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
1468 @latexonly \IPAlabel{mdatabase_load} @endlatexonly
1473 mdatabase_load (), mdatabase_define () */
1476 mdatabase_load (MDatabase *mdb)
1478 return (*mdb->loader) (mdb->tag, mdb->extra_info);
1483 @brief Get tags of a data.
1485 The mdatabase_tag () function returns an array of tags (symbols)
1486 that identify the data in $MDB. The length of the array is
1490 @brief ¥Ç¡¼¥¿¤Î¥¿¥°¤òÆÀ¤ë.
1492 ´Ø¿ô mdatabase_tag () ¤Ï¡¢¥Ç¡¼¥¿ $MDB ¤Î¥¿¥°¡Ê¥·¥ó¥Ü¥ë¡Ë¤ÎÇÛÎó¤òÊÖ¤¹¡£ÇÛÎó¤ÎŤµ¤Ï
1495 @latexonly \IPAlabel{mdatabase_tag} @endlatexonly */
1498 mdatabase_tag (MDatabase *mdb)