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;
164 /** Structure for a data in the m17n database. */
168 /** Tags to identify the data. <tag>[0] specifies the type of
169 database. If it is #Mchar_table, the type is @e chartable, if
170 it is #Mcharset, the type is @e charset, otherwise the type is
174 void *(*loader) (MSymbol *tags, void *extra_info);
176 /** The meaning of the value is dependent on <loader>. If <loader>
177 is load_database (), the value is a string of the file name that
178 contains the data. */
182 static MPlist *mdatabase__list;
185 read_number (char *buf, int *i)
194 while (c && isspace (c)) c = buf[idx++];
200 for (idx++, c = 0; (n = hex_mnemonic[(unsigned) buf[idx]]) < 16;
214 n = escape_mnemonic[c];
218 while (buf[idx] && buf[idx++] != '\'');
222 else if (hex_mnemonic[c] < 10)
227 while ((n = hex_mnemonic[(unsigned) buf[idx]]) < 10)
228 c = (c * 10) + n, idx++;
234 /** Load a data of type @c chartable from the file FD, and return the
235 newly created chartable. */
238 load_chartable (FILE *fp, MSymbol type)
246 MERROR (MERROR_DB, NULL);
248 table = mchartable (type, (type == Msymbol ? (void *) Mnil
249 : type == Minteger ? (void *) -1
256 for (len = 0; len < 1023 && (c = getc (fp)) != EOF && c != '\n'; len++)
259 if (hex_mnemonic[(unsigned) buf[0]] >= 10)
260 /* skip comment/invalid line */
263 from = read_number (buf, &i);
265 i++, to = read_number (buf, &i);
268 if (from < 0 || to < from)
271 while (buf[i] && isspace ((unsigned) buf[i])) i++;
278 /* VAL is a C-string. */
279 if (! (val = strdup (buf + i)))
280 MEMORY_FULL (MERROR_DB);
282 else if (type == Minteger)
284 /* VAL is an integer. */
290 n = read_number (buf, &i);
293 val = (void *) (n * positive);
295 else if (type == Mtext)
297 /* VAL is an M-text. */
300 mt = mconv_decode_buffer (Mcoding_utf_8,
301 (unsigned char *) (buf + i),
306 while ((c = read_number (buf, &i)) >= 0)
307 mt = mtext_cat_char (mt, c);
311 else if (type == Msymbol)
315 while (*p && ! isspace (*p))
317 if (*p == '\\' && p[1] != '\0')
319 memmove (p, p + 1, buf + len - (p + 1));
325 if (! strcmp (buf + i, "nil"))
328 val = (void *) msymbol (buf + i);
330 else if (type == Mplist)
332 val = (void *) mplist__from_string ((unsigned char *) buf + i,
339 mchartable_set (table, from, val);
341 mchartable_set_range (table, from, to, val);
346 M17N_OBJECT_UNREF (table);
347 MERROR (MERROR_DB, NULL);
351 /** Load a data of type @c charset from the file FD. */
354 load_charset (FILE *fp, MSymbol charset_name)
356 MCharset *charset = MCHARSET (charset_name);
365 MERROR (MERROR_DB, NULL);
366 size = (charset->code_range[15]
367 - (charset->min_code - charset->code_range_min_code));
368 MTABLE_MALLOC (decoder, size, MERROR_DB);
369 for (i = 0; i < size; i++)
371 encoder = mchartable (Minteger, (void *) MCHAR_INVALID_CODE);
373 while ((c = getc (fp)) != EOF)
375 unsigned code1, code2, c1, c2;
380 fgets (buf, 256, fp);
383 if (sscanf (buf, "0x%x-0x%x 0x%x", &code1, &code2, &c1) == 3)
385 idx1 = CODE_POINT_TO_INDEX (charset, code1);
388 idx2 = CODE_POINT_TO_INDEX (charset, code2);
391 c2 = c1 + (idx2 - idx1);
393 else if (sscanf (buf, "0x%x 0x%x", &code1, &c1) == 2)
395 idx1 = idx2 = CODE_POINT_TO_INDEX (charset, code1);
402 if (idx1 >= 0 && idx2 >= 0)
405 mchartable_set (encoder, c1, (void *) code1);
406 for (idx1++, c1++; idx1 <= idx2; idx1++, c1++)
408 code1 = INDEX_TO_CODE_POINT (charset, idx1);
410 mchartable_set (encoder, c1, (void *) code1);
420 M17N_OBJECT_UNREF (encoder);
424 mplist_add (plist, Mt, decoder);
425 mplist_add (plist, Mt, encoder);
430 gen_database_name (char *buf, MSymbol *tags)
434 strcpy (buf, msymbol_name (tags[0]));
435 for (i = 1; i < 4; i++)
438 strcat (buf, msymbol_name (tags[i]));
444 find_file (MDatabaseInfo *db_info, struct stat *buf)
447 char path[PATH_MAX + 1];
449 MPLIST_DO (plist, mdatabase__dir_list)
451 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
453 if (dir_info->status != MDB_STATUS_DISABLED
454 && GEN_PATH (path, dir_info->filename, dir_info->len,
455 db_info->filename, db_info->len)
456 && stat (path, buf) == 0)
457 return strdup (path);
463 /* Return the absolute file name for DB_INFO->filename. If BUF is
464 non-NULL, store the result of `stat' call in it. It returns NULL
465 if no absolute file name was found. */
468 get_database_file (MDatabaseInfo *db_info, struct stat *buf)
470 if (db_info->status == MDB_STATUS_DISABLED)
472 if (db_info->absolute_filename)
475 stat (db_info->absolute_filename, buf);
479 struct stat stat_buf;
480 struct stat *statbuf = buf ? buf : &stat_buf;
482 db_info->absolute_filename = find_file (db_info, statbuf);
485 return db_info->absolute_filename;
489 load_database (MSymbol *tags, void *extra_info)
491 MDatabaseInfo *db_info = extra_info;
493 char *filename = get_database_file (db_info, NULL);
495 int mdebug_mask = MDEBUG_DATABASE;
498 MDEBUG_PRINT1 (" [DB] <%s>", gen_database_name (buf, tags));
499 if (! filename || ! (fp = fopen (filename, "r")))
502 MDEBUG_PRINT1 (" open fail: %s\n", filename);
504 MDEBUG_PRINT1 (" not found: %s\n", db_info->filename);
505 MERROR (MERROR_DB, NULL);
508 MDEBUG_PRINT1 (" from %s\n", filename);
510 if (tags[0] == Mchar_table)
511 value = load_chartable (fp, tags[1]);
512 else if (tags[0] == Mcharset)
513 value = load_charset (fp, tags[1]);
515 value = mplist__from_file (fp, NULL);
519 MERROR (MERROR_DB, NULL);
520 db_info->time = time (NULL);
525 /** Return a newly allocated MDatabaseInfo for DIRNAME. */
527 static MDatabaseInfo *
528 get_dir_info (char *dirname)
530 MDatabaseInfo *dir_info;
532 MSTRUCT_CALLOC (dir_info, MERROR_DB);
535 int len = strlen (dirname);
537 if (len + MDB_DIR_LEN < PATH_MAX)
539 MTABLE_MALLOC (dir_info->filename, len + 2, MERROR_DB);
540 memcpy (dir_info->filename, dirname, len + 1);
541 /* Append PATH_SEPARATOR if DIRNAME doesn't end with it. */
542 if (dir_info->filename[len - 1] != PATH_SEPARATOR)
544 dir_info->filename[len] = PATH_SEPARATOR;
545 dir_info->filename[++len] = '\0';
548 dir_info->status = MDB_STATUS_OUTDATED;
551 dir_info->status = MDB_STATUS_DISABLED;
554 dir_info->status = MDB_STATUS_DISABLED;
559 find_database (MSymbol tags[4])
564 if (! mdatabase__list)
566 for (i = 0, plist = mdatabase__list; i < 4; i++)
568 plist = mplist__assq (plist, tags[i]);
571 plist = MPLIST_PLIST (plist);
572 plist = MPLIST_NEXT (plist);
574 return MPLIST_VAL (plist);
578 free_db_info (MDatabaseInfo *db_info)
580 free (db_info->filename);
581 if (db_info->absolute_filename
582 && db_info->filename != db_info->absolute_filename)
583 free (db_info->absolute_filename);
588 check_version (MText *version)
590 char *verstr = (char *) MTEXT_DATA (version);
591 char *endp = verstr + mtext_nbytes (version);
595 ver[0] = ver[1] = ver[2] = 0;
596 for (i = 0; verstr < endp; verstr++)
605 if (! isdigit (*verstr))
607 ver[i] = ver[i] * 10 + (*verstr - '0');
609 return (ver[0] < M17NLIB_MAJOR_VERSION
610 || (ver[0] == M17NLIB_MAJOR_VERSION
611 && (ver[1] < M17NLIB_MINOR_VERSION
612 || (ver[1] == M17NLIB_MINOR_VERSION
613 && ver[2] <= M17NLIB_PATCH_LEVEL))));
617 register_database (MSymbol tags[4],
618 void *(*loader) (MSymbol *, void *),
619 void *extra_info, enum MDatabaseStatus status)
622 MDatabaseInfo *db_info;
626 if (! mdatabase__list)
627 mdatabase__list = mplist ();
629 for (i = 0, plist = mdatabase__list; i < 4; i++)
631 MPlist *pl = mplist__assq (plist, tags[i]);
634 pl = MPLIST_PLIST (pl);
638 mplist_add (pl, Msymbol, tags[i]);
639 mplist_push (plist, Mplist, pl);
640 M17N_OBJECT_UNREF (pl);
642 plist = MPLIST_NEXT (pl);
645 if (MPLIST_TAIL_P (plist))
647 MSTRUCT_MALLOC (mdb, MERROR_DB);
648 for (i = 0; i < 4; i++)
649 mdb->tag[i] = tags[i];
650 mdb->loader = loader;
651 if (loader == load_database)
653 MSTRUCT_CALLOC (db_info, MERROR_DB);
654 mdb->extra_info = db_info;
659 mdb->extra_info = extra_info;
661 mplist_push (plist, Mt, mdb);
665 mdb = MPLIST_VAL (plist);
666 if (loader == load_database)
667 db_info = mdb->extra_info;
674 db_info->status = status;
675 if (! db_info->filename
676 || strcmp (db_info->filename, (char *) extra_info) != 0)
678 if (db_info->filename)
679 free (db_info->filename);
680 if (db_info->absolute_filename
681 && db_info->filename != db_info->absolute_filename)
682 free (db_info->absolute_filename);
683 db_info->filename = strdup ((char *) extra_info);
684 db_info->len = strlen ((char *) extra_info);
687 if (db_info->filename[0] == PATH_SEPARATOR)
688 db_info->absolute_filename = db_info->filename;
690 db_info->absolute_filename = NULL;
693 if (mdb->tag[0] == Mchar_table
694 && mdb->tag[2] != Mnil
695 && (mdb->tag[1] == Mstring || mdb->tag[1] == Mtext
696 || mdb->tag[1] == Msymbol || mdb->tag[1] == Minteger
697 || mdb->tag[1] == Mplist))
698 mchar__define_prop (mdb->tag[2], mdb->tag[1], mdb);
703 register_databases_in_files (MSymbol tags[4], glob_t *globbuf, int headlen)
706 MPlist *load_key = mplist ();
710 for (i = 0; i < globbuf->gl_pathc; i++)
712 if (! (fp = fopen (globbuf->gl_pathv[i], "r")))
714 plist = mplist__from_file (fp, load_key);
718 if (MPLIST_PLIST_P (plist))
723 for (j = 0, pl = MPLIST_PLIST (plist); j < 4 && MPLIST_SYMBOL_P (pl);
724 j++, pl = MPLIST_NEXT (pl))
725 tags2[j] = MPLIST_SYMBOL (pl);
728 for (j = 0; j < 4; j++)
729 if (tags[j] == Masterisk ? tags2[j] == Mnil
730 : (tags[j] != Mnil && tags[j] != tags2[j]))
734 MText *version = NULL;
737 version = MPLIST_MTEXT_P (pl) ? MPLIST_MTEXT (pl) : NULL;
738 if (! version || check_version (version))
739 register_database (tags2, load_database,
740 globbuf->gl_pathv[i] + headlen,
744 M17N_OBJECT_UNREF (plist);
746 M17N_OBJECT_UNREF (load_key);
752 /** List of database directories. */
753 MPlist *mdatabase__dir_list;
758 MDatabaseInfo *dir_info;
761 Mchar_table = msymbol ("char-table");
762 Masterisk = msymbol ("*");
764 mdatabase__dir_list = mplist ();
765 /** The macro M17NDIR specifies a directory where the system-wide
766 MDB_DIR file exists. */
767 mplist_set (mdatabase__dir_list, Mt, get_dir_info (M17NDIR));
769 /* The variable mdatabase_dir specifies a directory where an
770 application program specific MDB_DIR file exists. */
771 if (mdatabase_dir && strlen (mdatabase_dir) > 0)
772 mplist_push (mdatabase__dir_list, Mt, get_dir_info (mdatabase_dir));
774 /* The environment variable M17NDIR specifies a directory where a
775 user specific MDB_DIR file exists. */
776 path = getenv ("M17NDIR");
777 if (path && strlen (path) > 0)
778 mplist_push (mdatabase__dir_list, Mt, get_dir_info (path));
781 /* If the env var M17NDIR is not set, check "~/.m17n.d". */
782 char *home = getenv ("HOME");
786 && (len = strlen (home))
787 && (path = alloca (len + 9)))
790 if (path[len - 1] != PATH_SEPARATOR)
791 path[len++] = PATH_SEPARATOR;
792 strcpy (path + len, ".m17n.d");
793 dir_info = get_dir_info (path);
794 mplist_push (mdatabase__dir_list, Mt, dir_info);
797 mplist_push (mdatabase__dir_list, Mt, get_dir_info (NULL));
800 mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
802 mdatabase__loader = (void *(*) (void *)) mdatabase_load;
804 mdatabase__list = mplist ();
805 mdatabase__update ();
810 mdatabase__fini (void)
812 MPlist *plist, *p0, *p1, *p2, *p3;
814 MPLIST_DO (plist, mdatabase__dir_list)
815 free_db_info (MPLIST_VAL (plist));
816 M17N_OBJECT_UNREF (mdatabase__dir_list);
818 /* MDATABASE_LIST ::= ((TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) ...) */
819 MPLIST_DO (plist, mdatabase__list)
821 p0 = MPLIST_PLIST (plist);
822 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) */
823 MPLIST_DO (p0, MPLIST_NEXT (p0))
825 p1 = MPLIST_PLIST (p0);
826 /* P1 ::= (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) */
827 MPLIST_DO (p1, MPLIST_NEXT (p1))
829 p2 = MPLIST_PLIST (p1);
830 /* P2 ::= (TAG2 (TAG3 t:MDB) ...) */
831 MPLIST_DO (p2, MPLIST_NEXT (p2))
835 p3 = MPLIST_PLIST (p2); /* P3 ::= (TAG3 t:MDB) */
836 p3 = MPLIST_NEXT (p3);
837 mdb = MPLIST_VAL (p3);
838 if (mdb->loader == load_database)
839 free_db_info (mdb->extra_info);
845 M17N_OBJECT_UNREF (mdatabase__list);
849 mdatabase__update (void)
851 MPlist *plist, *p0, *p1, *p2, *p3;
852 char path[PATH_MAX + 1];
853 MDatabaseInfo *dir_info;
857 /* Update elements of mdatabase__dir_list. */
858 MPLIST_DO (plist, mdatabase__dir_list)
860 dir_info = MPLIST_VAL (plist);
861 if (dir_info->filename)
863 if (stat (dir_info->filename, &statbuf) == 0
864 && (statbuf.st_mode & S_IFDIR))
866 if (dir_info->time < statbuf.st_mtime)
869 dir_info->time = statbuf.st_mtime;
871 if (GEN_PATH (path, dir_info->filename, dir_info->len,
872 MDB_DIR, MDB_DIR_LEN)
873 && stat (path, &statbuf) >= 0
874 && dir_info->time < statbuf.st_mtime)
877 dir_info->time = statbuf.st_mtime;
879 dir_info->status = MDB_STATUS_UPDATED;
883 if (dir_info->status != MDB_STATUS_DISABLED)
887 dir_info->status = MDB_STATUS_DISABLED;
896 /* At first, mark all databases defined automatically from mdb.dir
897 file(s) as "disabled". */
898 MPLIST_DO (plist, mdatabase__list)
900 p0 = MPLIST_PLIST (plist);
901 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
902 MPLIST_DO (p0, MPLIST_NEXT (p0))
904 p1 = MPLIST_PLIST (p0);
905 MPLIST_DO (p1, MPLIST_NEXT (p1))
907 p2 = MPLIST_PLIST (p1);
908 MPLIST_DO (p2, MPLIST_NEXT (p2))
911 MDatabaseInfo *db_info;
913 p3 = MPLIST_PLIST (p2);
914 p3 = MPLIST_NEXT (p3);
915 mdb = MPLIST_VAL (p3);
916 db_info = mdb->extra_info;
917 if (db_info->status == MDB_STATUS_AUTO)
918 db_info->status = MDB_STATUS_DISABLED;
925 MPLIST_DO (p0, mdatabase__dir_list)
926 mplist_push (plist, MPLIST_KEY (p0), MPLIST_VAL (p0));
928 while (! MPLIST_TAIL_P (plist))
930 MDatabaseInfo *dir_info = mplist_pop (plist);
935 if (dir_info->status == MDB_STATUS_DISABLED)
937 if (! GEN_PATH (path, dir_info->filename, dir_info->len,
938 MDB_DIR, MDB_DIR_LEN))
940 if (! (fp = fopen (path, "r")))
942 pl = mplist__from_file (fp, NULL);
952 int with_wildcard = 0;
954 if (! MPLIST_PLIST_P (p))
956 for (i = 0, p1 = MPLIST_PLIST (p); i < 4 && MPLIST_SYMBOL_P (p1);
957 i++, p1 = MPLIST_NEXT (p1))
958 with_wildcard |= ((tags[i] = MPLIST_SYMBOL (p1)) == Masterisk);
960 || tags[0] == Masterisk
961 || ! MPLIST_MTEXT_P (p1))
965 mt = MPLIST_MTEXT (p1);
966 nbytes = mtext_nbytes (mt);
967 if (nbytes > PATH_MAX)
969 memcpy (path, MTEXT_DATA (mt), nbytes);
976 if (tags[0] == Mchar_table || tags[0] == Mcharset)
978 if (path[0] == PATH_SEPARATOR)
980 if (glob (path, GLOB_NOSORT, NULL, &globbuf))
982 register_databases_in_files (tags, &globbuf, 0);
986 MPLIST_DO (dlist, mdatabase__dir_list)
988 MDatabaseInfo *d_info = MPLIST_VAL (dlist);
990 if (d_info->status == MDB_STATUS_DISABLED)
992 if (! GEN_PATH (path, d_info->filename, d_info->len,
993 MTEXT_DATA (mt), nbytes))
995 if (glob (path, GLOB_NOSORT, NULL, &globbuf))
997 register_databases_in_files (tags, &globbuf, d_info->len);
1003 MText *version = NULL;
1006 version = MPLIST_MTEXT_P (pl) ? MPLIST_MTEXT (pl) : NULL;
1007 if (! version || check_version (version))
1008 register_database (tags, load_database, path, MDB_STATUS_AUTO);
1011 M17N_OBJECT_UNREF (pl);
1013 M17N_OBJECT_UNREF (plist);
1017 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
1019 int mdebug_mask = MDEBUG_DATABASE;
1020 MDatabaseInfo *db_info;
1026 if (mdb->loader != load_database
1027 || mdb->tag[0] == Mchar_table
1028 || mdb->tag[0] == Mcharset)
1029 MERROR (MERROR_DB, NULL);
1030 MDEBUG_PRINT1 (" [DB] <%s>.\n",
1031 gen_database_name (name, mdb->tag));
1032 db_info = mdb->extra_info;
1033 filename = get_database_file (db_info, NULL);
1034 if (! filename || ! (fp = fopen (filename, "r")))
1035 MERROR (MERROR_DB, NULL);
1036 plist = mplist__from_file (fp, keys);
1042 /* Check if the database MDB should be reloaded or not. It returns:
1044 1: The database has not been updated since it was loaded last
1047 0: The database has never been loaded or has been updated
1048 since it was loaded last time.
1050 -1: The database is not loadable at the moment. */
1053 mdatabase__check (MDatabase *mdb)
1055 MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
1058 if (! get_database_file (db_info, &buf))
1060 if (db_info->time < buf.st_mtime)
1062 if (db_info->status == MDB_STATUS_AUTO
1063 && db_info->filename != db_info->absolute_filename)
1067 mdatabase__update ();
1068 new = find_database (mdb->tag);
1076 /* Search directories in mdatabase__dir_list for file FILENAME. If
1077 the file exist, return the absolute pathname. If FILENAME is
1078 already absolute, return a copy of it. */
1081 mdatabase__find_file (char *filename)
1084 MDatabaseInfo db_info;
1086 if (filename[0] == PATH_SEPARATOR)
1087 return (stat (filename, &buf) == 0 ? filename : NULL);
1088 db_info.filename = filename;
1089 db_info.len = strlen (filename);
1091 db_info.absolute_filename = NULL;
1092 if (! get_database_file (&db_info, &buf)
1093 || stat (db_info.absolute_filename, &buf) < 0)
1095 return db_info.absolute_filename;
1099 mdatabase__file (MDatabase *mdb)
1101 MDatabaseInfo *db_info;
1103 if (mdb->loader != load_database)
1105 db_info = mdb->extra_info;
1106 return get_database_file (db_info, NULL);
1110 mdatabase__lock (MDatabase *mdb)
1112 MDatabaseInfo *db_info;
1118 if (mdb->loader != load_database)
1120 db_info = mdb->extra_info;
1121 if (db_info->lock_file)
1123 file = get_database_file (db_info, NULL);
1126 len = strlen (file);
1127 db_info->uniq_file = malloc (len + 35);
1128 if (! db_info->uniq_file)
1130 db_info->lock_file = malloc (len + 5);
1131 if (! db_info->lock_file)
1133 free (db_info->uniq_file);
1136 sprintf (db_info->uniq_file, "%s.%X.%X", db_info->absolute_filename,
1137 (unsigned) time (NULL), (unsigned) getpid ());
1138 sprintf (db_info->lock_file, "%s.LCK", db_info->absolute_filename);
1140 fp = fopen (db_info->uniq_file, "w");
1143 char *str = strdup (db_info->uniq_file);
1144 char *dir = dirname (str);
1146 if (stat (dir, &buf) == 0
1147 || mkdir (dir, 0777) < 0
1148 || ! (fp = fopen (db_info->uniq_file, "w")))
1150 free (db_info->uniq_file);
1151 free (db_info->lock_file);
1152 db_info->lock_file = NULL;
1159 if (link (db_info->uniq_file, db_info->lock_file) < 0
1160 && (stat (db_info->uniq_file, &buf) < 0
1161 || buf.st_nlink != 2))
1163 unlink (db_info->uniq_file);
1164 unlink (db_info->lock_file);
1165 free (db_info->uniq_file);
1166 free (db_info->lock_file);
1167 db_info->lock_file = NULL;
1174 mdatabase__save (MDatabase *mdb, MPlist *data)
1176 MDatabaseInfo *db_info;
1182 if (mdb->loader != load_database)
1184 db_info = mdb->extra_info;
1185 if (! db_info->lock_file)
1187 file = get_database_file (db_info, NULL);
1191 if (mplist__serialize (mt, data, 1) < 0)
1193 M17N_OBJECT_UNREF (mt);
1196 fp = fopen (db_info->uniq_file, "w");
1199 M17N_OBJECT_UNREF (mt);
1202 mconv_encode_stream (msymbol ("utf-8"), mt, fp);
1203 M17N_OBJECT_UNREF (mt);
1205 if ((ret = rename (db_info->uniq_file, file)) < 0)
1206 unlink (db_info->uniq_file);
1207 free (db_info->uniq_file);
1208 db_info->uniq_file = NULL;
1213 mdatabase__unlock (MDatabase *mdb)
1215 MDatabaseInfo *db_info;
1217 if (mdb->loader != load_database)
1219 db_info = mdb->extra_info;
1220 if (! db_info->lock_file)
1222 unlink (db_info->lock_file);
1223 free (db_info->lock_file);
1224 db_info->lock_file = NULL;
1225 if (db_info->uniq_file)
1227 unlink (db_info->uniq_file);
1228 free (db_info->uniq_file);
1234 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1239 /*** @addtogroup m17nDatabase */
1244 @brief Directory for application specific data.
1246 If an application program wants to provide a data specific to the
1247 program or a data overriding what supplied by the m17n database,
1248 it must set this variable to a name of directory that contains the
1249 data files before it calls the macro M17N_INIT (). The directory
1250 may contain a file "mdb.dir" which contains a list of data
1251 definitions in the format described in @ref mdbDir "mdbDir(5)".
1253 The default value is NULL. */
1255 @brief ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¸ÇͤΥǡ¼¥¿Íѥǥ£¥ì¥¯¥È¥ê.
1257 ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬¡¢¤½¤Î¥×¥í¥°¥é¥à¸ÇͤΥǡ¼¥¿¤ä m17n
1258 ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¾å½ñ¤¤¹¤ë¥Ç¡¼¥¿¤òÄ󶡤¹¤ë¾ì¹ç¤Ë¤Ï¡¢¥Þ¥¯¥í M17N_INIT ()
1259 ¤ò¸Æ¤ÖÁ°¤Ë¤³¤ÎÊÑ¿ô¤ò¥Ç¡¼¥¿¥Õ¥¡¥¤¥ë¤ò´Þ¤à¥Ç¥£¥ì¥¯¥È¥ê̾¤Ë¥»¥Ã¥È¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤Ï
1260 "mdb.dir" ¥Õ¥¡¥¤¥ë¤ò¤ª¤¯¤³¤È¤¬¤Ç¤¤ë¡£¤½¤Î"mdb.dir"¥Õ¥¡¥¤¥ë¤Ë¤Ï¡¢
1261 @ref mdbDir "mdbDir(5)" ¤ÇÀâÌÀ¤µ¤ì¤Æ¤¤¤ë¥Õ¥©¡¼¥Þ¥Ã¥È¤Ç¥Ç¡¼¥¿ÄêµÁ¤Î¥ê¥¹¥È¤òµ½Ò¤¹¤ë¡£
1263 ¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¤Ï NULL ¤Ç¤¢¤ë¡£ */
1265 char *mdatabase_dir;
1269 @brief Look for a data in the database.
1271 The mdatabase_find () function searches the m17n database for a
1272 data who has tags $TAG0 through $TAG3, and returns a pointer to
1273 the data. If such a data is not found, it returns @c NULL. */
1276 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹Ãæ¤Î¥Ç¡¼¥¿¤òõ¤¹.
1278 ´Ø¿ô mdatabase_find () ¤Ï¡¢ m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ãæ¤Ç $TAG0 ¤«¤é
1279 $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤Î¤è¤¦¤Ê¥Ç¡¼¥¿¤¬¤Ê¤±¤ì¤Ð
1282 @latexonly \IPAlabel{mdatabase_find} @endlatexonly */
1285 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
1289 mdatabase__update ();
1290 tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
1291 return find_database (tags);
1296 @brief Return a data list of the m17n database.
1298 The mdatabase_list () function searches the m17n database for data
1299 who have tags $TAG0 through $TAG3, and returns their list by a
1300 plist. The value #Mnil in $TAGn means a wild card that matches
1301 any tag. Each element of the plist has key #Mt and value a
1302 pointer to type #MDatabase. */
1304 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¥ê¥¹¥È¤òÊÖ¤¹.
1306 ´Ø¿ô mdatabase_list () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é $TAG0 ¤«¤é$TAG3
1307 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤Î¥ê¥¹¥È¤òplist ¤È¤·¤ÆÊÖ¤¹¡£ $TAGn ¤¬ #Mnil
1308 ¤Ç¤¢¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥¿¥°¤Ë¥Þ¥Ã¥Á¤¹¤ë¥ï¥¤¥ë¥É¥«¡¼¥É¤È¤·¤Æ¼è¤ê°·¤ï¤ì¤ë¡£ÊÖ¤µ¤ì¤ë
1309 plist ¤Î³ÆÍ×ÁǤϥ¡¼ ¤È¤·¤Æ #Mt ¤ò¡¢ÃͤȤ·¤Æ #MDatabase ·¿¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò»ý¤Ä¡£ */
1312 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
1314 MPlist *plist = mplist (), *pl = plist;
1315 MPlist *p, *p0, *p1, *p2, *p3;
1317 mdatabase__update ();
1319 MPLIST_DO (p, mdatabase__list)
1321 p0 = MPLIST_PLIST (p);
1322 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
1323 if (tag0 != Mnil && MPLIST_SYMBOL (p0) != tag0)
1325 MPLIST_DO (p0, MPLIST_NEXT (p0))
1327 p1 = MPLIST_PLIST (p0);
1328 if (tag1 != Mnil && MPLIST_SYMBOL (p1) != tag1)
1330 MPLIST_DO (p1, MPLIST_NEXT (p1))
1332 p2 = MPLIST_PLIST (p1);
1333 if (tag2 != Mnil && MPLIST_SYMBOL (p2) != tag2)
1335 MPLIST_DO (p2, MPLIST_NEXT (p2))
1337 p3 = MPLIST_PLIST (p2);
1338 if (tag3 != Mnil && MPLIST_SYMBOL (p3) != tag3)
1340 p3 = MPLIST_NEXT (p3);
1341 pl = mplist_add (pl, Mt, MPLIST_VAL (p3));
1346 if (MPLIST_TAIL_P (plist))
1348 M17N_OBJECT_UNREF (plist);
1356 @brief Define a data of the m17n database.
1358 The mdatabase_define () function defines a data that has tags
1359 $TAG0 through $TAG3 and additional information $EXTRA_INFO.
1361 $LOADER is a pointer to a function that loads the data from the
1362 database. This function is called from the mdatabase_load ()
1363 function with the two arguments $TAGS and $EXTRA_INFO. Here,
1364 $TAGS is the array of $TAG0 through $TAG3.
1366 If $LOADER is @c NULL, the default loader of the m17n library is
1367 used. In this case, $EXTRA_INFO must be a string specifying a
1368 filename that contains the data.
1371 If the operation was successful, mdatabase_define () returns a
1372 pointer to the defined data, which can be used as an argument to
1373 mdatabase_load (). Otherwise, it returns @c NULL. */
1376 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë.
1378 ´Ø¿ô mdatabase_define () ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ª¤è¤ÓÉղþðÊó
1379 $EXTRA_INFO ¤ò»ý¤Ä¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë¡£
1381 $LOADER ¤Ï¤½¤Î¥Ç¡¼¥¿¤Î¥í¡¼¥É¤ËÍѤ¤¤é¤ì¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï
1382 mdatabase_load () ¤«¤é $TAGS ¤È $EXTRA_INFO ¤È¤¤¤¦Æó¤Ä¤Î°ú¿ôÉÕ¤¤Ç¸Æ¤Ó½Ð¤µ¤ì¤ë¡£¤³¤³¤Ç
1383 $TAGS ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1385 ¤â¤· $LOADER ¤¬ @c NULL ¤Ê¤é¡¢m17n ¥é¥¤¥Ö¥é¥êɸ½à¤Î¥í¡¼¥À¤¬»È¤ï¤ì¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï
1386 $EXTRA_INFO ¤Ï¥Ç¡¼¥¿¤ò´Þ¤à¥Õ¥¡¥¤¥ë̾¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1389 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mdatabase_define ()
1390 ¤ÏÄêµÁ¤µ¤ì¤¿¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¥Ý¥¤¥ó¥¿¤Ï´Ø¿ô mdatabase_load ()
1391 ¤Î°ú¿ô¤È¤·¤ÆÍѤ¤¤ë¤³¤È¤¬¤Ç¤¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1393 @latexonly \IPAlabel{mdatabase_define} @endlatexonly */
1397 mdatabase_load (), mdatabase_define () */
1400 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
1401 void *(*loader) (MSymbol *, void *),
1407 tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
1409 loader = load_database;
1410 mdb = register_database (tags, loader, extra_info, MDB_STATUS_EXPLICIT);
1416 @brief Load a data from the database.
1418 The mdatabase_load () function loads a data specified in $MDB and
1419 returns the contents. The type of contents depends on the type of
1422 If the data is of the @e plist @e type, this function returns a
1423 pointer to @e plist.
1425 If the database is of the @e chartable @e type, it returns a
1426 chartable. The default value of the chartable is set according to
1427 the second tag of the data as below:
1429 @li If the tag is #Msymbol, the default value is #Mnil.
1430 @li If the tag is #Minteger, the default value is -1.
1431 @li Otherwise, the default value is @c NULL.
1433 If the data is of the @e charset @e type, it returns a plist of length 2
1434 (keys are both #Mt). The value of the first element is an array
1435 of integers that maps code points to the corresponding character
1436 codes. The value of the second element is a chartable of integers
1437 that does the reverse mapping. The charset must be defined in
1442 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿¤ò¥í¡¼¥É¤¹¤ë.
1444 ´Ø¿ô mdatabase_load () ¤Ï $MDB
1445 ¤¬»Ø¤¹¥Ç¡¼¥¿¤ò¥í¡¼¥É¤·¡¢¤½¤ÎÃæ¿È¤òÊÖ¤¹¡£ÊÖ¤µ¤ì¤ë¤â¤Î¤Ï¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ°Û¤Ê¤ë¡£
1447 ¥Ç¡¼¥¿¤¬ @e plist¥¿¥¤¥× ¤Ê¤é¤Ð¡¢ @e plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1449 ¥Ç¡¼¥¿¤¬ @e chartable¥¿¥¤¥× ¤Ê¤é¤Ðʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£
1450 ʸ»ú¥Æ¡¼¥Ö¥ë¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤϡ¢¥Ç¡¼¥¿¤ÎÂè2¥¿¥°¤Ë¤è¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Ë·è¤Þ¤ë¡£
1452 @li ¥¿¥°¤¬ #Msymbol ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï #Mnil
1453 @li ¥¿¥°¤¬ #Minteger ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï -1
1454 @li ¤½¤ì°Ê³°¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï @c NULL
1456 ¥Ç¡¼¥¿¤¬ @e charset¥¿¥¤¥× ¤Ê¤é¤ÐŤµ 2 ¤Î plist ¤òÊÖ¤¹¡Ê¥¡¼¤Ï¶¦¤Ë#Mt ¡Ë¡£
1457 ºÇ½é¤ÎÍ×ÁǤÎÃͤϥ³¡¼¥É¥Ý¥¤¥ó¥È¤òÂбþ¤¹¤ëʸ»ú¥³¡¼¥É¤Ë¥Þ¥Ã¥×¤¹¤ëÀ°¿ô¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1458 £²ÈÖÌܤÎÍ×ÁǤÎÃͤϵդΥޥåפò¤¹¤ëʸ»ú¥Æ¡¼¥Ö¥ë¤Ç¤¢¤ë¡£
1459 ¤³¤Îʸ»ú¥»¥Ã¥È¤Ïͽ¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
1461 @latexonly \IPAlabel{mdatabase_load} @endlatexonly
1466 mdatabase_load (), mdatabase_define () */
1469 mdatabase_load (MDatabase *mdb)
1471 return (*mdb->loader) (mdb->tag, mdb->extra_info);
1476 @brief Get tags of a data.
1478 The mdatabase_tag () function returns an array of tags (symbols)
1479 that identify the data in $MDB. The length of the array is
1483 @brief ¥Ç¡¼¥¿¤Î¥¿¥°¤òÆÀ¤ë.
1485 ´Ø¿ô mdatabase_tag () ¤Ï¡¢¥Ç¡¼¥¿ $MDB ¤Î¥¿¥°¡Ê¥·¥ó¥Ü¥ë¡Ë¤ÎÇÛÎó¤òÊÖ¤¹¡£ÇÛÎó¤ÎŤµ¤Ï
1488 @latexonly \IPAlabel{mdatabase_tag} @endlatexonly */
1491 mdatabase_tag (MDatabase *mdb)