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>
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);
496 if (! filename || ! (fp = fopen (filename, "r")))
497 MERROR (MERROR_DB, NULL);
499 if (tags[0] == Mchar_table)
500 value = load_chartable (fp, tags[1]);
501 else if (tags[0] == Mcharset)
502 value = load_charset (fp, tags[1]);
504 value = mplist__from_file (fp, NULL);
508 MERROR (MERROR_DB, NULL);
509 db_info->time = time (NULL);
514 /** Return a newly allocated MDatabaseInfo for DIRNAME. */
516 static MDatabaseInfo *
517 get_dir_info (char *dirname)
519 MDatabaseInfo *dir_info;
521 MSTRUCT_CALLOC (dir_info, MERROR_DB);
524 int len = strlen (dirname);
526 if (len + MDB_DIR_LEN < PATH_MAX)
528 MTABLE_MALLOC (dir_info->filename, len + 2, MERROR_DB);
529 memcpy (dir_info->filename, dirname, len + 1);
530 /* Append PATH_SEPARATOR if DIRNAME doesn't end with it. */
531 if (dir_info->filename[len - 1] != PATH_SEPARATOR)
533 dir_info->filename[len] = PATH_SEPARATOR;
534 dir_info->filename[++len] = '\0';
537 dir_info->status = MDB_STATUS_AUTO;
540 dir_info->status = MDB_STATUS_DISABLED;
543 dir_info->status = MDB_STATUS_DISABLED;
548 find_database (MSymbol tags[4])
553 if (! mdatabase__list)
555 for (i = 0, plist = mdatabase__list; i < 4; i++)
557 plist = mplist__assq (plist, tags[i]);
560 plist = MPLIST_PLIST (plist);
561 plist = MPLIST_NEXT (plist);
563 return MPLIST_VAL (plist);
567 free_db_info (MDatabaseInfo *db_info)
569 free (db_info->filename);
570 if (db_info->absolute_filename
571 && db_info->filename != db_info->absolute_filename)
572 free (db_info->absolute_filename);
577 register_database (MSymbol tags[4], void *(*loader) (MSymbol *, void *),
578 void *extra_info, enum MDatabaseStatus status)
580 MDatabase *mdb = find_database (tags);
581 MDatabaseInfo *db_info = NULL;
585 if (loader == load_database)
586 db_info = mdb->extra_info;
593 MSTRUCT_MALLOC (mdb, MERROR_DB);
594 for (i = 0; i < 4; i++)
595 mdb->tag[i] = tags[i];
596 mdb->loader = loader;
597 if (loader == load_database)
599 MSTRUCT_CALLOC (db_info, MERROR_DB);
600 mdb->extra_info = db_info;
603 mdb->extra_info = extra_info;
604 if (! mdatabase__list)
605 mdatabase__list = mplist ();
606 for (i = 0, plist = mdatabase__list; i < 4; i++)
608 MPlist *pl = mplist__assq (plist, tags[i]);
611 pl = MPLIST_PLIST (pl);
615 mplist_add (pl, Msymbol, tags[i]);
616 mplist_push (plist, Mplist, pl);
617 M17N_OBJECT_UNREF (pl);
619 plist = MPLIST_NEXT (pl);
621 mplist_push (plist, Mt, mdb);
626 db_info->status = status;
627 if (! db_info->filename
628 || strcmp (db_info->filename, (char *) extra_info) != 0)
630 if (db_info->filename)
631 free (db_info->filename);
632 if (db_info->absolute_filename
633 && db_info->filename != db_info->absolute_filename)
634 free (db_info->absolute_filename);
635 db_info->filename = strdup ((char *) extra_info);
636 db_info->len = strlen ((char *) extra_info);
639 if (db_info->filename[0] == PATH_SEPARATOR)
640 db_info->absolute_filename = db_info->filename;
642 db_info->absolute_filename = NULL;
645 if (mdb->tag[0] == Mchar_table
646 && mdb->tag[2] != Mnil
647 && (mdb->tag[1] == Mstring || mdb->tag[1] == Mtext
648 || mdb->tag[1] == Msymbol || mdb->tag[1] == Minteger
649 || mdb->tag[1] == Mplist))
650 mchar__define_prop (mdb->tag[2], mdb->tag[1], mdb);
655 register_databases_in_files (MSymbol tags[4], glob_t *globbuf)
658 MPlist *load_key = mplist ();
662 for (i = 0; i < globbuf->gl_pathc; i++)
664 if (! (fp = fopen (globbuf->gl_pathv[i], "r")))
666 plist = mplist__from_file (fp, load_key);
670 if (MPLIST_PLIST_P (plist))
675 for (j = 0, pl = MPLIST_PLIST (plist); j < 4 && MPLIST_SYMBOL_P (pl);
676 j++, pl = MPLIST_NEXT (pl))
677 tags2[j] = MPLIST_SYMBOL (pl);
680 for (j = 0; j < 4; j++)
681 if (tags[j] == Masterisk ? tags2[j] == Mnil
682 : (tags[j] != Mnil && tags[j] != tags2[j]))
685 register_database (tags2, load_database, globbuf->gl_pathv[i],
688 M17N_OBJECT_UNREF (plist);
690 M17N_OBJECT_UNREF (load_key);
696 /** List of database directories. */
697 MPlist *mdatabase__dir_list;
702 MDatabaseInfo *dir_info;
705 Mchar_table = msymbol ("char-table");
706 Masterisk = msymbol ("*");
708 mdatabase__dir_list = mplist ();
709 /** The macro M17NDIR specifies a directory where the system-wide
710 MDB_DIR file exists. */
711 mplist_set (mdatabase__dir_list, Mt, get_dir_info (M17NDIR));
713 /* The variable mdatabase_dir specifies a directory where an
714 application program specific MDB_DIR file exists. */
715 if (mdatabase_dir && strlen (mdatabase_dir) > 0)
716 mplist_push (mdatabase__dir_list, Mt, get_dir_info (mdatabase_dir));
718 /* The environment variable M17NDIR specifies a directory where a
719 user specific MDB_DIR file exists. */
720 path = getenv ("M17NDIR");
721 if (path && strlen (path) > 0)
722 mplist_push (mdatabase__dir_list, Mt, get_dir_info (path));
725 /* If the env var M17NDIR is not set, check "~/.m17n.d". */
726 char *home = getenv ("HOME");
730 && (len = strlen (home))
731 && (path = alloca (len + 9)))
734 if (path[len - 1] != PATH_SEPARATOR)
735 path[len++] = PATH_SEPARATOR;
736 strcpy (path + len, ".m17n.d");
737 dir_info = get_dir_info (path);
738 mplist_push (mdatabase__dir_list, Mt, dir_info);
741 mplist_push (mdatabase__dir_list, Mt, get_dir_info (NULL));
744 mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol))
746 mdatabase__loader = (void *(*) (void *)) mdatabase_load;
748 mdatabase__list = mplist ();
749 mdatabase__update ();
754 mdatabase__fini (void)
756 MPlist *plist, *p0, *p1, *p2, *p3;
758 MPLIST_DO (plist, mdatabase__dir_list)
759 free_db_info (MPLIST_VAL (plist));
760 M17N_OBJECT_UNREF (mdatabase__dir_list);
762 /* MDATABASE_LIST ::= ((TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) ...) */
763 MPLIST_DO (plist, mdatabase__list)
765 p0 = MPLIST_PLIST (plist);
766 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) */
767 MPLIST_DO (p0, MPLIST_NEXT (p0))
769 p1 = MPLIST_PLIST (p0);
770 /* P1 ::= (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) */
771 MPLIST_DO (p1, MPLIST_NEXT (p1))
773 p2 = MPLIST_PLIST (p1);
774 /* P2 ::= (TAG2 (TAG3 t:MDB) ...) */
775 MPLIST_DO (p2, MPLIST_NEXT (p2))
779 p3 = MPLIST_PLIST (p2); /* P3 ::= (TAG3 t:MDB) */
780 p3 = MPLIST_NEXT (p3);
781 mdb = MPLIST_VAL (p3);
782 if (mdb->loader == load_database)
783 free_db_info (mdb->extra_info);
789 M17N_OBJECT_UNREF (mdatabase__list);
793 mdatabase__update (void)
795 MPlist *plist, *p0, *p1, *p2, *p3;
796 char path[PATH_MAX + 1];
797 MDatabaseInfo *dir_info;
801 /* Update elements of mdatabase__dir_list. */
802 MPLIST_DO (plist, mdatabase__dir_list)
804 dir_info = MPLIST_VAL (plist);
805 if (dir_info->filename)
807 enum MDatabaseStatus status;
809 if (stat (dir_info->filename, &statbuf) == 0
810 && (statbuf.st_mode & S_IFDIR))
811 status = ((dir_info->time >= statbuf.st_mtime)
812 ? MDB_STATUS_EXPLICIT : MDB_STATUS_AUTO);
814 status = MDB_STATUS_DISABLED;
816 if (dir_info->status != status)
818 dir_info->status = status;
821 else if (dir_info->status == MDB_STATUS_AUTO)
829 /* At first, mark all databases defined automatically from mdb.dir
830 file(s) as "disabled". */
831 MPLIST_DO (plist, mdatabase__list)
833 p0 = MPLIST_PLIST (plist);
834 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
835 MPLIST_DO (p0, MPLIST_NEXT (p0))
837 p1 = MPLIST_PLIST (p0);
838 MPLIST_DO (p1, MPLIST_NEXT (p1))
840 p2 = MPLIST_PLIST (p1);
841 MPLIST_DO (p2, MPLIST_NEXT (p2))
844 MDatabaseInfo *db_info;
846 p3 = MPLIST_PLIST (p2);
847 p3 = MPLIST_NEXT (p3);
848 mdb = MPLIST_VAL (p3);
849 db_info = mdb->extra_info;
850 if (db_info->status == MDB_STATUS_AUTO)
851 db_info->status = MDB_STATUS_DISABLED;
857 MPLIST_DO (plist, mdatabase__dir_list)
859 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
864 if (dir_info->status == MDB_STATUS_DISABLED)
866 if (! GEN_PATH (path, dir_info->filename, dir_info->len,
867 MDB_DIR, MDB_DIR_LEN))
869 if (stat (path, &statbuf) < 0)
871 dir_info->time = statbuf.st_mtime;
872 if (! (fp = fopen (path, "r")))
874 pl = mplist__from_file (fp, NULL);
884 int with_wildcard = 0;
886 if (! MPLIST_PLIST_P (p))
888 for (i = 0, p1 = MPLIST_PLIST (p); i < 4 && MPLIST_SYMBOL_P (p1);
889 i++, p1 = MPLIST_NEXT (p1))
890 with_wildcard |= ((tags[i] = MPLIST_SYMBOL (p1)) == Masterisk);
892 || tags[0] == Masterisk
893 || ! MPLIST_MTEXT_P (p1))
897 mt = MPLIST_MTEXT (p1);
898 if (mt->format >= MTEXT_FORMAT_UTF_16LE)
899 mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
900 nbytes = mtext_nbytes (mt);
901 if (nbytes > PATH_MAX)
903 memcpy (path, MTEXT_DATA (mt), nbytes);
910 if (tags[0] == Mchar_table || tags[0] == Mcharset)
912 if (path[0] == PATH_SEPARATOR)
914 if (glob (path, GLOB_NOSORT, NULL, &globbuf))
916 register_databases_in_files (tags, &globbuf);
920 MPLIST_DO (dlist, mdatabase__dir_list)
922 MDatabaseInfo *d_info = MPLIST_VAL (dlist);
924 if (d_info->status == MDB_STATUS_DISABLED)
926 if (! GEN_PATH (path, d_info->filename, d_info->len,
927 MTEXT_DATA (mt), nbytes))
929 if (glob (path, GLOB_NOSORT, NULL, &globbuf))
931 register_databases_in_files (tags, &globbuf);
937 register_database (tags, load_database, path, MDB_STATUS_AUTO);
940 M17N_OBJECT_UNREF (pl);
945 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
947 int mdebug_mask = MDEBUG_DATABASE;
948 MDatabaseInfo *db_info;
954 if (mdb->loader != load_database
955 || mdb->tag[0] == Mchar_table
956 || mdb->tag[0] == Mcharset)
957 MERROR (MERROR_DB, NULL);
958 MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
959 gen_database_name (name, mdb->tag));
960 db_info = mdb->extra_info;
961 filename = get_database_file (db_info, NULL);
962 if (! filename || ! (fp = fopen (filename, "r")))
963 MERROR (MERROR_DB, NULL);
964 plist = mplist__from_file (fp, keys);
970 /* Check if the database MDB should be reloaded or not. It returns:
972 1: The database has not been updated since it was loaded last
975 0: The database has never been loaded or has been updated
976 since it was loaded last time.
978 -1: The database is not loadable at the moment. */
981 mdatabase__check (MDatabase *mdb)
983 MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
986 if (! get_database_file (db_info, &buf))
988 if (db_info->time < buf.st_mtime)
993 /* Search directories in mdatabase__dir_list for file FILENAME. If
994 the file exist, return the absolute pathname. If FILENAME is
995 already absolute, return a copy of it. */
998 mdatabase__find_file (char *filename)
1001 MDatabaseInfo db_info;
1003 if (filename[0] == PATH_SEPARATOR)
1004 return (stat (filename, &buf) == 0 ? filename : NULL);
1005 db_info.filename = filename;
1006 db_info.len = strlen (filename);
1008 db_info.absolute_filename = NULL;
1009 if (! get_database_file (&db_info, &buf)
1010 || stat (db_info.absolute_filename, &buf) < 0)
1012 return db_info.absolute_filename;
1016 mdatabase__file (MDatabase *mdb)
1018 MDatabaseInfo *db_info;
1020 if (mdb->loader != load_database)
1022 db_info = mdb->extra_info;
1023 return get_database_file (db_info, NULL);
1027 mdatabase__lock (MDatabase *mdb)
1029 MDatabaseInfo *db_info;
1035 if (mdb->loader != load_database)
1037 db_info = mdb->extra_info;
1038 if (db_info->lock_file)
1040 file = get_database_file (db_info, NULL);
1043 len = strlen (file);
1044 db_info->uniq_file = malloc (len + 35);
1045 if (! db_info->uniq_file)
1047 db_info->lock_file = malloc (len + 5);
1048 if (! db_info->lock_file)
1050 free (db_info->uniq_file);
1053 sprintf (db_info->uniq_file, "%s.%X.%X", db_info->absolute_filename,
1054 (unsigned) time (NULL), (unsigned) getpid ());
1055 sprintf (db_info->lock_file, "%s.LCK", db_info->absolute_filename);
1057 fp = fopen (db_info->uniq_file, "w");
1060 char *str = strdup (db_info->uniq_file);
1061 char *dir = dirname (str);
1063 if (stat (dir, &buf) == 0
1064 || mkdir (dir, 0777) < 0
1065 || ! (fp = fopen (db_info->uniq_file, "w")))
1067 free (db_info->uniq_file);
1068 free (db_info->lock_file);
1069 db_info->lock_file = NULL;
1076 if (link (db_info->uniq_file, db_info->lock_file) < 0
1077 && (stat (db_info->uniq_file, &buf) < 0
1078 || buf.st_nlink != 2))
1080 unlink (db_info->uniq_file);
1081 unlink (db_info->lock_file);
1082 free (db_info->uniq_file);
1083 free (db_info->lock_file);
1084 db_info->lock_file = NULL;
1091 mdatabase__save (MDatabase *mdb, MPlist *data)
1093 MDatabaseInfo *db_info;
1099 if (mdb->loader != load_database)
1101 db_info = mdb->extra_info;
1102 if (! db_info->lock_file)
1104 file = get_database_file (db_info, NULL);
1108 if (mplist__serialize (mt, data, 1) < 0)
1110 M17N_OBJECT_UNREF (mt);
1113 fp = fopen (db_info->uniq_file, "w");
1116 M17N_OBJECT_UNREF (mt);
1119 mconv_encode_stream (msymbol ("utf-8"), mt, fp);
1120 M17N_OBJECT_UNREF (mt);
1122 if ((ret = rename (db_info->uniq_file, file)) < 0)
1123 unlink (db_info->uniq_file);
1124 free (db_info->uniq_file);
1125 db_info->uniq_file = NULL;
1130 mdatabase__unlock (MDatabase *mdb)
1132 MDatabaseInfo *db_info;
1134 if (mdb->loader != load_database)
1136 db_info = mdb->extra_info;
1137 if (! db_info->lock_file)
1139 unlink (db_info->lock_file);
1140 free (db_info->lock_file);
1141 db_info->lock_file = NULL;
1142 if (db_info->uniq_file)
1144 unlink (db_info->uniq_file);
1145 free (db_info->uniq_file);
1151 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1156 /*** @addtogroup m17nDatabase */
1161 @brief Directory for application specific data.
1163 If an application program wants to provide a data specific to the
1164 program or a data overriding what supplied by the m17n database,
1165 it must set this variable to a name of directory that contains the
1166 data files before it calls the macro M17N_INIT (). The directory
1167 may contain a file "mdb.dir" which contains a list of data
1168 definitions in the format described in @ref mdbDir "mdbDir(5)".
1170 The default value is NULL. */
1172 @brief ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¸ÇͤΥǡ¼¥¿Íѥǥ£¥ì¥¯¥È¥ê.
1174 ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬¡¢¤½¤Î¥×¥í¥°¥é¥à¸ÇͤΥǡ¼¥¿¤ä m17n
1175 ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¾å½ñ¤¤¹¤ë¥Ç¡¼¥¿¤òÄ󶡤¹¤ë¾ì¹ç¤Ë¤Ï¡¢¥Þ¥¯¥í M17N_INIT ()
1176 ¤ò¸Æ¤ÖÁ°¤Ë¤³¤ÎÊÑ¿ô¤ò¥Ç¡¼¥¿¥Õ¥¡¥¤¥ë¤ò´Þ¤à¥Ç¥£¥ì¥¯¥È¥ê̾¤Ë¥»¥Ã¥È¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤Ï
1177 "mdb.dir" ¥Õ¥¡¥¤¥ë¤ò¤ª¤¯¤³¤È¤¬¤Ç¤¤ë¡£¤½¤Î"mdb.dir"¥Õ¥¡¥¤¥ë¤Ë¤Ï¡¢
1178 @ref mdbDir "mdbDir(5)" ¤ÇÀâÌÀ¤µ¤ì¤Æ¤¤¤ë¥Õ¥©¡¼¥Þ¥Ã¥È¤Ç¥Ç¡¼¥¿ÄêµÁ¤Î¥ê¥¹¥È¤òµ½Ò¤¹¤ë¡£
1180 ¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¤Ï NULL ¤Ç¤¢¤ë¡£ */
1182 char *mdatabase_dir;
1186 @brief Look for a data in the database.
1188 The mdatabase_find () function searches the m17n database for a
1189 data who has tags $TAG0 through $TAG3, and returns a pointer to
1190 the data. If such a data is not found, it returns @c NULL. */
1193 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹Ãæ¤Î¥Ç¡¼¥¿¤òõ¤¹.
1195 ´Ø¿ô mdatabase_find () ¤Ï¡¢ m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ãæ¤Ç $TAG0 ¤«¤é
1196 $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤ì¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤½¤Î¤è¤¦¤Ê¥Ç¡¼¥¿¤¬¤Ê¤±¤ì¤Ð
1199 @latexonly \IPAlabel{mdatabase_find} @endlatexonly */
1202 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
1206 mdatabase__update ();
1207 tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
1208 return find_database (tags);
1213 @brief Return a data list of the m17n database.
1215 The mdatabase_list () function searches the m17n database for data
1216 who have tags $TAG0 through $TAG3, and returns their list by a
1217 plist. The value #Mnil in $TAGn means a wild card that matches
1218 any tag. Each element of the plist has key #Mt and value a
1219 pointer to type #MDatabase. */
1221 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¥ê¥¹¥È¤òÊÖ¤¹.
1223 ´Ø¿ô mdatabase_list () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é $TAG0 ¤«¤é$TAG3
1224 ¤Þ¤Ç¤Î¥¿¥°¤ò»ý¤Ä¥Ç¡¼¥¿¤òõ¤·¡¢¤½¤Î¥ê¥¹¥È¤òplist ¤È¤·¤ÆÊÖ¤¹¡£ $TAGn ¤¬ #Mnil
1225 ¤Ç¤¢¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥¿¥°¤Ë¥Þ¥Ã¥Á¤¹¤ë¥ï¥¤¥ë¥É¥«¡¼¥É¤È¤·¤Æ¼è¤ê°·¤ï¤ì¤ë¡£ÊÖ¤µ¤ì¤ë
1226 plist ¤Î³ÆÍ×ÁǤϥ¡¼ ¤È¤·¤Æ #Mt ¤ò¡¢ÃͤȤ·¤Æ #MDatabase ·¿¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò»ý¤Ä¡£ */
1229 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
1231 MPlist *plist = mplist (), *pl = plist;
1232 MPlist *p, *p0, *p1, *p2, *p3;
1234 mdatabase__update ();
1236 MPLIST_DO (p, mdatabase__list)
1238 p0 = MPLIST_PLIST (p);
1239 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
1240 if (tag0 != Mnil && MPLIST_SYMBOL (p0) != tag0)
1242 MPLIST_DO (p0, MPLIST_NEXT (p0))
1244 p1 = MPLIST_PLIST (p0);
1245 if (tag1 != Mnil && MPLIST_SYMBOL (p1) != tag1)
1247 MPLIST_DO (p1, MPLIST_NEXT (p1))
1249 p2 = MPLIST_PLIST (p1);
1250 if (tag2 != Mnil && MPLIST_SYMBOL (p2) != tag2)
1252 MPLIST_DO (p2, MPLIST_NEXT (p2))
1254 p3 = MPLIST_PLIST (p2);
1255 if (tag3 != Mnil && MPLIST_SYMBOL (p3) != tag3)
1257 p3 = MPLIST_NEXT (p3);
1258 pl = mplist_add (pl, Mt, MPLIST_VAL (p3));
1263 if (MPLIST_TAIL_P (plist))
1265 M17N_OBJECT_UNREF (plist);
1273 @brief Define a data of the m17n database.
1275 The mdatabase_define () function defines a data that has tags
1276 $TAG0 through $TAG3 and additional information $EXTRA_INFO.
1278 $LOADER is a pointer to a function that loads the data from the
1279 database. This function is called from the mdatabase_load ()
1280 function with the two arguments $TAGS and $EXTRA_INFO. Here,
1281 $TAGS is the array of $TAG0 through $TAG3.
1283 If $LOADER is @c NULL, the default loader of the m17n library is
1284 used. In this case, $EXTRA_INFO must be a string specifying a
1285 filename that contains the data.
1288 If the operation was successful, mdatabase_define () returns a
1289 pointer to the defined data, which can be used as an argument to
1290 mdatabase_load (). Otherwise, it returns @c NULL. */
1293 @brief m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë.
1295 ´Ø¿ô mdatabase_define () ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤Î¥¿¥°¤ª¤è¤ÓÉղþðÊó
1296 $EXTRA_INFO ¤ò»ý¤Ä¥Ç¡¼¥¿¤òÄêµÁ¤¹¤ë¡£
1298 $LOADER ¤Ï¤½¤Î¥Ç¡¼¥¿¤Î¥í¡¼¥É¤ËÍѤ¤¤é¤ì¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï
1299 mdatabase_load () ¤«¤é $TAGS ¤È $EXTRA_INFO ¤È¤¤¤¦Æó¤Ä¤Î°ú¿ôÉÕ¤¤Ç¸Æ¤Ó½Ð¤µ¤ì¤ë¡£¤³¤³¤Ç
1300 $TAGS ¤Ï $TAG0 ¤«¤é $TAG3 ¤Þ¤Ç¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1302 ¤â¤· $LOADER ¤¬ @c NULL ¤Ê¤é¡¢m17n ¥é¥¤¥Ö¥é¥êɸ½à¤Î¥í¡¼¥À¤¬»È¤ï¤ì¤ë¡£¤³¤Î¾ì¹ç¤Ë¤Ï
1303 $EXTRA_INFO ¤Ï¥Ç¡¼¥¿¤ò´Þ¤à¥Õ¥¡¥¤¥ë̾¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1306 ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mdatabase_define ()
1307 ¤ÏÄêµÁ¤µ¤ì¤¿¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¤³¤Î¥Ý¥¤¥ó¥¿¤Ï´Ø¿ô mdatabase_load ()
1308 ¤Î°ú¿ô¤È¤·¤ÆÍѤ¤¤ë¤³¤È¤¬¤Ç¤¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1310 @latexonly \IPAlabel{mdatabase_define} @endlatexonly */
1314 mdatabase_load (), mdatabase_define () */
1317 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
1318 void *(*loader) (MSymbol *, void *),
1324 tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
1326 loader = load_database;
1327 mdb = register_database (tags, loader, extra_info, MDB_STATUS_EXPLICIT);
1333 @brief Load a data from the database.
1335 The mdatabase_load () function loads a data specified in $MDB and
1336 returns the contents. The type of contents depends on the type of
1339 If the data is of the @e plist @e type, this function returns a
1340 pointer to @e plist.
1342 If the database is of the @e chartable @e type, it returns a
1343 chartable. The default value of the chartable is set according to
1344 the second tag of the data as below:
1346 @li If the tag is #Msymbol, the default value is #Mnil.
1347 @li If the tag is #Minteger, the default value is -1.
1348 @li Otherwise, the default value is @c NULL.
1350 If the data is of the @e charset @e type, it returns a plist of length 2
1351 (keys are both #Mt). The value of the first element is an array
1352 of integers that maps code points to the corresponding character
1353 codes. The value of the second element is a chartable of integers
1354 that does the reverse mapping. The charset must be defined in
1359 @brief ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿¤ò¥í¡¼¥É¤¹¤ë.
1361 ´Ø¿ô mdatabase_load () ¤Ï $MDB
1362 ¤¬»Ø¤¹¥Ç¡¼¥¿¤ò¥í¡¼¥É¤·¡¢¤½¤ÎÃæ¿È¤òÊÖ¤¹¡£ÊÖ¤µ¤ì¤ë¤â¤Î¤Ï¥Ç¡¼¥¿¤Î¥¿¥¤¥×¤Ë¤è¤Ã¤Æ°Û¤Ê¤ë¡£
1364 ¥Ç¡¼¥¿¤¬ @e plist¥¿¥¤¥× ¤Ê¤é¤Ð¡¢ @e plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1366 ¥Ç¡¼¥¿¤¬ @e chartable¥¿¥¤¥× ¤Ê¤é¤Ðʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£
1367 ʸ»ú¥Æ¡¼¥Ö¥ë¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤϡ¢¥Ç¡¼¥¿¤ÎÂè2¥¿¥°¤Ë¤è¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Ë·è¤Þ¤ë¡£
1369 @li ¥¿¥°¤¬ #Msymbol ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï #Mnil
1370 @li ¥¿¥°¤¬ #Minteger ¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï -1
1371 @li ¤½¤ì°Ê³°¤Ê¤é¡¢¥Ç¥Õ¥©¥ë¥ÈÃÍ¤Ï @c NULL
1373 ¥Ç¡¼¥¿¤¬ @e charset¥¿¥¤¥× ¤Ê¤é¤ÐŤµ 2 ¤Î plist ¤òÊÖ¤¹¡Ê¥¡¼¤Ï¶¦¤Ë#Mt ¡Ë¡£
1374 ºÇ½é¤ÎÍ×ÁǤÎÃͤϥ³¡¼¥É¥Ý¥¤¥ó¥È¤òÂбþ¤¹¤ëʸ»ú¥³¡¼¥É¤Ë¥Þ¥Ã¥×¤¹¤ëÀ°¿ô¤ÎÇÛÎó¤Ç¤¢¤ë¡£
1375 £²ÈÖÌܤÎÍ×ÁǤÎÃͤϵդΥޥåפò¤¹¤ëʸ»ú¥Æ¡¼¥Ö¥ë¤Ç¤¢¤ë¡£
1376 ¤³¤Îʸ»ú¥»¥Ã¥È¤Ïͽ¤áÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
1378 @latexonly \IPAlabel{mdatabase_load} @endlatexonly
1383 mdatabase_load (), mdatabase_define () */
1386 mdatabase_load (MDatabase *mdb)
1388 int mdebug_mask = MDEBUG_DATABASE;
1391 MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n",
1392 gen_database_name (buf, mdb->tag));
1393 return (*mdb->loader) (mdb->tag, mdb->extra_info);
1398 @brief Get tags of a data.
1400 The mdatabase_tag () function returns an array of tags (symbols)
1401 that identify the data in $MDB. The length of the array is
1405 @brief ¥Ç¡¼¥¿¤Î¥¿¥°¤òÆÀ¤ë.
1407 ´Ø¿ô mdatabase_tag () ¤Ï¡¢¥Ç¡¼¥¿ $MDB ¤Î¥¿¥°¡Ê¥·¥ó¥Ü¥ë¡Ë¤ÎÇÛÎó¤òÊÖ¤¹¡£ÇÛÎó¤ÎŤµ¤Ï
1410 @latexonly \IPAlabel{mdatabase_tag} @endlatexonly */
1413 mdatabase_tag (MDatabase *mdb)