1 /* database.c -- database module.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
5
6 This file is part of the m17n library.
7
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.
12
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.
17
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,
21 Boston, MA 02110-1301 USA. */
22
23 /***en
24 @addtogroup m17nDatabase
25 @brief The m17n database and API for it.
26
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".
35
36 The m17n database contains multiple heterogeneous data, and each
37 data is identified by four tags; TAG0, TAG1, TAG2, TAG3. Each tag
38 must be a symbol.
39
40 TAG0 specifies the type of data stored in the database as below.
41
42 @li
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
47 symbols.
48
49 @li
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
53 can be any symbols.
54
55 @li
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.
60
61 The notation \<TAG0, TAG1, TAG2, TAG3\> means a data with those
62 tags.
63
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.
70 */
71
72 /***ja
73 @addtogroup m17nDatabase
74 @brief m17n �ǡ����١����ˤȤ���˴ؤ��� API.
75
76 m17n �饤�֥���ɬ�פ˱�����ưŪ�� @e m17n @e �ǡ����١���
77 ��������������롣�ޤ����ץꥱ�������ץ����⡢�ȼ��Υǡ�����
78 m17n �ǡ����١������ɲä��������ưŪ�˼������뤳�Ȥ��Ǥ��롣
79 ���ץꥱ�������ץ���ब�ȼ��Υǡ������ɲá���������ˤϡ��ѿ�
80 #mdatabase_dir �ˤ��Υ��ץꥱ��������ͭ�Υǥ��쥯�ȥ�åȤ���
81 ������˥ǡ������Ǽ���롣�桼�������Υǡ������С��饤�Ȥ�����
82 �Ȥ��ϡ��Ķ��ѿ� "M17NDIR" �ǻ��ꤵ���ǥ��쥯�ȥ�ʻ��ꤵ��Ƥ���
83 ���Ȥ��� "~/.m17n.d" �Ȥ����ǥ��쥯�ȥ�ˤ��̤Υǡ������֤���
84
85 m17n
86 �ǡ����١����ˤ�ʣ����¿�ͤʥǡ������ޤޤ�Ƥ��ꡢ�ƥǡ�����
87 TAG0, TAG1, TAG2, TAG3�ʤ��٤ƥ���ܥ�ˤΣ��ĤΥ����ˤ�äƼ��̤���롣
88
89 TAG0 �ˤ�äơ��ǡ����١�����Υǡ����Υ����פϼ��Τ褦�˻��ꤵ��롣
90
91 @li
92 TAG0 �� #Mchar_table �Ǥ���ǡ����� @e chartable������
93 �ȸƤФ졢��ʸ���˴ؤ����������롣���ξ��
94 TAG1 �Ͼ���μ������ꤹ�륷��ܥ�Ǥ��ꡢ#Msymbol, #Minteger, #Mstring,
95 #Mtext, #Mplist �Τ����줫�Ǥ��롣TAG2 �� TAG3 ��Ǥ�դΥ���ܥ�Ǥ褤��
96
97 @li
98 TAG0 �� #Mcharset �Ǥ���ǡ����� @e charset������
99 �ȸƤФ졢ʸ�����å��ѤΥǥ����ɡ������ɥޥåפ����롣���ξ�� TAG1
100 ��ʸ�����åȤΥ���ܥ�Ǥʤ���Фʤ�ʤ���TAG2 �� TAG3
101 ��Ǥ�դΥ���ܥ�Ǥ褤��
102
103 @li
104 TAG0 �� #Mchar_table �Ǥ� #Mcharset �Ǥ�ʤ���硢���Υǡ����� @e
105 plist������ �Ǥ��롣�ܺ٤˴ؤ��Ƥϴؿ� mdatabase_load ()
106 �������ȤΤ��ȡ����ξ�� TAG1��TAG2��TAG3 ��Ǥ�դΥ���ܥ�Ǥ褤��
107
108 ����Υ�������ĥǡ����١����� \<TAG0, TAG1, TAG2, TAG3\>
109 �Ȥ���������ɽ����
110
111 ���ץꥱ�������ץ����ϡ��ޤ��ؿ� mdatabase_find ()
112 ��Ȥäƥǡ����١����˴ؤ��������ݻ����륪�֥������ȡ�#MDatabase
113 ���ˤؤΥݥ������롣��������������顢 mdatabase_load ()
114 �ˤ�äƼºݤ˥ǡ����١�������ɤ��롣��¤�� #MDatabase
115 ���Ȥ��ɤ���������Ƥ��뤫�ϡ����ץꥱ�������ץ���फ��ϸ����ʤ���
116
117 @latexonly \IPAlabel{database} @endlatexonly
118 */
119
120 /*=*/
121
122 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
123 /*** @addtogroup m17nInternal
124 @{ */
125
126 #include <config.h>
127 #include <stdio.h>
128 #include <stdlib.h>
129 #include <string.h>
130 #include <ctype.h>
131 #include <sys/types.h>
132 #include <sys/stat.h>
133 #include <unistd.h>
134 #include <limits.h>
135 #include <glob.h>
136 #include <time.h>
137 #include <libgen.h>
138
139 #include "m17n-core.h"
140 #include "m17n-misc.h"
141 #include "internal.h"
142 #include "mtext.h"
143 #include "character.h"
144 #include "database.h"
145 #include "plist.h"
146
147 /** The file containing a list of databases. */
148 #define MDB_DIR "mdb.dir"
149 /** Length of MDB_DIR. */
150 #define MDB_DIR_LEN 7
151
152 #define MAX_TIME(TIME1, TIME2) ((TIME1) >= (TIME2) ? (TIME1) : (TIME2))
153
154 #define GEN_PATH(path, dir, dir_len, file, file_len) \
155 (dir_len + file_len > PATH_MAX ? 0 \
156 : (memcpy (path, dir, dir_len), \
157 memcpy (path + dir_len, file, file_len), \
158 path[dir_len + file_len] = '\0', 1))
159
160 static MSymbol Masterisk;
161 static MSymbol Mversion;
162
163 /** Structure for a data in the m17n database. */
164
165 struct MDatabase
166 {
167 /** Tags to identify the data. <tag>[0] specifies the type of
168 database. If it is #Mchar_table, the type is @e chartable, if
169 it is #Mcharset, the type is @e charset, otherwise the type is
170 @e plist. */
171 MSymbol tag[4];
172
173 void *(*loader) (MSymbol *tags, void *extra_info);
174
175 /** The meaning of the value is dependent on <loader>. If <loader>
176 is load_database (), the value is a string of the file name that
177 contains the data. */
178 void *extra_info;
179 };
180
181 static MPlist *mdatabase__list;
182
183 static int
read_number(char * buf,int * i)184 read_number (char *buf, int *i)
185 {
186 int idx = *i;
187 int c = buf[idx++];
188 int n;
189
190 if (!c)
191 return -1;
192
193 while (c && isspace (c)) c = buf[idx++];
194
195 if (c == '0')
196 {
197 if (buf[idx] == 'x')
198 {
199 for (idx++, c = 0; (n = hex_mnemonic[(unsigned) buf[idx]]) < 16;
200 idx++)
201 c = (c << 4) | n;
202 *i = idx;
203 return c;
204 }
205 c = 0;
206 }
207 else if (c == '\'')
208 {
209 c = buf[idx++];
210 if (c == '\\')
211 {
212 c = buf[idx++];
213 n = escape_mnemonic[c];
214 if (n != 255)
215 c = n;
216 }
217 while (buf[idx] && buf[idx++] != '\'');
218 *i = idx;
219 return c;
220 }
221 else if (hex_mnemonic[c] < 10)
222 c -= '0';
223 else
224 return -1;
225
226 while ((n = hex_mnemonic[(unsigned) buf[idx]]) < 10)
227 c = (c * 10) + n, idx++;
228 *i = idx;
229 return c;
230 }
231
232
233 /** Load a data of type @c chartable from the file FD, and return the
234 newly created chartable. */
235
236 static void *
load_chartable(FILE * fp,MSymbol type)237 load_chartable (FILE *fp, MSymbol type)
238 {
239 int c, from, to;
240 char buf[1024];
241 void *val;
242 MCharTable *table;
243
244 if (! fp)
245 MERROR (MERROR_DB, NULL);
246
247 table = mchartable (type, (type == Msymbol ? (void *) Mnil
248 : type == Minteger ? (void *) -1
249 : NULL));
250
251 while (! feof (fp))
252 {
253 int i, len;
254
255 for (len = 0; len < 1023 && (c = getc (fp)) != EOF && c != '\n'; len++)
256 buf[len] = c;
257 buf[len] = '\0';
258 if (hex_mnemonic[(unsigned) buf[0]] >= 10)
259 /* skip comment/invalid line */
260 continue;
261 i = 0;
262 from = read_number (buf, &i);
263 if (buf[i] == '-')
264 i++, to = read_number (buf, &i);
265 else
266 to = from;
267 if (from < 0 || to < from)
268 continue;
269
270 while (buf[i] && isspace ((unsigned) buf[i])) i++;
271 c = buf[i];
272 if (!c)
273 continue;
274
275 if (type == Mstring)
276 {
277 /* VAL is a C-string. */
278 if (! (val = strdup (buf + i)))
279 MEMORY_FULL (MERROR_DB);
280 }
281 else if (type == Minteger)
282 {
283 /* VAL is an integer. */
284 int positive = 1;
285 int n;
286
287 if (c == '-')
288 i++, positive = -1;
289 n = read_number (buf, &i);
290 if (n < 0)
291 goto label_error;
292 val = (void *) (n * positive);
293 }
294 else if (type == Mtext)
295 {
296 /* VAL is an M-text. */
297 MText *mt;
298 if (c == '"')
299 mt = mtext__from_data (buf + i, len - i - 1, MTEXT_FORMAT_UTF_8, 1);
300 else
301 {
302 mt = mtext ();
303 while ((c = read_number (buf, &i)) >= 0)
304 mt = mtext_cat_char (mt, c);
305 }
306 val = (void *) mt;
307 }
308 else if (type == Msymbol)
309 {
310 char *p = buf + i;
311
312 while (*p && ! isspace (*p))
313 {
314 if (*p == '\\' && p[1] != '\0')
315 {
316 memmove (p, p + 1, buf + len - (p + 1));
317 len--;
318 }
319 p++;
320 }
321 *p = '\0';
322 if (! strcmp (buf + i, "nil"))
323 val = (void *) Mnil;
324 else
325 val = (void *) msymbol (buf + i);
326 }
327 else if (type == Mplist)
328 {
329 val = (void *) mplist__from_string ((unsigned char *) buf + i,
330 strlen (buf + i));
331 }
332 else
333 val = NULL;
334
335 if (from == to)
336 mchartable_set (table, from, val);
337 else
338 mchartable_set_range (table, from, to, val);
339 }
340 return table;
341
342 label_error:
343 M17N_OBJECT_UNREF (table);
344 MERROR (MERROR_DB, NULL);
345 }
346
347
348 static char *
gen_database_name(char * buf,MSymbol * tags)349 gen_database_name (char *buf, MSymbol *tags)
350 {
351 int i;
352
353 strcpy (buf, msymbol_name (tags[0]));
354 for (i = 1; i < 4; i++)
355 {
356 strcat (buf, ",");
357 strcat (buf, msymbol_name (tags[i]));
358 }
359 return buf;
360 }
361
362 /* Return the absolute file name for DB_INFO->filename or NULL if no
363 absolute file name was found. If BUF is non-NULL, store the result
364 of `stat' call in it. In that case, set *RESULT to the return
365 value of `stat'. */
366
367 char *
get_database_file(MDatabaseInfo * db_info,struct stat * buf,int * result)368 get_database_file (MDatabaseInfo *db_info, struct stat *buf, int *result)
369 {
370 if (db_info->absolute_filename)
371 {
372 if (buf)
373 *result = stat (db_info->absolute_filename, buf);
374 }
375 else
376 {
377 struct stat stat_buf;
378 struct stat *statbuf = buf ? buf : &stat_buf;
379 int res;
380 MPlist *plist;
381 char path[PATH_MAX + 1];
382
383 MPLIST_DO (plist, mdatabase__dir_list)
384 {
385 MDatabaseInfo *dir_info = MPLIST_VAL (plist);
386
387 if (dir_info->status != MDB_STATUS_DISABLED
388 && GEN_PATH (path, dir_info->filename, dir_info->len,
389 db_info->filename, db_info->len)
390 && (res = stat (path, statbuf)) == 0)
391 {
392 db_info->absolute_filename = strdup (path);
393 if (result)
394 *result = res;
395 break;
396 }
397 }
398 }
399
400 return db_info->absolute_filename;
401 }
402
403 static void *
load_database(MSymbol * tags,void * extra_info)404 load_database (MSymbol *tags, void *extra_info)
405 {
406 MDatabaseInfo *db_info = extra_info;
407 void *value;
408 char *filename = get_database_file (db_info, NULL, NULL);
409 FILE *fp;
410 int mdebug_flag = MDEBUG_DATABASE;
411 char buf[256];
412
413 MDEBUG_PRINT1 (" [DB] <%s>", gen_database_name (buf, tags));
414 if (! filename || ! (fp = fopen (filename, "r")))
415 {
416 if (filename)
417 MDEBUG_PRINT1 (" open fail: %s\n", filename);
418 else
419 MDEBUG_PRINT1 (" not found: %s\n", db_info->filename);
420 MERROR (MERROR_DB, NULL);
421 }
422
423 MDEBUG_PRINT1 (" from %s\n", filename);
424
425 if (tags[0] == Mchar_table)
426 value = load_chartable (fp, tags[1]);
427 else if (tags[0] == Mcharset)
428 {
429 if (! mdatabase__load_charset_func)
430 MERROR (MERROR_DB, NULL);
431 value = (*mdatabase__load_charset_func) (fp, tags[1]);
432 }
433 else
434 value = mplist__from_file (fp, NULL);
435 fclose (fp);
436
437 if (! value)
438 MERROR (MERROR_DB, NULL);
439 db_info->time = time (NULL);
440 return value;
441 }
442
443
444 /** Return a newly allocated MDatabaseInfo for DIRNAME. */
445
446 static MDatabaseInfo *
get_dir_info(char * dirname)447 get_dir_info (char *dirname)
448 {
449 MDatabaseInfo *dir_info;
450
451 MSTRUCT_CALLOC (dir_info, MERROR_DB);
452 if (dirname)
453 {
454 int len = strlen (dirname);
455
456 if (len + MDB_DIR_LEN < PATH_MAX)
457 {
458 MTABLE_MALLOC (dir_info->filename, len + 2, MERROR_DB);
459 memcpy (dir_info->filename, dirname, len + 1);
460 /* Append PATH_SEPARATOR if DIRNAME doesn't end with it. */
461 if (dir_info->filename[len - 1] != PATH_SEPARATOR)
462 {
463 dir_info->filename[len] = PATH_SEPARATOR;
464 dir_info->filename[++len] = '\0';
465 }
466 dir_info->len = len;
467 dir_info->status = MDB_STATUS_OUTDATED;
468 }
469 else
470 dir_info->status = MDB_STATUS_DISABLED;
471 }
472 else
473 dir_info->status = MDB_STATUS_DISABLED;
474 return dir_info;
475 }
476
477 static void register_databases_in_files (MSymbol tags[4],
478 char *filename, int len);
479
480 static MDatabase *
find_database(MSymbol tags[4])481 find_database (MSymbol tags[4])
482 {
483 MPlist *plist;
484 int i;
485 MDatabase *mdb;
486
487 if (! mdatabase__list)
488 return NULL;
489 for (i = 0, plist = mdatabase__list; i < 4; i++)
490 {
491 MPlist *pl = mplist__assq (plist, tags[i]);
492 MPlist *p;
493
494 if ((p = mplist__assq (plist, Masterisk)))
495 {
496 MDatabaseInfo *db_info;
497 int j;
498
499 p = MPLIST_PLIST (p);
500 for (j = i + 1; j < 4; j++)
501 p = MPLIST_PLIST (MPLIST_NEXT (p));
502 mdb = MPLIST_VAL (MPLIST_NEXT (p));
503 db_info = mdb->extra_info;
504 if (db_info->status != MDB_STATUS_DISABLED)
505 {
506 register_databases_in_files (mdb->tag,
507 db_info->filename, db_info->len);
508 db_info->status = MDB_STATUS_DISABLED;
509 return find_database (tags);
510 }
511 }
512 if (! pl)
513 return NULL;
514 plist = MPLIST_PLIST (pl);
515 plist = MPLIST_NEXT (plist);
516 }
517 mdb = MPLIST_VAL (plist);
518 return mdb;
519 }
520
521 static void
free_db_info(MDatabaseInfo * db_info)522 free_db_info (MDatabaseInfo *db_info)
523 {
524 free (db_info->filename);
525 if (db_info->absolute_filename
526 && db_info->filename != db_info->absolute_filename)
527 free (db_info->absolute_filename);
528 M17N_OBJECT_UNREF (db_info->properties);
529 free (db_info);
530 }
531
532 static int
check_version(MText * version)533 check_version (MText *version)
534 {
535 char *verstr = (char *) MTEXT_DATA (version);
536 char *endp = verstr + mtext_nbytes (version);
537 int ver[3];
538 int i;
539
540 ver[0] = ver[1] = ver[2] = 0;
541 for (i = 0; verstr < endp; verstr++)
542 {
543 if (*verstr == '.')
544 {
545 i++;
546 if (i == 3)
547 break;
548 continue;
549 }
550 if (! isdigit (*verstr))
551 break;
552 ver[i] = ver[i] * 10 + (*verstr - '0');
553 }
554 return (ver[0] < M17NLIB_MAJOR_VERSION
555 || (ver[0] == M17NLIB_MAJOR_VERSION
556 && (ver[1] < M17NLIB_MINOR_VERSION
557 || (ver[1] == M17NLIB_MINOR_VERSION
558 && ver[2] <= M17NLIB_PATCH_LEVEL))));
559 }
560
561 static MDatabase *
register_database(MSymbol tags[4],void * (* loader)(MSymbol *,void *),void * extra_info,enum MDatabaseStatus status,MPlist * properties)562 register_database (MSymbol tags[4],
563 void *(*loader) (MSymbol *, void *),
564 void *extra_info, enum MDatabaseStatus status,
565 MPlist *properties)
566 {
567 MDatabase *mdb;
568 MDatabaseInfo *db_info;
569 int i;
570 MPlist *plist;
571
572 if (properties)
573 {
574 MPLIST_DO (plist, properties)
575 if (MPLIST_PLIST_P (plist))
576 {
577 MPlist *p = MPLIST_PLIST (plist);
578
579 if (MPLIST_SYMBOL_P (p)
580 && MPLIST_SYMBOL (p) == Mversion
581 && MPLIST_MTEXT_P (MPLIST_NEXT (p)))
582 {
583 if (check_version (MPLIST_MTEXT (MPLIST_NEXT (p))))
584 break;
585 return NULL;
586 }
587 }
588 }
589
590 for (i = 0, plist = mdatabase__list; i < 4; i++)
591 {
592 MPlist *pl = mplist__assq (plist, tags[i]);
593
594 if (pl)
595 pl = MPLIST_PLIST (pl);
596 else
597 {
598 pl = mplist ();
599 mplist_add (pl, Msymbol, tags[i]);
600 mplist_push (plist, Mplist, pl);
601 M17N_OBJECT_UNREF (pl);
602 }
603 plist = MPLIST_NEXT (pl);
604 }
605
606 if (MPLIST_TAIL_P (plist))
607 {
608 MSTRUCT_MALLOC (mdb, MERROR_DB);
609 for (i = 0; i < 4; i++)
610 mdb->tag[i] = tags[i];
611 mdb->loader = loader;
612 if (loader == load_database)
613 {
614 MSTRUCT_CALLOC (db_info, MERROR_DB);
615 mdb->extra_info = db_info;
616 }
617 else
618 {
619 db_info = NULL;
620 mdb->extra_info = extra_info;
621 }
622 mplist_push (plist, Mt, mdb);
623 }
624 else
625 {
626 mdb = MPLIST_VAL (plist);
627 if (loader == load_database)
628 db_info = mdb->extra_info;
629 else
630 db_info = NULL;
631 }
632
633 if (db_info)
634 {
635 db_info->status = status;
636 if (! db_info->filename
637 || strcmp (db_info->filename, (char *) extra_info) != 0)
638 {
639 if (db_info->filename)
640 free (db_info->filename);
641 if (db_info->absolute_filename
642 && db_info->filename != db_info->absolute_filename)
643 free (db_info->absolute_filename);
644 db_info->filename = strdup ((char *) extra_info);
645 db_info->len = strlen ((char *) extra_info);
646 db_info->time = 0;
647 }
648 if (db_info->filename[0] == PATH_SEPARATOR)
649 db_info->absolute_filename = db_info->filename;
650 else
651 db_info->absolute_filename = NULL;
652 M17N_OBJECT_UNREF (db_info->properties);
653 if (properties)
654 {
655 db_info->properties = properties;
656 M17N_OBJECT_REF (properties);
657 }
658 }
659
660 if (mdb->tag[0] == Mchar_table
661 && mdb->tag[2] != Mnil
662 && (mdb->tag[1] == Mstring || mdb->tag[1] == Mtext
663 || mdb->tag[1] == Msymbol || mdb->tag[1] == Minteger
664 || mdb->tag[1] == Mplist))
665 mchar__define_prop (mdb->tag[2], mdb->tag[1], mdb);
666 return mdb;
667 }
668
669 static void
register_databases_in_files(MSymbol tags[4],char * filename,int len)670 register_databases_in_files (MSymbol tags[4], char *filename, int len)
671 {
672 int i, j;
673 MPlist *load_key = mplist ();
674 FILE *fp;
675 MPlist *plist, *pl;
676
677 MPLIST_DO (plist, mdatabase__dir_list)
678 {
679 glob_t globbuf;
680 int headlen;
681
682 if (filename[0] == PATH_SEPARATOR)
683 {
684 if (glob (filename, GLOB_NOSORT, NULL, &globbuf))
685 break;
686 headlen = 0;
687 }
688 else
689 {
690 MDatabaseInfo *d_info = MPLIST_VAL (plist);
691 char path[PATH_MAX + 1];
692
693 if (d_info->status == MDB_STATUS_DISABLED)
694 continue;
695 if (! GEN_PATH (path, d_info->filename, d_info->len, filename, len))
696 continue;
697 if (glob (path, GLOB_NOSORT, NULL, &globbuf))
698 continue;
699 headlen = d_info->len;
700 }
701
702 for (i = 0; i < globbuf.gl_pathc; i++)
703 {
704 if (! (fp = fopen (globbuf.gl_pathv[i], "r")))
705 continue;
706 pl = mplist__from_file (fp, load_key);
707 fclose (fp);
708 if (! pl)
709 continue;
710 if (MPLIST_PLIST_P (pl))
711 {
712 MPlist *p;
713 MSymbol tags2[4];
714
715 for (j = 0, p = MPLIST_PLIST (pl); j < 4 && MPLIST_SYMBOL_P (p);
716 j++, p = MPLIST_NEXT (p))
717 tags2[j] = MPLIST_SYMBOL (p);
718 for (; j < 4; j++)
719 tags2[j] = Mnil;
720 for (j = 0; j < 4; j++)
721 if (tags[j] != Masterisk && tags[j] != tags2[j])
722 break;
723 if (j == 4)
724 register_database (tags2, load_database,
725 globbuf.gl_pathv[i] + headlen,
726 MDB_STATUS_AUTO, p);
727 }
728 M17N_OBJECT_UNREF (pl);
729 }
730 globfree (&globbuf);
731 if (filename[0] == PATH_SEPARATOR)
732 break;
733 }
734 M17N_OBJECT_UNREF (load_key);
735 }
736
737 static int
expand_wildcard_database(MPlist * plist)738 expand_wildcard_database (MPlist *plist)
739 {
740 MDatabase *mdb;
741 MDatabaseInfo *db_info;
742
743 plist = MPLIST_NEXT (plist);
744 while (MPLIST_PLIST_P (plist))
745 {
746 plist = MPLIST_PLIST (plist);
747 plist = MPLIST_NEXT (plist);
748 }
749 mdb = MPLIST_VAL (plist);
750 if (mdb->loader == load_database
751 && (db_info = mdb->extra_info)
752 && db_info->status != MDB_STATUS_DISABLED)
753 {
754 register_databases_in_files (mdb->tag, db_info->filename, db_info->len);
755 db_info->status = MDB_STATUS_DISABLED;
756 return 1;
757 }
758 return 0;
759 }
760
761
762 /* Internal API */
763
764 /** List of database directories. */
765 MPlist *mdatabase__dir_list;
766
767 void *(*mdatabase__load_charset_func) (FILE *fp, MSymbol charset_name);
768
769 int
mdatabase__init()770 mdatabase__init ()
771 {
772 MDatabaseInfo *dir_info;
773 char *path;
774
775 mdatabase__load_charset_func = NULL;
776
777 Mchar_table = msymbol ("char-table");
778 Mcharset = msymbol ("charset");
779 Masterisk = msymbol ("*");
780 Mversion = msymbol ("version");
781
782 mdatabase__dir_list = mplist ();
783 /** The macro M17NDIR specifies a directory where the system-wide
784 MDB_DIR file exists. */
785 mplist_set (mdatabase__dir_list, Mt, get_dir_info (M17NDIR));
786
787 /* The variable mdatabase_dir specifies a directory where an
788 application program specific MDB_DIR file exists. */
789 if (mdatabase_dir && strlen (mdatabase_dir) > 0)
790 mplist_push (mdatabase__dir_list, Mt, get_dir_info (mdatabase_dir));
791
792 /* The environment variable M17NDIR specifies a directory where a
793 user specific MDB_DIR file exists. */
794 path = getenv ("M17NDIR");
795 if (path && strlen (path) > 0)
796 mplist_push (mdatabase__dir_list, Mt, get_dir_info (path));
797 else
798 {
799 /* If the env var M17NDIR is not set, check "~/.m17n.d". */
800 char *home = getenv ("HOME");
801 int len;
802
803 if (home
804 && (len = strlen (home))
805 && (path = alloca (len + 9)))
806 {
807 strcpy (path, home);
808 if (path[len - 1] != PATH_SEPARATOR)
809 path[len++] = PATH_SEPARATOR;
810 strcpy (path + len, ".m17n.d");
811 dir_info = get_dir_info (path);
812 mplist_push (mdatabase__dir_list, Mt, dir_info);
813 }
814 else
815 mplist_push (mdatabase__dir_list, Mt, get_dir_info (NULL));
816 }
817
818 mdatabase__list = mplist ();
819 mdatabase__update ();
820 return 0;
821 }
822
823 void
mdatabase__fini(void)824 mdatabase__fini (void)
825 {
826 MPlist *plist, *p0, *p1, *p2, *p3;
827
828 MPLIST_DO (plist, mdatabase__dir_list)
829 free_db_info (MPLIST_VAL (plist));
830 M17N_OBJECT_UNREF (mdatabase__dir_list);
831
832 /* MDATABASE_LIST ::= ((TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) ...) */
833 MPLIST_DO (plist, mdatabase__list)
834 {
835 p0 = MPLIST_PLIST (plist);
836 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) */
837 MPLIST_DO (p0, MPLIST_NEXT (p0))
838 {
839 p1 = MPLIST_PLIST (p0);
840 /* P1 ::= (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) */
841 MPLIST_DO (p1, MPLIST_NEXT (p1))
842 {
843 p2 = MPLIST_PLIST (p1);
844 /* P2 ::= (TAG2 (TAG3 t:MDB) ...) */
845 MPLIST_DO (p2, MPLIST_NEXT (p2))
846 {
847 MDatabase *mdb;
848
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);
854 free (mdb);
855 }
856 }
857 }
858 }
859 M17N_OBJECT_UNREF (mdatabase__list);
860 }
861
862 void
mdatabase__update(void)863 mdatabase__update (void)
864 {
865 MPlist *plist, *p0, *p1, *p2, *p3;
866 char path[PATH_MAX + 1];
867 MDatabaseInfo *dir_info;
868 struct stat statbuf;
869 int rescan = 0;
870
871 /* Update elements of mdatabase__dir_list. */
872 MPLIST_DO (plist, mdatabase__dir_list)
873 {
874 dir_info = MPLIST_VAL (plist);
875 if (dir_info->filename)
876 {
877 if (stat (dir_info->filename, &statbuf) == 0
878 && (statbuf.st_mode & S_IFDIR))
879 {
880 if (dir_info->time < statbuf.st_mtime)
881 {
882 rescan = 1;
883 dir_info->time = statbuf.st_mtime;
884 }
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)
889 {
890 rescan = 1;
891 dir_info->time = statbuf.st_mtime;
892 }
893 dir_info->status = MDB_STATUS_UPDATED;
894 }
895 else
896 {
897 if (dir_info->status != MDB_STATUS_DISABLED)
898 {
899 rescan = 1;
900 dir_info->time = 0;
901 dir_info->status = MDB_STATUS_DISABLED;
902 }
903 }
904 }
905 }
906
907 if (! rescan)
908 return;
909
910 /* At first, mark all databases defined automatically from mdb.dir
911 file(s) as "disabled". */
912 MPLIST_DO (plist, mdatabase__list)
913 {
914 p0 = MPLIST_PLIST (plist);
915 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
916 MPLIST_DO (p0, MPLIST_NEXT (p0))
917 {
918 p1 = MPLIST_PLIST (p0);
919 MPLIST_DO (p1, MPLIST_NEXT (p1))
920 {
921 p2 = MPLIST_PLIST (p1);
922 MPLIST_DO (p2, MPLIST_NEXT (p2))
923 {
924 MDatabase *mdb;
925 MDatabaseInfo *db_info;
926
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;
933 }
934 }
935 }
936 }
937
938 plist = mplist ();
939 MPLIST_DO (p0, mdatabase__dir_list)
940 mplist_push (plist, MPLIST_KEY (p0), MPLIST_VAL (p0));
941
942 while (! MPLIST_TAIL_P (plist))
943 {
944 MDatabaseInfo *dir_info = mplist_pop (plist);
945 MPlist *pl, *p;
946 int i;
947 FILE *fp;
948
949 if (dir_info->status == MDB_STATUS_DISABLED)
950 continue;
951 if (! GEN_PATH (path, dir_info->filename, dir_info->len,
952 MDB_DIR, MDB_DIR_LEN))
953 continue;
954 if (! (fp = fopen (path, "r")))
955 continue;
956 pl = mplist__from_file (fp, NULL);
957 fclose (fp);
958 if (! pl)
959 continue;
960 MPLIST_DO (p, pl)
961 {
962 MSymbol tags[4];
963 MPlist *p1;
964 MText *mt;
965 int nbytes;
966 int with_wildcard = 0;
967
968 if (! MPLIST_PLIST_P (p))
969 continue;
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);
973 if (i == 0
974 || tags[0] == Masterisk
975 || ! MPLIST_MTEXT_P (p1))
976 continue;
977 for (; i < 4; i++)
978 tags[i] = with_wildcard ? Masterisk : Mnil;
979 mt = MPLIST_MTEXT (p1);
980 nbytes = mtext_nbytes (mt);
981 if (nbytes > PATH_MAX)
982 continue;
983 memcpy (path, MTEXT_DATA (mt), nbytes);
984 path[nbytes] = '\0';
985 if (with_wildcard)
986 register_database (tags, load_database, path,
987 MDB_STATUS_AUTO_WILDCARD, NULL);
988 else
989 register_database (tags, load_database, path,
990 MDB_STATUS_AUTO, p1);
991 }
992 M17N_OBJECT_UNREF (pl);
993 }
994 M17N_OBJECT_UNREF (plist);
995 }
996
997 MPlist *
mdatabase__load_for_keys(MDatabase * mdb,MPlist * keys)998 mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
999 {
1000 int mdebug_flag = MDEBUG_DATABASE;
1001 MDatabaseInfo *db_info;
1002 char *filename;
1003 FILE *fp;
1004 MPlist *plist;
1005 char name[256];
1006
1007 if (mdb->loader != load_database
1008 || mdb->tag[0] == Mchar_table
1009 || mdb->tag[0] == Mcharset)
1010 MERROR (MERROR_DB, NULL);
1011 MDEBUG_PRINT1 (" [DB] <%s>.\n",
1012 gen_database_name (name, mdb->tag));
1013 db_info = mdb->extra_info;
1014 filename = get_database_file (db_info, NULL, NULL);
1015 if (! filename || ! (fp = fopen (filename, "r")))
1016 MERROR (MERROR_DB, NULL);
1017 plist = mplist__from_file (fp, keys);
1018 fclose (fp);
1019 return plist;
1020 }
1021
1022
1023 /* Check if the database MDB should be reloaded or not. It returns:
1024
1025 1: The database has not been updated since it was loaded last
1026 time.
1027
1028 0: The database has never been loaded or has been updated
1029 since it was loaded last time.
1030
1031 -1: The database is not loadable at the moment. */
1032
1033 int
mdatabase__check(MDatabase * mdb)1034 mdatabase__check (MDatabase *mdb)
1035 {
1036 MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
1037 struct stat buf;
1038 int result;
1039
1040 if (db_info->absolute_filename != db_info->filename
1041 || db_info->status == MDB_STATUS_AUTO)
1042 mdatabase__update ();
1043
1044 if (! get_database_file (db_info, &buf, &result)
1045 || result < 0)
1046 return -1;
1047 if (db_info->time < buf.st_mtime)
1048 return 0;
1049 return 1;
1050 }
1051
1052 /* Search directories in mdatabase__dir_list for file FILENAME. If
1053 the file exist, return the absolute pathname. If FILENAME is
1054 already absolute, return a copy of it. */
1055
1056 char *
mdatabase__find_file(char * filename)1057 mdatabase__find_file (char *filename)
1058 {
1059 struct stat buf;
1060 int result;
1061 MDatabaseInfo db_info;
1062
1063 if (filename[0] == PATH_SEPARATOR)
1064 return (stat (filename, &buf) == 0 ? strdup (filename) : NULL);
1065 db_info.filename = filename;
1066 db_info.len = strlen (filename);
1067 db_info.time = 0;
1068 db_info.absolute_filename = NULL;
1069 if (! get_database_file (&db_info, &buf, &result)
1070 || result < 0)
1071 return NULL;
1072 return db_info.absolute_filename;
1073 }
1074
1075 char *
mdatabase__file(MDatabase * mdb)1076 mdatabase__file (MDatabase *mdb)
1077 {
1078 MDatabaseInfo *db_info;
1079
1080 if (mdb->loader != load_database)
1081 return NULL;
1082 db_info = mdb->extra_info;
1083 return get_database_file (db_info, NULL, NULL);
1084 }
1085
1086 int
mdatabase__lock(MDatabase * mdb)1087 mdatabase__lock (MDatabase *mdb)
1088 {
1089 MDatabaseInfo *db_info;
1090 struct stat buf;
1091 FILE *fp;
1092 int len;
1093 char *file;
1094
1095 if (mdb->loader != load_database)
1096 return -1;
1097 db_info = mdb->extra_info;
1098 if (db_info->lock_file)
1099 return -1;
1100 file = get_database_file (db_info, NULL, NULL);
1101 if (! file)
1102 return -1;
1103 len = strlen (file);
1104 db_info->uniq_file = malloc (len + 35);
1105 if (! db_info->uniq_file)
1106 return -1;
1107 db_info->lock_file = malloc (len + 5);
1108 if (! db_info->lock_file)
1109 {
1110 free (db_info->uniq_file);
1111 return -1;
1112 }
1113 sprintf (db_info->uniq_file, "%s.%X.%X", db_info->absolute_filename,
1114 (unsigned) time (NULL), (unsigned) getpid ());
1115 sprintf (db_info->lock_file, "%s.LCK", db_info->absolute_filename);
1116
1117 fp = fopen (db_info->uniq_file, "w");
1118 if (! fp)
1119 {
1120 char *str = strdup (db_info->uniq_file);
1121 char *dir = dirname (str);
1122
1123 if (stat (dir, &buf) == 0
1124 || mkdir (dir, 0777) < 0
1125 || ! (fp = fopen (db_info->uniq_file, "w")))
1126 {
1127 free (db_info->uniq_file);
1128 free (db_info->lock_file);
1129 db_info->lock_file = NULL;
1130 free (str);
1131 return -1;
1132 }
1133 free (str);
1134 }
1135 fclose (fp);
1136 if (link (db_info->uniq_file, db_info->lock_file) < 0
1137 && (stat (db_info->uniq_file, &buf) < 0
1138 || buf.st_nlink != 2))
1139 {
1140 unlink (db_info->uniq_file);
1141 unlink (db_info->lock_file);
1142 free (db_info->uniq_file);
1143 free (db_info->lock_file);
1144 db_info->lock_file = NULL;
1145 return 0;
1146 }
1147 return 1;
1148 }
1149
1150 int
mdatabase__save(MDatabase * mdb,MPlist * data)1151 mdatabase__save (MDatabase *mdb, MPlist *data)
1152 {
1153 MDatabaseInfo *db_info;
1154 FILE *fp;
1155 char *file;
1156 MText *mt;
1157 int ret;
1158
1159 if (mdb->loader != load_database)
1160 return -1;
1161 db_info = mdb->extra_info;
1162 if (! db_info->lock_file)
1163 return -1;
1164 file = get_database_file (db_info, NULL, NULL);
1165 if (! file)
1166 return -1;
1167 mt = mtext ();
1168 if (mplist__serialize (mt, data, 1) < 0)
1169 {
1170 M17N_OBJECT_UNREF (mt);
1171 return -1;
1172 }
1173 fp = fopen (db_info->uniq_file, "w");
1174 if (! fp)
1175 {
1176 M17N_OBJECT_UNREF (mt);
1177 return -1;
1178 }
1179 if (mt->format > MTEXT_FORMAT_UTF_8)
1180 mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
1181 fwrite (MTEXT_DATA (mt), 1, mtext_nchars (mt), fp);
1182 fclose (fp);
1183 M17N_OBJECT_UNREF (mt);
1184 if ((ret = rename (db_info->uniq_file, file)) < 0)
1185 unlink (db_info->uniq_file);
1186 free (db_info->uniq_file);
1187 db_info->uniq_file = NULL;
1188 return ret;
1189 }
1190
1191 int
mdatabase__unlock(MDatabase * mdb)1192 mdatabase__unlock (MDatabase *mdb)
1193 {
1194 MDatabaseInfo *db_info;
1195
1196 if (mdb->loader != load_database)
1197 return -1;
1198 db_info = mdb->extra_info;
1199 if (! db_info->lock_file)
1200 return -1;
1201 unlink (db_info->lock_file);
1202 free (db_info->lock_file);
1203 db_info->lock_file = NULL;
1204 if (db_info->uniq_file)
1205 {
1206 unlink (db_info->uniq_file);
1207 free (db_info->uniq_file);
1208 }
1209 return 0;
1210 }
1211
1212 MPlist *
mdatabase__props(MDatabase * mdb)1213 mdatabase__props (MDatabase *mdb)
1214 {
1215 MDatabaseInfo *db_info;
1216
1217 if (mdb->loader != load_database)
1218 return NULL;
1219 db_info = mdb->extra_info;
1220 return db_info->properties;
1221 }
1222
1223 /*** @} */
1224 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1225
1226
1227 /* External API */
1228
1229 /*** @addtogroup m17nCharset */
1230 /*** @{ */
1231 /*=*/
1232 /***en
1233 @brief The symbol @c Mcharset.
1234
1235 Any decoded M-text has a text property whose key is the predefined
1236 symbol @c Mcharset. The name of @c Mcharset is
1237 <tt>"charset"</tt>. */
1238
1239 /***ja
1240 @brief ����ܥ� @c Mcharset.
1241
1242 �ǥ����ɤ��줿 M-text �ϡ������� @c Mcharset
1243 �Ǥ���褦�ʥƥ����ȥץ�ѥƥ�����ġ�
1244 ����ܥ� @c Mcharset �� <tt>"charset"</tt> �Ȥ���̾������ġ� */
1245
1246 MSymbol Mcharset;
1247 /*=*/
1248 /*** @} */
1249 /*=*/
1250
1251 /*** @addtogroup m17nDatabase */
1252 /*** @{ */
1253
1254 /*=*/
1255 /***en
1256 @brief Directory for application specific data.
1257
1258 If an application program wants to provide a data specific to the
1259 program or a data overriding what supplied by the m17n database,
1260 it must set this variable to a name of directory that contains the
1261 data files before it calls the macro M17N_INIT (). The directory
1262 may contain a file "mdb.dir" which contains a list of data
1263 definitions in the format described in @ref mdbDir "mdbDir(5)".
1264
1265 The default value is NULL. */
1266 /***ja
1267 @brief ���ץꥱ��������ͭ�Υǡ����ѥǥ��쥯�ȥ�.
1268
1269 ���ץꥱ�������ץ���ब�����Υץ�����ͭ�Υǡ����� m17n
1270 �ǡ����١���������ǡ�����������ˤϡ��ޥ��� M17N_INIT ()
1271 ��Ƥ����ˤ����ѿ���ǡ����ե������ޤ�ǥ��쥯�ȥ�̾�˥��åȤ��ʤ��ƤϤʤ�ʤ����ǥ��쥯�ȥ�ˤ�
1272 "mdb.dir" �ե���������Ȥ��Ǥ��롣����"mdb.dir"�ե�����ˤϡ�
1273 @ref mdbDir "mdbDir(5)" ����������Ƥ���ե����ޥåȤǥǡ�������Υꥹ�ȤҤ��롣
1274
1275 �ǥե���Ȥ��ͤ� NULL �Ǥ��롣 */
1276
1277 char *mdatabase_dir;
1278
1279 /*=*/
1280 /***en
1281 @brief Look for a data in the database.
1282
1283 The mdatabase_find () function searches the m17n database for a
1284 data who has tags $TAG0 through $TAG3, and returns a pointer to
1285 the data. If such a data is not found, it returns @c NULL. */
1286
1287 /***ja
1288 @brief �ǡ����١�����Υǡ�����õ��.
1289
1290 �ؿ� mdatabase_find () �ϡ� m17n �������١������ $TAG0 ����
1291 $TAG3 �ޤǤΥ�������ĥǡ�����õ��������ؤΥݥ����֤������Τ褦�ʥǡ������ʤ����
1292 @c NULL ���֤���
1293
1294 @latexonly \IPAlabel{mdatabase_find} @endlatexonly */
1295
1296 MDatabase *
mdatabase_find(MSymbol tag0,MSymbol tag1,MSymbol tag2,MSymbol tag3)1297 mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
1298 {
1299 MSymbol tags[4];
1300
1301 mdatabase__update ();
1302 tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
1303 return find_database (tags);
1304 }
1305
1306 /*=*/
1307 /***en
1308 @brief Return a data list of the m17n database.
1309
1310 The mdatabase_list () function searches the m17n database for data
1311 who have tags $TAG0 through $TAG3, and returns their list by a
1312 plist. The value #Mnil in $TAGn means a wild card that matches
1313 any tag. Each element of the plist has key #Mt and value a
1314 pointer to type #MDatabase. */
1315 /***ja
1316 @brief m17n �ǡ����١����Υǡ����ꥹ�Ȥ��֤�.
1317
1318 �ؿ� mdatabase_list () �� m17n �ǡ����١����椫�� $TAG0 ����$TAG3
1319 �ޤǤΥ�������ĥǡ�����õ�������Υꥹ�Ȥ�plist �Ȥ����֤��� $TAGn �� #Mnil
1320 �Ǥ��ä����ˤϡ�Ǥ�դΥ����˥ޥå�����磻��ɥ����ɤȤ��Ƽ�갷���롣�֤����
1321 plist �γ����Ǥϥ��� �Ȥ��� #Mt ���ͤȤ��� #MDatabase ���ؤΥݥ�����ġ� */
1322
1323 MPlist *
mdatabase_list(MSymbol tag0,MSymbol tag1,MSymbol tag2,MSymbol tag3)1324 mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
1325 {
1326 MPlist *plist = mplist (), *pl = plist;
1327 MPlist *p, *p0, *p1, *p2, *p3;
1328
1329 mdatabase__update ();
1330
1331 MPLIST_DO (p, mdatabase__list)
1332 {
1333 p0 = MPLIST_PLIST (p);
1334 /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
1335 if (MPLIST_SYMBOL (p0) == Masterisk
1336 || (tag0 != Mnil && MPLIST_SYMBOL (p0) != tag0))
1337 continue;
1338 MPLIST_DO (p0, MPLIST_NEXT (p0))
1339 {
1340 p1 = MPLIST_PLIST (p0);
1341 if (MPLIST_SYMBOL (p1) == Masterisk)
1342 {
1343 if (expand_wildcard_database (p1))
1344 {
1345 M17N_OBJECT_UNREF (plist);
1346 return mdatabase_list (tag0, tag1, tag2, tag3);
1347 }
1348 continue;
1349 }
1350 if (tag1 != Mnil && MPLIST_SYMBOL (p1) != tag1)
1351 continue;
1352 MPLIST_DO (p1, MPLIST_NEXT (p1))
1353 {
1354 p2 = MPLIST_PLIST (p1);
1355 if (MPLIST_SYMBOL (p2) == Masterisk)
1356 {
1357 if (expand_wildcard_database (p2))
1358 {
1359 M17N_OBJECT_UNREF (plist);
1360 return mdatabase_list (tag0, tag1, tag2, tag3);
1361 }
1362 continue;
1363 }
1364 if (tag2 != Mnil && MPLIST_SYMBOL (p2) != tag2)
1365 continue;
1366 MPLIST_DO (p2, MPLIST_NEXT (p2))
1367 {
1368 p3 = MPLIST_PLIST (p2);
1369 if (MPLIST_SYMBOL (p3) == Masterisk)
1370 {
1371 if (expand_wildcard_database (p3))
1372 {
1373 M17N_OBJECT_UNREF (plist);
1374 return mdatabase_list (tag0, tag1, tag2, tag3);
1375 }
1376 continue;
1377 }
1378 if (tag3 != Mnil && MPLIST_SYMBOL (p3) != tag3)
1379 continue;
1380 p3 = MPLIST_NEXT (p3);
1381 pl = mplist_add (pl, Mt, MPLIST_VAL (p3));
1382 }
1383 }
1384 }
1385 }
1386 if (MPLIST_TAIL_P (plist))
1387 M17N_OBJECT_UNREF (plist);
1388 return plist;
1389 }
1390
1391 /*=*/
1392 /***en
1393 @brief Define a data of the m17n database.
1394
1395 The mdatabase_define () function defines a data that has tags
1396 $TAG0 through $TAG3 and additional information $EXTRA_INFO.
1397
1398 $LOADER is a pointer to a function that loads the data from the
1399 database. This function is called from the mdatabase_load ()
1400 function with the two arguments $TAGS and $EXTRA_INFO. Here,
1401 $TAGS is the array of $TAG0 through $TAG3.
1402
1403 If $LOADER is @c NULL, the default loader of the m17n library is
1404 used. In this case, $EXTRA_INFO must be a string specifying a
1405 filename that contains the data.
1406
1407 @return
1408 If the operation was successful, mdatabase_define () returns a
1409 pointer to the defined data, which can be used as an argument to
1410 mdatabase_load (). Otherwise, it returns @c NULL. */
1411
1412 /***ja
1413 @brief m17n �ǡ����١����Υǡ������������.
1414
1415 �ؿ� mdatabase_define () �� $TAG0 ���� $TAG3 �ޤǤΥ���������ղþ���
1416 $EXTRA_INFO ����ĥǡ�����������롣
1417
1418 $LOADER �Ϥ��Υǡ����Υ��ɤ��Ѥ�����ؿ��ؤΥݥ��Ǥ��롣���δؿ���
1419 mdatabase_load () ���� $TAGS �� $EXTRA_INFO �Ȥ�����Ĥΰ����դ��ǸƤӽФ���롣������
1420 $TAGS �� $TAG0 ���� $TAG3 �ޤǤ�����Ǥ��롣
1421
1422 �⤷ $LOADER �� @c NULL �ʤ顢m17n �饤�֥��ɸ��Υ������Ȥ��롣���ξ��ˤ�
1423 $EXTRA_INFO �ϥǡ�����ޤ�ե�����̾�Ǥʤ��ƤϤʤ�ʤ���
1424
1425 @return
1426 ��������������� mdatabase_define ()
1427 ��������줿�ǡ����١����ؤΥݥ����֤������Υݥ��ϴؿ� mdatabase_load ()
1428 �ΰ����Ȥ����Ѥ��뤳�Ȥ��Ǥ��롣�����Ǥʤ���� @c NULL ���֤���
1429
1430 @latexonly \IPAlabel{mdatabase_define} @endlatexonly */
1431
1432 /***
1433 @seealso
1434 mdatabase_load (), mdatabase_define () */
1435
1436 MDatabase *
mdatabase_define(MSymbol tag0,MSymbol tag1,MSymbol tag2,MSymbol tag3,void * (* loader)(MSymbol *,void *),void * extra_info)1437 mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
1438 void *(*loader) (MSymbol *, void *),
1439 void *extra_info)
1440 {
1441 MDatabase *mdb;
1442 MSymbol tags[4];
1443
1444 tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
1445 if (! loader)
1446 loader = load_database;
1447 mdb = register_database (tags, loader, extra_info, MDB_STATUS_EXPLICIT, NULL);
1448 return mdb;
1449 }
1450
1451 /*=*/
1452 /***en
1453 @brief Load a data from the database.
1454
1455 The mdatabase_load () function loads a data specified in $MDB and
1456 returns the contents. The type of contents depends on the type of
1457 the data.
1458
1459 If the data is of the @e plist @e type, this function returns a
1460 pointer to @e plist.
1461
1462 If the database is of the @e chartable @e type, it returns a
1463 chartable. The default value of the chartable is set according to
1464 the second tag of the data as below:
1465
1466 @li If the tag is #Msymbol, the default value is #Mnil.
1467 @li If the tag is #Minteger, the default value is -1.
1468 @li Otherwise, the default value is @c NULL.
1469
1470 If the data is of the @e charset @e type, it returns a plist of length 2
1471 (keys are both #Mt). The value of the first element is an array
1472 of integers that maps code points to the corresponding character
1473 codes. The value of the second element is a chartable of integers
1474 that does the reverse mapping. The charset must be defined in
1475 advance. */
1476
1477
1478 /***ja
1479 @brief �ǡ����١�������ǡ�������ɤ���.
1480
1481 �ؿ� mdatabase_load () �� $MDB
1482 ���ؤ��ǡ�������ɤ���������Ȥ��֤����֤�����Τϥǡ����Υ����פˤ�äưۤʤ롣
1483
1484 �ǡ����� @e plist������ �ʤ�С� @e plist �ؤΥݥ����֤���
1485
1486 �ǡ����� @e chartable������ �ʤ��ʸ���ơ��֥���֤���
1487 ʸ���ơ��֥�Υǥե�����ͤϡ��ǡ�������2�����ˤ�äưʲ��Τ褦�˷�ޤ롣
1488
1489 @li ������ #Msymbol �ʤ顢�ǥե�����ͤ� #Mnil
1490 @li ������ #Minteger �ʤ顢�ǥե�����ͤ� -1
1491 @li ����ʳ��ʤ顢�ǥե�����ͤ� @c NULL
1492
1493 �ǡ����� @e charset������ �ʤ��Ĺ�� 2 �� plist ���֤��ʥ����϶���#Mt �ˡ�
1494 �ǽ�����Ǥ��ͤϥ����ɥݥ���Ȥ��б�����ʸ�������ɤ˥ޥåפ�������������Ǥ��롣
1495 �����ܤ����Ǥ��ͤϵդΥޥåפ�ʸ���ơ��֥�Ǥ��롣
1496 ����ʸ�����åȤ�ͽ���������Ƥ��ʤ���Фʤ�ʤ���
1497
1498 @latexonly \IPAlabel{mdatabase_load} @endlatexonly
1499 */
1500
1501 /***
1502 @seealso
1503 mdatabase_load (), mdatabase_define () */
1504
1505 void *
mdatabase_load(MDatabase * mdb)1506 mdatabase_load (MDatabase *mdb)
1507 {
1508 return (*mdb->loader) (mdb->tag, mdb->extra_info);
1509 }
1510
1511 /*=*/
1512 /***en
1513 @brief Get tags of a data.
1514
1515 The mdatabase_tag () function returns an array of tags (symbols)
1516 that identify the data in $MDB. The length of the array is
1517 four. */
1518
1519 /***ja
1520 @brief �ǡ����Υ���������.
1521
1522 �ؿ� mdatabase_tag () �ϡ��ǡ��� $MDB �Υ����ʥ���ܥ�ˤ�������֤��������Ĺ����
1523 4 �Ǥ��롣
1524
1525 @latexonly \IPAlabel{mdatabase_tag} @endlatexonly */
1526
1527 MSymbol *
mdatabase_tag(MDatabase * mdb)1528 mdatabase_tag (MDatabase *mdb)
1529 {
1530 return mdb->tag;
1531 }
1532
1533 /*** @} */
1534
1535 /*
1536 Local Variables:
1537 coding: euc-japan
1538 End:
1539 */
1540