Blame src/database.c

Packit Service a721b1
/* database.c -- database module.
Packit Service a721b1
   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Packit Service a721b1
     National Institute of Advanced Industrial Science and Technology (AIST)
Packit Service a721b1
     Registration Number H15PRO112
Packit Service a721b1
Packit Service a721b1
   This file is part of the m17n library.
Packit Service a721b1
Packit Service a721b1
   The m17n library is free software; you can redistribute it and/or
Packit Service a721b1
   modify it under the terms of the GNU Lesser General Public License
Packit Service a721b1
   as published by the Free Software Foundation; either version 2.1 of
Packit Service a721b1
   the License, or (at your option) any later version.
Packit Service a721b1
Packit Service a721b1
   The m17n library is distributed in the hope that it will be useful,
Packit Service a721b1
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a721b1
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service a721b1
   Lesser General Public License for more details.
Packit Service a721b1
Packit Service a721b1
   You should have received a copy of the GNU Lesser General Public
Packit Service a721b1
   License along with the m17n library; if not, write to the Free
Packit Service a721b1
   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit Service a721b1
   Boston, MA 02110-1301 USA.  */
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @addtogroup m17nDatabase
Packit Service a721b1
    @brief The m17n database and API for it.
Packit Service a721b1
Packit Service a721b1
    The m17n library acquires various kinds of information
Packit Service a721b1
    from data in the  m17n database on demand.  Application
Packit Service a721b1
    programs can also add/load their original data to/from the m17n
Packit Service a721b1
    database by setting the variable #mdatabase_dir to an
Packit Service a721b1
    application-specific directory and storing data in it.  Users can
Packit Service a721b1
    overwrite those data by storing preferable data in the directory
Packit Service a721b1
    specified by the environment variable "M17NDIR", or if it is not
Packit Service a721b1
    set, in the directory "~/.m17n.d".
Packit Service a721b1
Packit Service a721b1
    The m17n database contains multiple heterogeneous data, and each
Packit Service a721b1
    data is identified by four tags; TAG0, TAG1, TAG2, TAG3.  Each tag
Packit Service a721b1
    must be a symbol.
Packit Service a721b1
Packit Service a721b1
    TAG0 specifies the type of data stored in the database as below.
Packit Service a721b1
Packit Service a721b1
    @li
Packit Service a721b1
    If TAG0 is #Mchar_table, the data is of the @e chartable @e
Packit Service a721b1
    type and provides information about each character.  In this case,
Packit Service a721b1
    TAG1 specifies the type of the information and must be #Msymbol,
Packit Service a721b1
    #Minteger, #Mstring, #Mtext, or #Mplist.  TAG2 and TAG3 can be any
Packit Service a721b1
    symbols.
Packit Service a721b1
Packit Service a721b1
    @li
Packit Service a721b1
    If TAG0 is #Mcharset, the data is of the @e charset @e type
Packit Service a721b1
    and provides a decode/encode mapping table for a charset.  In this
Packit Service a721b1
    case, TAG1 must be a symbol representing a charset.  TAG2 and TAG3
Packit Service a721b1
    can be any symbols.
Packit Service a721b1
Packit Service a721b1
    @li 
Packit Service a721b1
    If TAG0 is neither #Mchar_table nor #Mcharset, the data is of
Packit Service a721b1
    the @e plist @e type.  See the documentation of the 
Packit Service a721b1
    mdatabase_load () function for the details.  
Packit Service a721b1
    In this case, TAG1, TAG2, and TAG3 can be any symbols.
Packit Service a721b1
Packit Service a721b1
    The notation \<TAG0, TAG1, TAG2, TAG3\> means a data with those
Packit Service a721b1
    tags.
Packit Service a721b1
Packit Service a721b1
    Application programs first calls the mdatabase_find () function to
Packit Service a721b1
    get a pointer to an object of the type #MDatabase.  That object
Packit Service a721b1
    holds information about the specified data.  When it is
Packit Service a721b1
    successfully returned, the mdatabase_load () function loads the
Packit Service a721b1
    data.  The implementation of the structure #MDatabase is
Packit Service a721b1
    concealed from application programs.
Packit Service a721b1
*/
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @addtogroup m17nDatabase
Packit Service a721b1
    @brief m17n データベースにとそれに関する API.
Packit Service a721b1
Packit Service a721b1
    m17n ライブラリは必要に応じて動的に @e m17n @e データベース 
Packit Service a721b1
    から情報を取得する。またアプリケーションプログラムも、独自のデータを 
Packit Service a721b1
    m17n データベースに追加し、それを動的に取得することができる。
Packit Service a721b1
    アプリケーションプログラムが独自のデータを追加・取得するには、変数 
Packit Service a721b1
    #mdatabase_dir にそのアプリケーション固有のディレクトリをセットし、
Packit Service a721b1
    その中にデータを格納する。ユーザがそのデータをオーバーライトしたい
Packit Service a721b1
    ときは、環境変数 "M17NDIR" で指定されるディレクトリ(指定されていな
Packit Service a721b1
    いときは "~/.m17n.d" というディレクトリ)に別のデータを置く。
Packit Service a721b1
Packit Service a721b1
    m17n 
Packit Service a721b1
    データベースには複数の多様なデータが含まれており、各データは
Packit Service a721b1
    TAG0, TAG1, TAG2, TAG3(すべてシンボル)の4つのタグによって識別される。
Packit Service a721b1
Packit Service a721b1
    TAG0 によって、データベース内のデータのタイプは次のように指定される。
Packit Service a721b1
Packit Service a721b1
    @li 
Packit Service a721b1
    TAG0 が #Mchar_table であるデータは @e chartableタイプ 
Packit Service a721b1
    と呼ばれ、各文字に関する情報を提供する。この場合
Packit Service a721b1
    TAG1 は情報の種類を指定するシンボルであり、#Msymbol, #Minteger, #Mstring,
Packit Service a721b1
    #Mtext, #Mplist のいずれかである。TAG2 と TAG3 は任意のシンボルでよい。
Packit Service a721b1
Packit Service a721b1
    @li 
Packit Service a721b1
    TAG0 が #Mcharset であるデータは @e charsetタイプ 
Packit Service a721b1
    と呼ばれ、文字セット用のデコード/エンコードマップを提供する。この場合 TAG1
Packit Service a721b1
    は文字セットのシンボルでなければならない。TAG2 と TAG3
Packit Service a721b1
    は任意のシンボルでよい。
Packit Service a721b1
Packit Service a721b1
    @li
Packit Service a721b1
    TAG0 が #Mchar_table でも #Mcharset でもない場合、そのデータは @e
Packit Service a721b1
    plistタイプ である。詳細に関しては関数 mdatabase_load () 
Packit Service a721b1
    の説明を参照のこと。この場合 TAG1、TAG2、TAG3 は任意のシンボルでよい。
Packit Service a721b1
Packit Service a721b1
    特定のタグを持つデータベースを \<TAG0, TAG1, TAG2, TAG3\> 
Packit Service a721b1
    という形式で表す。
Packit Service a721b1
Packit Service a721b1
    アプリケーションプログラムは、まず関数 mdatabase_find () 
Packit Service a721b1
    を使ってデータベースに関する情報を保持するオブジェクト(#MDatabase
Packit Service a721b1
    型)へのポインタを得る。それに成功したら、 mdatabase_load () 
Packit Service a721b1
    によって実際にデータベースをロードする。構造体 #MDatabase 
Packit Service a721b1
    自身がどう実装されているかは、アプリケーションプログラムからは見えない。
Packit Service a721b1
Packit Service a721b1
    @latexonly \IPAlabel{database} @endlatexonly
Packit Service a721b1
*/
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
#if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
Packit Service a721b1
/*** @addtogroup m17nInternal
Packit Service a721b1
     @{ */
Packit Service a721b1
Packit Service a721b1
#include <config.h>
Packit Service a721b1
#include <stdio.h>
Packit Service a721b1
#include <stdlib.h>
Packit Service a721b1
#include <string.h>
Packit Service a721b1
#include <ctype.h>
Packit Service a721b1
#include <sys/types.h>
Packit Service a721b1
#include <sys/stat.h>
Packit Service a721b1
#include <unistd.h>
Packit Service a721b1
#include <limits.h>
Packit Service a721b1
#include <glob.h>
Packit Service a721b1
#include <time.h>
Packit Service a721b1
#include <libgen.h>
Packit Service a721b1
Packit Service a721b1
#include "m17n-core.h"
Packit Service a721b1
#include "m17n-misc.h"
Packit Service a721b1
#include "internal.h"
Packit Service a721b1
#include "mtext.h"
Packit Service a721b1
#include "character.h"
Packit Service a721b1
#include "database.h"
Packit Service a721b1
#include "plist.h"
Packit Service a721b1
Packit Service a721b1
/** The file containing a list of databases.  */
Packit Service a721b1
#define MDB_DIR "mdb.dir"
Packit Service a721b1
/** Length of MDB_DIR.  */
Packit Service a721b1
#define MDB_DIR_LEN 7
Packit Service a721b1
Packit Service a721b1
#define MAX_TIME(TIME1, TIME2) ((TIME1) >= (TIME2) ? (TIME1) : (TIME2))
Packit Service a721b1
Packit Service a721b1
#define GEN_PATH(path, dir, dir_len, file, file_len)	\
Packit Service a721b1
  (dir_len + file_len > PATH_MAX ? 0			\
Packit Service a721b1
   : (memcpy (path, dir, dir_len),			\
Packit Service a721b1
      memcpy (path + dir_len, file, file_len),		\
Packit Service a721b1
      path[dir_len + file_len] = '\0', 1))
Packit Service a721b1
Packit Service a721b1
static MSymbol Masterisk;
Packit Service a721b1
static MSymbol Mversion;
Packit Service a721b1
Packit Service a721b1
/** Structure for a data in the m17n database.  */
Packit Service a721b1
Packit Service a721b1
struct MDatabase
Packit Service a721b1
{
Packit Service a721b1
  /** Tags to identify the data.  <tag>[0] specifies the type of
Packit Service a721b1
      database.  If it is #Mchar_table, the type is @e chartable, if
Packit Service a721b1
      it is #Mcharset, the type is @e charset, otherwise the type is
Packit Service a721b1
      @e plist.  */
Packit Service a721b1
  MSymbol tag[4];
Packit Service a721b1
Packit Service a721b1
  void *(*loader) (MSymbol *tags, void *extra_info);
Packit Service a721b1
Packit Service a721b1
  /** The meaning of the value is dependent on <loader>.  If <loader>
Packit Service a721b1
      is load_database (), the value is a string of the file name that
Packit Service a721b1
      contains the data.  */
Packit Service a721b1
  void *extra_info;
Packit Service a721b1
};
Packit Service a721b1
Packit Service a721b1
static MPlist *mdatabase__list;
Packit Service a721b1
Packit Service a721b1
static int
Packit Service a721b1
read_number (char *buf, int *i)
Packit Service a721b1
{
Packit Service a721b1
  int idx = *i;
Packit Service a721b1
  int c = buf[idx++];
Packit Service a721b1
  int n;
Packit Service a721b1
Packit Service a721b1
  if (!c)
Packit Service a721b1
    return -1;
Packit Service a721b1
Packit Service a721b1
  while (c && isspace (c)) c = buf[idx++];
Packit Service a721b1
Packit Service a721b1
  if (c == '0')
Packit Service a721b1
    {
Packit Service a721b1
      if (buf[idx] == 'x')
Packit Service a721b1
	{
Packit Service a721b1
	  for (idx++, c = 0; (n = hex_mnemonic[(unsigned) buf[idx]]) < 16;
Packit Service a721b1
	       idx++)
Packit Service a721b1
	    c  = (c << 4) | n;
Packit Service a721b1
	  *i = idx;
Packit Service a721b1
	  return c;
Packit Service a721b1
	}
Packit Service a721b1
      c = 0;
Packit Service a721b1
    }
Packit Service a721b1
  else if (c == '\'')
Packit Service a721b1
    {
Packit Service a721b1
      c = buf[idx++];
Packit Service a721b1
      if (c == '\\')
Packit Service a721b1
	{
Packit Service a721b1
	  c = buf[idx++];
Packit Service a721b1
	  n = escape_mnemonic[c];
Packit Service a721b1
	  if (n != 255)
Packit Service a721b1
	    c = n;
Packit Service a721b1
	}
Packit Service a721b1
      while (buf[idx] && buf[idx++] != '\'');
Packit Service a721b1
      *i = idx;
Packit Service a721b1
      return c;
Packit Service a721b1
    }
Packit Service a721b1
  else if (hex_mnemonic[c] < 10)
Packit Service a721b1
    c -= '0';
Packit Service a721b1
  else
Packit Service a721b1
    return -1;
Packit Service a721b1
Packit Service a721b1
  while ((n = hex_mnemonic[(unsigned) buf[idx]]) < 10)
Packit Service a721b1
    c = (c * 10) + n, idx++;
Packit Service a721b1
  *i = idx;
Packit Service a721b1
  return c;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/** Load a data of type @c chartable from the file FD, and return the
Packit Service a721b1
    newly created chartable.  */
Packit Service a721b1
Packit Service a721b1
static void *
Packit Service a721b1
load_chartable (FILE *fp, MSymbol type)
Packit Service a721b1
{
Packit Service a721b1
  int c, from, to;
Packit Service a721b1
  char buf[1024];
Packit Service a721b1
  void *val;
Packit Service a721b1
  MCharTable *table;
Packit Service a721b1
Packit Service a721b1
  if (! fp)
Packit Service a721b1
    MERROR (MERROR_DB, NULL);
Packit Service a721b1
Packit Service a721b1
  table = mchartable (type, (type == Msymbol ? (void *) Mnil
Packit Service a721b1
			     : type == Minteger ? (void *) -1
Packit Service a721b1
			     : NULL));
Packit Service a721b1
Packit Service a721b1
  while (! feof (fp))
Packit Service a721b1
    {
Packit Service a721b1
      int i, len;
Packit Service a721b1
Packit Service a721b1
      for (len = 0; len < 1023 && (c = getc (fp)) != EOF && c != '\n'; len++)
Packit Service a721b1
	buf[len] = c;
Packit Service a721b1
      buf[len] = '\0';	  
Packit Service a721b1
      if (hex_mnemonic[(unsigned) buf[0]] >= 10)
Packit Service a721b1
	/* skip comment/invalid line */
Packit Service a721b1
	continue;
Packit Service a721b1
      i = 0;
Packit Service a721b1
      from = read_number (buf, &i);
Packit Service a721b1
      if (buf[i] == '-')
Packit Service a721b1
	i++, to = read_number (buf, &i);
Packit Service a721b1
      else
Packit Service a721b1
	to = from;
Packit Service a721b1
      if (from < 0 || to < from)
Packit Service a721b1
	continue;
Packit Service a721b1
Packit Service a721b1
      while (buf[i] && isspace ((unsigned) buf[i])) i++;
Packit Service a721b1
      c = buf[i];
Packit Service a721b1
      if (!c)
Packit Service a721b1
	continue;
Packit Service a721b1
Packit Service a721b1
      if (type == Mstring)
Packit Service a721b1
	{
Packit Service a721b1
	  /* VAL is a C-string.  */
Packit Service a721b1
	  if (! (val = strdup (buf + i)))
Packit Service a721b1
	    MEMORY_FULL (MERROR_DB);
Packit Service a721b1
	}
Packit Service a721b1
      else if (type == Minteger)
Packit Service a721b1
	{
Packit Service a721b1
	  /* VAL is an integer.  */
Packit Service a721b1
	  int positive = 1;
Packit Service a721b1
	  int n;
Packit Service a721b1
Packit Service a721b1
	  if (c == '-')
Packit Service a721b1
	    i++, positive = -1;
Packit Service a721b1
	  n = read_number (buf, &i);
Packit Service a721b1
	  if (n < 0)
Packit Service a721b1
	    goto label_error;
Packit Service a721b1
	  val = (void *) (n * positive);
Packit Service a721b1
	}
Packit Service a721b1
      else if (type == Mtext)
Packit Service a721b1
	{
Packit Service a721b1
	  /* VAL is an M-text.  */
Packit Service a721b1
	  MText *mt;
Packit Service a721b1
	  if (c == '"')
Packit Service a721b1
	    mt = mtext__from_data (buf + i, len - i - 1, MTEXT_FORMAT_UTF_8, 1);
Packit Service a721b1
	  else
Packit Service a721b1
	    {
Packit Service a721b1
	      mt = mtext ();
Packit Service a721b1
	      while ((c = read_number (buf, &i)) >= 0)
Packit Service a721b1
		mt = mtext_cat_char (mt, c);
Packit Service a721b1
	    }
Packit Service a721b1
	  val = (void *) mt;
Packit Service a721b1
	}
Packit Service a721b1
      else if (type == Msymbol)
Packit Service a721b1
	{
Packit Service a721b1
	  char *p = buf + i;
Packit Service a721b1
Packit Service a721b1
	  while (*p && ! isspace (*p)) 
Packit Service a721b1
	    {
Packit Service a721b1
	      if (*p == '\\' && p[1] != '\0')
Packit Service a721b1
		{
Packit Service a721b1
		  memmove (p, p + 1, buf + len - (p + 1));
Packit Service a721b1
		  len--;
Packit Service a721b1
		}
Packit Service a721b1
	      p++;
Packit Service a721b1
	    }
Packit Service a721b1
	  *p = '\0';
Packit Service a721b1
	  if (! strcmp (buf + i, "nil"))
Packit Service a721b1
	    val = (void *) Mnil;
Packit Service a721b1
	  else
Packit Service a721b1
	    val = (void *) msymbol (buf + i);
Packit Service a721b1
	}
Packit Service a721b1
      else if (type == Mplist)
Packit Service a721b1
	{
Packit Service a721b1
	  val = (void *) mplist__from_string ((unsigned char *) buf + i,
Packit Service a721b1
					      strlen (buf + i));
Packit Service a721b1
	}
Packit Service a721b1
      else
Packit Service a721b1
	val = NULL;
Packit Service a721b1
Packit Service a721b1
      if (from == to)
Packit Service a721b1
	mchartable_set (table, from, val);
Packit Service a721b1
      else
Packit Service a721b1
	mchartable_set_range (table, from, to, val);
Packit Service a721b1
    }
Packit Service a721b1
  return table;
Packit Service a721b1
Packit Service a721b1
 label_error:
Packit Service a721b1
  M17N_OBJECT_UNREF (table);
Packit Service a721b1
  MERROR (MERROR_DB, NULL);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
static char *
Packit Service a721b1
gen_database_name (char *buf, MSymbol *tags)
Packit Service a721b1
{
Packit Service a721b1
  int i;
Packit Service a721b1
Packit Service a721b1
  strcpy (buf, msymbol_name (tags[0]));
Packit Service a721b1
  for (i = 1; i < 4; i++)
Packit Service a721b1
    {
Packit Service a721b1
      strcat (buf, ",");
Packit Service a721b1
      strcat (buf, msymbol_name (tags[i]));
Packit Service a721b1
    }
Packit Service a721b1
  return buf;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/* Return the absolute file name for DB_INFO->filename or NULL if no
Packit Service a721b1
   absolute file name was found.  If BUF is non-NULL, store the result
Packit Service a721b1
   of `stat' call in it.  In that case, set *RESULT to the return
Packit Service a721b1
   value of `stat'.  */
Packit Service a721b1
Packit Service a721b1
char *
Packit Service a721b1
get_database_file (MDatabaseInfo *db_info, struct stat *buf, int *result)
Packit Service a721b1
{
Packit Service a721b1
  if (db_info->absolute_filename)
Packit Service a721b1
    {
Packit Service a721b1
      if (buf)
Packit Service a721b1
	*result = stat (db_info->absolute_filename, buf);
Packit Service a721b1
    }
Packit Service a721b1
  else
Packit Service a721b1
    {
Packit Service a721b1
      struct stat stat_buf;
Packit Service a721b1
      struct stat *statbuf = buf ? buf : &stat_buf;
Packit Service a721b1
      int res;
Packit Service a721b1
      MPlist *plist;
Packit Service a721b1
      char path[PATH_MAX + 1];
Packit Service a721b1
Packit Service a721b1
      MPLIST_DO (plist, mdatabase__dir_list)
Packit Service a721b1
	{
Packit Service a721b1
	  MDatabaseInfo *dir_info = MPLIST_VAL (plist);
Packit Service a721b1
Packit Service a721b1
	  if (dir_info->status != MDB_STATUS_DISABLED
Packit Service a721b1
	      && GEN_PATH (path, dir_info->filename, dir_info->len,
Packit Service a721b1
			   db_info->filename, db_info->len)
Packit Service a721b1
	      && (res = stat (path, statbuf)) == 0)
Packit Service a721b1
	    {
Packit Service a721b1
	      db_info->absolute_filename = strdup (path);
Packit Service a721b1
	      if (result)
Packit Service a721b1
		*result = res;
Packit Service a721b1
	      break;
Packit Service a721b1
	    }
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  return db_info->absolute_filename;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static void *
Packit Service a721b1
load_database (MSymbol *tags, void *extra_info)
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *db_info = extra_info;
Packit Service a721b1
  void *value;
Packit Service a721b1
  char *filename = get_database_file (db_info, NULL, NULL);
Packit Service a721b1
  FILE *fp;
Packit Service a721b1
  int mdebug_flag = MDEBUG_DATABASE;
Packit Service a721b1
  char buf[256];
Packit Service a721b1
Packit Service a721b1
  MDEBUG_PRINT1 (" [DB] <%s>", gen_database_name (buf, tags));
Packit Service a721b1
  if (! filename || ! (fp = fopen (filename, "r")))
Packit Service a721b1
    {
Packit Service a721b1
      if (filename)
Packit Service a721b1
	MDEBUG_PRINT1 (" open fail: %s\n", filename);
Packit Service a721b1
      else
Packit Service a721b1
	MDEBUG_PRINT1 (" not found: %s\n", db_info->filename);
Packit Service a721b1
      MERROR (MERROR_DB, NULL);
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  MDEBUG_PRINT1 (" from %s\n", filename);
Packit Service a721b1
Packit Service a721b1
  if (tags[0] == Mchar_table)
Packit Service a721b1
    value = load_chartable (fp, tags[1]);
Packit Service a721b1
  else if (tags[0] == Mcharset)
Packit Service a721b1
    {
Packit Service a721b1
      if (! mdatabase__load_charset_func)
Packit Service a721b1
	MERROR (MERROR_DB, NULL);
Packit Service a721b1
      value = (*mdatabase__load_charset_func) (fp, tags[1]);
Packit Service a721b1
    }
Packit Service a721b1
  else
Packit Service a721b1
    value = mplist__from_file (fp, NULL);
Packit Service a721b1
  fclose (fp);
Packit Service a721b1
Packit Service a721b1
  if (! value)
Packit Service a721b1
    MERROR (MERROR_DB, NULL);
Packit Service a721b1
  db_info->time = time (NULL);
Packit Service a721b1
  return value;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/** Return a newly allocated MDatabaseInfo for DIRNAME.  */
Packit Service a721b1
Packit Service a721b1
static MDatabaseInfo *
Packit Service a721b1
get_dir_info (char *dirname)
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *dir_info;
Packit Service a721b1
Packit Service a721b1
  MSTRUCT_CALLOC (dir_info, MERROR_DB);
Packit Service a721b1
  if (dirname)
Packit Service a721b1
    {
Packit Service a721b1
      int len = strlen (dirname);
Packit Service a721b1
Packit Service a721b1
      if (len + MDB_DIR_LEN < PATH_MAX)
Packit Service a721b1
	{
Packit Service a721b1
	  MTABLE_MALLOC (dir_info->filename, len + 2, MERROR_DB);
Packit Service a721b1
	  memcpy (dir_info->filename, dirname, len + 1);
Packit Service a721b1
	  /* Append PATH_SEPARATOR if DIRNAME doesn't end with it.  */
Packit Service a721b1
	  if (dir_info->filename[len - 1] != PATH_SEPARATOR)
Packit Service a721b1
	    {
Packit Service a721b1
	      dir_info->filename[len] = PATH_SEPARATOR;
Packit Service a721b1
	      dir_info->filename[++len] = '\0';
Packit Service a721b1
	    }
Packit Service a721b1
	  dir_info->len = len;
Packit Service a721b1
	  dir_info->status = MDB_STATUS_OUTDATED;
Packit Service a721b1
	}
Packit Service a721b1
      else
Packit Service a721b1
	dir_info->status = MDB_STATUS_DISABLED;	
Packit Service a721b1
    }
Packit Service a721b1
  else
Packit Service a721b1
    dir_info->status = MDB_STATUS_DISABLED;
Packit Service a721b1
  return dir_info;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static void register_databases_in_files (MSymbol tags[4],
Packit Service a721b1
					 char *filename, int len);
Packit Service a721b1
Packit Service a721b1
static MDatabase *
Packit Service a721b1
find_database (MSymbol tags[4])
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist;
Packit Service a721b1
  int i;
Packit Service a721b1
  MDatabase *mdb;
Packit Service a721b1
  
Packit Service a721b1
  if (! mdatabase__list)
Packit Service a721b1
    return NULL;
Packit Service a721b1
  for (i = 0, plist = mdatabase__list; i < 4; i++)
Packit Service a721b1
    {
Packit Service a721b1
      MPlist *pl = mplist__assq (plist, tags[i]);
Packit Service a721b1
      MPlist *p;
Packit Service a721b1
Packit Service a721b1
      if ((p = mplist__assq (plist, Masterisk)))
Packit Service a721b1
	{
Packit Service a721b1
	  MDatabaseInfo *db_info;
Packit Service a721b1
	  int j;
Packit Service a721b1
Packit Service a721b1
	  p = MPLIST_PLIST (p);
Packit Service a721b1
	  for (j = i + 1; j < 4; j++)
Packit Service a721b1
	    p = MPLIST_PLIST (MPLIST_NEXT (p));
Packit Service a721b1
	  mdb = MPLIST_VAL (MPLIST_NEXT (p));
Packit Service a721b1
	  db_info = mdb->extra_info;
Packit Service a721b1
	  if (db_info->status != MDB_STATUS_DISABLED)
Packit Service a721b1
	    {
Packit Service a721b1
	      register_databases_in_files (mdb->tag,
Packit Service a721b1
					   db_info->filename, db_info->len);
Packit Service a721b1
	      db_info->status = MDB_STATUS_DISABLED;
Packit Service a721b1
	      return find_database (tags);
Packit Service a721b1
	    }
Packit Service a721b1
	}
Packit Service a721b1
      if (! pl)
Packit Service a721b1
	return NULL;
Packit Service a721b1
      plist = MPLIST_PLIST (pl);
Packit Service a721b1
      plist = MPLIST_NEXT (plist);
Packit Service a721b1
    }
Packit Service a721b1
  mdb = MPLIST_VAL (plist);
Packit Service a721b1
  return mdb;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static void
Packit Service a721b1
free_db_info (MDatabaseInfo *db_info)
Packit Service a721b1
{
Packit Service a721b1
  free (db_info->filename);
Packit Service a721b1
  if (db_info->absolute_filename
Packit Service a721b1
      && db_info->filename != db_info->absolute_filename)
Packit Service a721b1
    free (db_info->absolute_filename);
Packit Service a721b1
  M17N_OBJECT_UNREF (db_info->properties);
Packit Service a721b1
  free (db_info);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static int
Packit Service a721b1
check_version (MText *version)
Packit Service a721b1
{
Packit Service a721b1
  char *verstr = (char *) MTEXT_DATA (version);
Packit Service a721b1
  char *endp = verstr + mtext_nbytes (version);
Packit Service a721b1
  int ver[3];
Packit Service a721b1
  int i;
Packit Service a721b1
Packit Service a721b1
  ver[0] = ver[1] = ver[2] = 0;
Packit Service a721b1
  for (i = 0; verstr < endp; verstr++)
Packit Service a721b1
    {
Packit Service a721b1
      if (*verstr == '.')
Packit Service a721b1
	{
Packit Service a721b1
	  i++;
Packit Service a721b1
	  if (i == 3)
Packit Service a721b1
	    break;
Packit Service a721b1
	  continue;
Packit Service a721b1
	}
Packit Service a721b1
      if (! isdigit (*verstr))
Packit Service a721b1
	break;
Packit Service a721b1
      ver[i] = ver[i] * 10 + (*verstr - '0');
Packit Service a721b1
    }
Packit Service a721b1
  return (ver[0] < M17NLIB_MAJOR_VERSION
Packit Service a721b1
	  || (ver[0] == M17NLIB_MAJOR_VERSION
Packit Service a721b1
	      && (ver[1] < M17NLIB_MINOR_VERSION
Packit Service a721b1
		  || (ver[1] == M17NLIB_MINOR_VERSION
Packit Service a721b1
		      && ver[2] <= M17NLIB_PATCH_LEVEL))));
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static MDatabase *
Packit Service a721b1
register_database (MSymbol tags[4],
Packit Service a721b1
		   void *(*loader) (MSymbol *, void *),
Packit Service a721b1
		   void *extra_info, enum MDatabaseStatus status,
Packit Service a721b1
		   MPlist *properties)
Packit Service a721b1
{
Packit Service a721b1
  MDatabase *mdb;
Packit Service a721b1
  MDatabaseInfo *db_info;
Packit Service a721b1
  int i;
Packit Service a721b1
  MPlist *plist;
Packit Service a721b1
Packit Service a721b1
  if (properties)
Packit Service a721b1
    {
Packit Service a721b1
      MPLIST_DO (plist, properties)
Packit Service a721b1
	if (MPLIST_PLIST_P (plist))
Packit Service a721b1
	  {
Packit Service a721b1
	    MPlist *p = MPLIST_PLIST (plist);
Packit Service a721b1
Packit Service a721b1
	    if (MPLIST_SYMBOL_P (p)
Packit Service a721b1
		&& MPLIST_SYMBOL (p) == Mversion
Packit Service a721b1
		&& MPLIST_MTEXT_P (MPLIST_NEXT (p)))
Packit Service a721b1
	      {
Packit Service a721b1
		if (check_version (MPLIST_MTEXT (MPLIST_NEXT (p))))
Packit Service a721b1
		  break;
Packit Service a721b1
		return NULL;
Packit Service a721b1
	      }
Packit Service a721b1
	  }
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  for (i = 0, plist = mdatabase__list; i < 4; i++)
Packit Service a721b1
    {
Packit Service a721b1
      MPlist *pl = mplist__assq (plist, tags[i]);
Packit Service a721b1
Packit Service a721b1
      if (pl)
Packit Service a721b1
	pl = MPLIST_PLIST (pl);
Packit Service a721b1
      else
Packit Service a721b1
	{
Packit Service a721b1
	  pl = mplist ();
Packit Service a721b1
	  mplist_add (pl, Msymbol, tags[i]);
Packit Service a721b1
	  mplist_push (plist, Mplist, pl);
Packit Service a721b1
	  M17N_OBJECT_UNREF (pl);
Packit Service a721b1
	}
Packit Service a721b1
      plist = MPLIST_NEXT (pl);
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (MPLIST_TAIL_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      MSTRUCT_MALLOC (mdb, MERROR_DB);
Packit Service a721b1
      for (i = 0; i < 4; i++)
Packit Service a721b1
	mdb->tag[i] = tags[i];
Packit Service a721b1
      mdb->loader = loader;
Packit Service a721b1
      if (loader == load_database)
Packit Service a721b1
	{
Packit Service a721b1
	  MSTRUCT_CALLOC (db_info, MERROR_DB);
Packit Service a721b1
	  mdb->extra_info = db_info;
Packit Service a721b1
	}
Packit Service a721b1
      else
Packit Service a721b1
	{
Packit Service a721b1
	  db_info = NULL;
Packit Service a721b1
	  mdb->extra_info = extra_info;
Packit Service a721b1
	}
Packit Service a721b1
      mplist_push (plist, Mt, mdb);
Packit Service a721b1
    }
Packit Service a721b1
  else
Packit Service a721b1
    {
Packit Service a721b1
      mdb = MPLIST_VAL (plist);
Packit Service a721b1
      if (loader == load_database)
Packit Service a721b1
	db_info = mdb->extra_info;
Packit Service a721b1
      else
Packit Service a721b1
	db_info = NULL;
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (db_info)
Packit Service a721b1
    {
Packit Service a721b1
      db_info->status = status;
Packit Service a721b1
      if (! db_info->filename
Packit Service a721b1
	  || strcmp (db_info->filename, (char *) extra_info) != 0)
Packit Service a721b1
	{
Packit Service a721b1
	  if (db_info->filename)
Packit Service a721b1
	    free (db_info->filename);
Packit Service a721b1
	  if (db_info->absolute_filename
Packit Service a721b1
	      && db_info->filename != db_info->absolute_filename)
Packit Service a721b1
	    free (db_info->absolute_filename);
Packit Service a721b1
	  db_info->filename = strdup ((char *) extra_info);
Packit Service a721b1
	  db_info->len = strlen ((char *) extra_info);
Packit Service a721b1
	  db_info->time = 0;
Packit Service a721b1
	}
Packit Service a721b1
      if (db_info->filename[0] == PATH_SEPARATOR)
Packit Service a721b1
	db_info->absolute_filename = db_info->filename;
Packit Service a721b1
      else
Packit Service a721b1
	db_info->absolute_filename = NULL;
Packit Service a721b1
      M17N_OBJECT_UNREF (db_info->properties);
Packit Service a721b1
      if (properties)
Packit Service a721b1
	{
Packit Service a721b1
	  db_info->properties = properties;
Packit Service a721b1
	  M17N_OBJECT_REF (properties);
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (mdb->tag[0] == Mchar_table
Packit Service a721b1
      && mdb->tag[2] != Mnil
Packit Service a721b1
      && (mdb->tag[1] == Mstring || mdb->tag[1] == Mtext
Packit Service a721b1
	  || mdb->tag[1] == Msymbol || mdb->tag[1] == Minteger
Packit Service a721b1
	  || mdb->tag[1] == Mplist))
Packit Service a721b1
    mchar__define_prop (mdb->tag[2], mdb->tag[1], mdb);
Packit Service a721b1
  return mdb;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static void
Packit Service a721b1
register_databases_in_files (MSymbol tags[4], char *filename, int len)
Packit Service a721b1
{
Packit Service a721b1
  int i, j;
Packit Service a721b1
  MPlist *load_key = mplist ();
Packit Service a721b1
  FILE *fp;
Packit Service a721b1
  MPlist *plist, *pl;
Packit Service a721b1
Packit Service a721b1
  MPLIST_DO (plist, mdatabase__dir_list)
Packit Service a721b1
    {
Packit Service a721b1
      glob_t globbuf;
Packit Service a721b1
      int headlen;
Packit Service a721b1
Packit Service a721b1
      if (filename[0] == PATH_SEPARATOR)
Packit Service a721b1
	{
Packit Service a721b1
	  if (glob (filename, GLOB_NOSORT, NULL, &globbuf))
Packit Service a721b1
	    break;
Packit Service a721b1
	  headlen = 0;
Packit Service a721b1
	}
Packit Service a721b1
      else
Packit Service a721b1
	{
Packit Service a721b1
	  MDatabaseInfo *d_info = MPLIST_VAL (plist);
Packit Service a721b1
	  char path[PATH_MAX + 1];
Packit Service a721b1
Packit Service a721b1
	  if (d_info->status == MDB_STATUS_DISABLED)
Packit Service a721b1
	    continue;
Packit Service a721b1
	  if (! GEN_PATH (path, d_info->filename, d_info->len, filename, len))
Packit Service a721b1
	    continue;
Packit Service a721b1
	  if (glob (path, GLOB_NOSORT, NULL, &globbuf))
Packit Service a721b1
	    continue;
Packit Service a721b1
	  headlen = d_info->len;
Packit Service a721b1
	}
Packit Service a721b1
Packit Service a721b1
      for (i = 0; i < globbuf.gl_pathc; i++)
Packit Service a721b1
	{
Packit Service a721b1
	  if (! (fp = fopen (globbuf.gl_pathv[i], "r")))
Packit Service a721b1
	    continue;
Packit Service a721b1
	  pl = mplist__from_file (fp, load_key);
Packit Service a721b1
	  fclose (fp);
Packit Service a721b1
	  if (! pl)
Packit Service a721b1
	    continue;
Packit Service a721b1
	  if (MPLIST_PLIST_P (pl))
Packit Service a721b1
	    {
Packit Service a721b1
	      MPlist *p;
Packit Service a721b1
	      MSymbol tags2[4];
Packit Service a721b1
Packit Service a721b1
	      for (j = 0, p = MPLIST_PLIST (pl); j < 4 && MPLIST_SYMBOL_P (p);
Packit Service a721b1
		   j++, p = MPLIST_NEXT (p))
Packit Service a721b1
		tags2[j] = MPLIST_SYMBOL (p);
Packit Service a721b1
	      for (; j < 4; j++)
Packit Service a721b1
		tags2[j] = Mnil;
Packit Service a721b1
	      for (j = 0; j < 4; j++)
Packit Service a721b1
		if (tags[j] != Masterisk && tags[j] != tags2[j])
Packit Service a721b1
		  break;
Packit Service a721b1
	      if (j == 4)
Packit Service a721b1
		register_database (tags2, load_database,
Packit Service a721b1
				   globbuf.gl_pathv[i] + headlen,
Packit Service a721b1
				   MDB_STATUS_AUTO, p);
Packit Service a721b1
	    }
Packit Service a721b1
	  M17N_OBJECT_UNREF (pl);
Packit Service a721b1
	}
Packit Service a721b1
      globfree (&globbuf);
Packit Service a721b1
      if (filename[0] == PATH_SEPARATOR)
Packit Service a721b1
	break;
Packit Service a721b1
    }
Packit Service a721b1
  M17N_OBJECT_UNREF (load_key);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static int
Packit Service a721b1
expand_wildcard_database (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  MDatabase *mdb;
Packit Service a721b1
  MDatabaseInfo *db_info;
Packit Service a721b1
Packit Service a721b1
  plist = MPLIST_NEXT (plist);
Packit Service a721b1
  while (MPLIST_PLIST_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      plist = MPLIST_PLIST (plist);
Packit Service a721b1
      plist = MPLIST_NEXT (plist);
Packit Service a721b1
    }
Packit Service a721b1
  mdb = MPLIST_VAL (plist);
Packit Service a721b1
  if (mdb->loader == load_database
Packit Service a721b1
      && (db_info = mdb->extra_info)
Packit Service a721b1
      && db_info->status != MDB_STATUS_DISABLED)
Packit Service a721b1
    {
Packit Service a721b1
      register_databases_in_files (mdb->tag, db_info->filename, db_info->len);
Packit Service a721b1
      db_info->status = MDB_STATUS_DISABLED;
Packit Service a721b1
      return 1;
Packit Service a721b1
    }
Packit Service a721b1
  return 0;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1

Packit Service a721b1
/* Internal API */
Packit Service a721b1
Packit Service a721b1
/** List of database directories.  */ 
Packit Service a721b1
MPlist *mdatabase__dir_list;
Packit Service a721b1
Packit Service a721b1
void *(*mdatabase__load_charset_func) (FILE *fp, MSymbol charset_name);
Packit Service a721b1
Packit Service a721b1
int
Packit Service a721b1
mdatabase__init ()
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *dir_info;
Packit Service a721b1
  char *path;
Packit Service a721b1
Packit Service a721b1
  mdatabase__load_charset_func = NULL;
Packit Service a721b1
Packit Service a721b1
  Mchar_table = msymbol ("char-table");
Packit Service a721b1
  Mcharset = msymbol ("charset");
Packit Service a721b1
  Masterisk = msymbol ("*");
Packit Service a721b1
  Mversion = msymbol ("version");
Packit Service a721b1
Packit Service a721b1
  mdatabase__dir_list = mplist ();
Packit Service a721b1
  /** The macro M17NDIR specifies a directory where the system-wide
Packit Service a721b1
    MDB_DIR file exists.  */
Packit Service a721b1
  mplist_set (mdatabase__dir_list, Mt, get_dir_info (M17NDIR));
Packit Service a721b1
Packit Service a721b1
  /* The variable mdatabase_dir specifies a directory where an
Packit Service a721b1
     application program specific MDB_DIR file exists.  */
Packit Service a721b1
  if (mdatabase_dir && strlen (mdatabase_dir) > 0)
Packit Service a721b1
    mplist_push (mdatabase__dir_list, Mt, get_dir_info (mdatabase_dir));
Packit Service a721b1
Packit Service a721b1
  /* The environment variable M17NDIR specifies a directory where a
Packit Service a721b1
     user specific MDB_DIR file exists.  */
Packit Service a721b1
  path = getenv ("M17NDIR");
Packit Service a721b1
  if (path && strlen (path) > 0)
Packit Service a721b1
    mplist_push (mdatabase__dir_list, Mt, get_dir_info (path));
Packit Service a721b1
  else
Packit Service a721b1
    {
Packit Service a721b1
      /* If the env var M17NDIR is not set, check "~/.m17n.d".  */
Packit Service a721b1
      char *home = getenv ("HOME");
Packit Service a721b1
      int len;
Packit Service a721b1
Packit Service a721b1
      if (home
Packit Service a721b1
	  && (len = strlen (home))
Packit Service a721b1
	  && (path = alloca (len + 9)))
Packit Service a721b1
	{
Packit Service a721b1
	  strcpy (path, home);
Packit Service a721b1
	  if (path[len - 1] != PATH_SEPARATOR)
Packit Service a721b1
	    path[len++] = PATH_SEPARATOR;
Packit Service a721b1
	  strcpy (path + len, ".m17n.d");
Packit Service a721b1
	  dir_info = get_dir_info (path);
Packit Service a721b1
	  mplist_push (mdatabase__dir_list, Mt, dir_info);
Packit Service a721b1
	}
Packit Service a721b1
      else
Packit Service a721b1
	mplist_push (mdatabase__dir_list, Mt, get_dir_info (NULL));
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  mdatabase__list = mplist ();
Packit Service a721b1
  mdatabase__update ();
Packit Service a721b1
  return 0;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
void
Packit Service a721b1
mdatabase__fini (void)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist, *p0, *p1, *p2, *p3;
Packit Service a721b1
Packit Service a721b1
  MPLIST_DO (plist, mdatabase__dir_list)
Packit Service a721b1
    free_db_info (MPLIST_VAL (plist));
Packit Service a721b1
  M17N_OBJECT_UNREF (mdatabase__dir_list);
Packit Service a721b1
Packit Service a721b1
  /* MDATABASE_LIST ::= ((TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) ...) */
Packit Service a721b1
  MPLIST_DO (plist, mdatabase__list)
Packit Service a721b1
    {
Packit Service a721b1
      p0 = MPLIST_PLIST (plist);
Packit Service a721b1
      /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) ...) */
Packit Service a721b1
      MPLIST_DO (p0, MPLIST_NEXT (p0))
Packit Service a721b1
	{
Packit Service a721b1
	  p1 = MPLIST_PLIST (p0);
Packit Service a721b1
	  /* P1 ::= (TAG1 (TAG2 (TAG3 t:MDB) ...) ...) */
Packit Service a721b1
	  MPLIST_DO (p1, MPLIST_NEXT (p1))
Packit Service a721b1
	    {
Packit Service a721b1
	      p2 = MPLIST_PLIST (p1);
Packit Service a721b1
	      /* P2 ::= (TAG2 (TAG3 t:MDB) ...) */
Packit Service a721b1
	      MPLIST_DO (p2, MPLIST_NEXT (p2))
Packit Service a721b1
		{
Packit Service a721b1
		  MDatabase *mdb;
Packit Service a721b1
Packit Service a721b1
		  p3 = MPLIST_PLIST (p2); /* P3 ::= (TAG3 t:MDB) */
Packit Service a721b1
		  p3 = MPLIST_NEXT (p3);
Packit Service a721b1
		  mdb = MPLIST_VAL (p3);
Packit Service a721b1
		  if (mdb->loader == load_database)
Packit Service a721b1
		    free_db_info (mdb->extra_info);
Packit Service a721b1
		  free (mdb);
Packit Service a721b1
		}
Packit Service a721b1
	    }
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
  M17N_OBJECT_UNREF (mdatabase__list);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
void
Packit Service a721b1
mdatabase__update (void)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist, *p0, *p1, *p2, *p3;
Packit Service a721b1
  char path[PATH_MAX + 1];
Packit Service a721b1
  MDatabaseInfo *dir_info;
Packit Service a721b1
  struct stat statbuf;
Packit Service a721b1
  int rescan = 0;
Packit Service a721b1
Packit Service a721b1
  /* Update elements of mdatabase__dir_list.  */
Packit Service a721b1
  MPLIST_DO (plist, mdatabase__dir_list)
Packit Service a721b1
    {
Packit Service a721b1
      dir_info = MPLIST_VAL (plist);
Packit Service a721b1
      if (dir_info->filename)
Packit Service a721b1
	{
Packit Service a721b1
	  if (stat (dir_info->filename, &statbuf) == 0
Packit Service a721b1
	      && (statbuf.st_mode & S_IFDIR))
Packit Service a721b1
	    {
Packit Service a721b1
	      if (dir_info->time < statbuf.st_mtime)
Packit Service a721b1
		{
Packit Service a721b1
		  rescan = 1;
Packit Service a721b1
		  dir_info->time = statbuf.st_mtime;
Packit Service a721b1
		}
Packit Service a721b1
	      if (GEN_PATH (path, dir_info->filename, dir_info->len,
Packit Service a721b1
			    MDB_DIR, MDB_DIR_LEN)
Packit Service a721b1
		  && stat (path, &statbuf) >= 0
Packit Service a721b1
		  && dir_info->time < statbuf.st_mtime)
Packit Service a721b1
		{
Packit Service a721b1
		  rescan = 1;
Packit Service a721b1
		  dir_info->time = statbuf.st_mtime;
Packit Service a721b1
		}
Packit Service a721b1
	      dir_info->status = MDB_STATUS_UPDATED;
Packit Service a721b1
	    }
Packit Service a721b1
	  else
Packit Service a721b1
	    {
Packit Service a721b1
	      if (dir_info->status != MDB_STATUS_DISABLED)
Packit Service a721b1
		{
Packit Service a721b1
		  rescan = 1;
Packit Service a721b1
		  dir_info->time = 0;
Packit Service a721b1
		  dir_info->status = MDB_STATUS_DISABLED;
Packit Service a721b1
		}
Packit Service a721b1
	    }
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (! rescan)
Packit Service a721b1
    return;
Packit Service a721b1
Packit Service a721b1
  /* At first, mark all databases defined automatically from mdb.dir
Packit Service a721b1
     file(s) as "disabled".  */
Packit Service a721b1
  MPLIST_DO (plist, mdatabase__list)
Packit Service a721b1
    {
Packit Service a721b1
      p0 = MPLIST_PLIST (plist);
Packit Service a721b1
      /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
Packit Service a721b1
      MPLIST_DO (p0, MPLIST_NEXT (p0))
Packit Service a721b1
	{
Packit Service a721b1
	  p1 = MPLIST_PLIST (p0);
Packit Service a721b1
	  MPLIST_DO (p1, MPLIST_NEXT (p1))
Packit Service a721b1
	    {
Packit Service a721b1
	      p2 = MPLIST_PLIST (p1);
Packit Service a721b1
	      MPLIST_DO (p2, MPLIST_NEXT (p2))
Packit Service a721b1
		{
Packit Service a721b1
		  MDatabase *mdb;
Packit Service a721b1
		  MDatabaseInfo *db_info;
Packit Service a721b1
Packit Service a721b1
		  p3 = MPLIST_PLIST (p2);
Packit Service a721b1
		  p3 = MPLIST_NEXT (p3);
Packit Service a721b1
		  mdb = MPLIST_VAL (p3);
Packit Service a721b1
		  db_info = mdb->extra_info;
Packit Service a721b1
		  if (db_info->status == MDB_STATUS_AUTO)
Packit Service a721b1
		    db_info->status = MDB_STATUS_DISABLED;
Packit Service a721b1
		}
Packit Service a721b1
	    }
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  plist = mplist (); 
Packit Service a721b1
  MPLIST_DO (p0, mdatabase__dir_list)
Packit Service a721b1
    mplist_push (plist, MPLIST_KEY (p0), MPLIST_VAL (p0));
Packit Service a721b1
Packit Service a721b1
  while (! MPLIST_TAIL_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      MDatabaseInfo *dir_info = mplist_pop (plist);
Packit Service a721b1
      MPlist *pl, *p;
Packit Service a721b1
      int i;
Packit Service a721b1
      FILE *fp;
Packit Service a721b1
Packit Service a721b1
      if (dir_info->status == MDB_STATUS_DISABLED)
Packit Service a721b1
	continue;
Packit Service a721b1
      if (! GEN_PATH (path, dir_info->filename, dir_info->len,
Packit Service a721b1
		      MDB_DIR, MDB_DIR_LEN))
Packit Service a721b1
	continue;
Packit Service a721b1
      if (! (fp = fopen (path, "r")))
Packit Service a721b1
	continue;
Packit Service a721b1
      pl = mplist__from_file (fp, NULL);
Packit Service a721b1
      fclose (fp);
Packit Service a721b1
      if (! pl)
Packit Service a721b1
	continue;
Packit Service a721b1
      MPLIST_DO (p, pl)
Packit Service a721b1
	{
Packit Service a721b1
	  MSymbol tags[4];
Packit Service a721b1
	  MPlist *p1;
Packit Service a721b1
	  MText *mt;
Packit Service a721b1
	  int nbytes;
Packit Service a721b1
	  int with_wildcard = 0;
Packit Service a721b1
Packit Service a721b1
	  if (! MPLIST_PLIST_P (p))
Packit Service a721b1
	    continue;
Packit Service a721b1
	  for (i = 0, p1 = MPLIST_PLIST (p); i < 4 && MPLIST_SYMBOL_P (p1);
Packit Service a721b1
	       i++, p1 = MPLIST_NEXT (p1))
Packit Service a721b1
	    with_wildcard |= ((tags[i] = MPLIST_SYMBOL (p1)) == Masterisk);
Packit Service a721b1
	  if (i == 0
Packit Service a721b1
	      || tags[0] == Masterisk
Packit Service a721b1
	      || ! MPLIST_MTEXT_P (p1))
Packit Service a721b1
	    continue;
Packit Service a721b1
	  for (; i < 4; i++)
Packit Service a721b1
	    tags[i] = with_wildcard ? Masterisk : Mnil;
Packit Service a721b1
	  mt = MPLIST_MTEXT (p1);
Packit Service a721b1
	  nbytes = mtext_nbytes (mt);
Packit Service a721b1
	  if (nbytes > PATH_MAX)
Packit Service a721b1
	    continue;
Packit Service a721b1
	  memcpy (path, MTEXT_DATA (mt), nbytes);
Packit Service a721b1
	  path[nbytes] = '\0';
Packit Service a721b1
	  if (with_wildcard)
Packit Service a721b1
	    register_database (tags, load_database, path,
Packit Service a721b1
			       MDB_STATUS_AUTO_WILDCARD, NULL);
Packit Service a721b1
	  else
Packit Service a721b1
	    register_database (tags, load_database, path,
Packit Service a721b1
			       MDB_STATUS_AUTO, p1);
Packit Service a721b1
	}
Packit Service a721b1
      M17N_OBJECT_UNREF (pl);
Packit Service a721b1
    }
Packit Service a721b1
  M17N_OBJECT_UNREF (plist);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys)
Packit Service a721b1
{
Packit Service a721b1
  int mdebug_flag = MDEBUG_DATABASE;
Packit Service a721b1
  MDatabaseInfo *db_info;
Packit Service a721b1
  char *filename;
Packit Service a721b1
  FILE *fp;
Packit Service a721b1
  MPlist *plist;
Packit Service a721b1
  char name[256];
Packit Service a721b1
Packit Service a721b1
  if (mdb->loader != load_database
Packit Service a721b1
      || mdb->tag[0] == Mchar_table
Packit Service a721b1
      || mdb->tag[0] == Mcharset)
Packit Service a721b1
    MERROR (MERROR_DB, NULL);
Packit Service a721b1
  MDEBUG_PRINT1 (" [DB]  <%s>.\n",
Packit Service a721b1
		 gen_database_name (name, mdb->tag));
Packit Service a721b1
  db_info = mdb->extra_info;
Packit Service a721b1
  filename = get_database_file (db_info, NULL, NULL);
Packit Service a721b1
  if (! filename || ! (fp = fopen (filename, "r")))
Packit Service a721b1
    MERROR (MERROR_DB, NULL);
Packit Service a721b1
  plist = mplist__from_file (fp, keys);
Packit Service a721b1
  fclose (fp);
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/* Check if the database MDB should be reloaded or not.  It returns:
Packit Service a721b1
Packit Service a721b1
	1: The database has not been updated since it was loaded last
Packit Service a721b1
	time.
Packit Service a721b1
Packit Service a721b1
	0: The database has never been loaded or has been updated
Packit Service a721b1
	since it was loaded last time.
Packit Service a721b1
Packit Service a721b1
	-1: The database is not loadable at the moment.  */
Packit Service a721b1
Packit Service a721b1
int
Packit Service a721b1
mdatabase__check (MDatabase *mdb)
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info;
Packit Service a721b1
  struct stat buf;
Packit Service a721b1
  int result;
Packit Service a721b1
Packit Service a721b1
  if (db_info->absolute_filename != db_info->filename
Packit Service a721b1
      || db_info->status == MDB_STATUS_AUTO)
Packit Service a721b1
    mdatabase__update ();
Packit Service a721b1
Packit Service a721b1
  if (! get_database_file (db_info, &buf, &result)
Packit Service a721b1
      || result < 0)
Packit Service a721b1
    return -1;
Packit Service a721b1
  if (db_info->time < buf.st_mtime)
Packit Service a721b1
    return 0;
Packit Service a721b1
  return 1;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/* Search directories in mdatabase__dir_list for file FILENAME.  If
Packit Service a721b1
   the file exist, return the absolute pathname.  If FILENAME is
Packit Service a721b1
   already absolute, return a copy of it.  */
Packit Service a721b1
Packit Service a721b1
char *
Packit Service a721b1
mdatabase__find_file (char *filename)
Packit Service a721b1
{
Packit Service a721b1
  struct stat buf;
Packit Service a721b1
  int result;
Packit Service a721b1
  MDatabaseInfo db_info;
Packit Service a721b1
Packit Service a721b1
  if (filename[0] == PATH_SEPARATOR)
Packit Service a721b1
    return (stat (filename, &buf) == 0 ? strdup (filename) : NULL);
Packit Service a721b1
  db_info.filename = filename;
Packit Service a721b1
  db_info.len = strlen (filename);
Packit Service a721b1
  db_info.time = 0;
Packit Service a721b1
  db_info.absolute_filename = NULL;
Packit Service a721b1
  if (! get_database_file (&db_info, &buf, &result)
Packit Service a721b1
      || result < 0)
Packit Service a721b1
    return NULL;
Packit Service a721b1
  return db_info.absolute_filename;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
char *
Packit Service a721b1
mdatabase__file (MDatabase *mdb)
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *db_info;
Packit Service a721b1
Packit Service a721b1
  if (mdb->loader != load_database)
Packit Service a721b1
    return NULL;
Packit Service a721b1
  db_info = mdb->extra_info;
Packit Service a721b1
  return get_database_file (db_info, NULL, NULL);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
int
Packit Service a721b1
mdatabase__lock (MDatabase *mdb)
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *db_info;
Packit Service a721b1
  struct stat buf;
Packit Service a721b1
  FILE *fp;
Packit Service a721b1
  int len;
Packit Service a721b1
  char *file;
Packit Service a721b1
Packit Service a721b1
  if (mdb->loader != load_database)
Packit Service a721b1
    return -1;
Packit Service a721b1
  db_info = mdb->extra_info;
Packit Service a721b1
  if (db_info->lock_file)
Packit Service a721b1
    return -1;
Packit Service a721b1
  file = get_database_file (db_info, NULL, NULL);
Packit Service a721b1
  if (! file)
Packit Service a721b1
    return -1;
Packit Service a721b1
  len = strlen (file);
Packit Service a721b1
  db_info->uniq_file = malloc (len + 35);
Packit Service a721b1
  if (! db_info->uniq_file)
Packit Service a721b1
    return -1;
Packit Service a721b1
  db_info->lock_file = malloc (len + 5);
Packit Service a721b1
  if (! db_info->lock_file)
Packit Service a721b1
    {
Packit Service a721b1
      free (db_info->uniq_file);
Packit Service a721b1
      return -1;
Packit Service a721b1
    }
Packit Service a721b1
  sprintf (db_info->uniq_file, "%s.%X.%X", db_info->absolute_filename,
Packit Service a721b1
	   (unsigned) time (NULL), (unsigned) getpid ());
Packit Service a721b1
  sprintf (db_info->lock_file, "%s.LCK", db_info->absolute_filename);
Packit Service a721b1
Packit Service a721b1
  fp = fopen (db_info->uniq_file, "w");
Packit Service a721b1
  if (! fp)
Packit Service a721b1
    {
Packit Service a721b1
      char *str = strdup (db_info->uniq_file);
Packit Service a721b1
      char *dir = dirname (str);
Packit Service a721b1
      
Packit Service a721b1
      if (stat (dir, &buf) == 0
Packit Service a721b1
	  || mkdir (dir, 0777) < 0
Packit Service a721b1
	  || ! (fp = fopen (db_info->uniq_file, "w")))
Packit Service a721b1
	{
Packit Service a721b1
	  free (db_info->uniq_file);
Packit Service a721b1
	  free (db_info->lock_file);
Packit Service a721b1
	  db_info->lock_file = NULL;
Packit Service a721b1
	  free (str);
Packit Service a721b1
	  return -1;
Packit Service a721b1
	}
Packit Service a721b1
      free (str);
Packit Service a721b1
    }
Packit Service a721b1
  fclose (fp);
Packit Service a721b1
  if (link (db_info->uniq_file, db_info->lock_file) < 0
Packit Service a721b1
      && (stat (db_info->uniq_file, &buf) < 0
Packit Service a721b1
	  || buf.st_nlink != 2))
Packit Service a721b1
    {
Packit Service a721b1
      unlink (db_info->uniq_file);
Packit Service a721b1
      unlink (db_info->lock_file);
Packit Service a721b1
      free (db_info->uniq_file);
Packit Service a721b1
      free (db_info->lock_file);
Packit Service a721b1
      db_info->lock_file = NULL;
Packit Service a721b1
      return 0;
Packit Service a721b1
    }
Packit Service a721b1
  return 1;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
int
Packit Service a721b1
mdatabase__save (MDatabase *mdb, MPlist *data)
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *db_info;
Packit Service a721b1
  FILE *fp;
Packit Service a721b1
  char *file;
Packit Service a721b1
  MText *mt;
Packit Service a721b1
  int ret;
Packit Service a721b1
Packit Service a721b1
  if (mdb->loader != load_database)
Packit Service a721b1
    return -1;
Packit Service a721b1
  db_info = mdb->extra_info;
Packit Service a721b1
  if (! db_info->lock_file)
Packit Service a721b1
    return -1;
Packit Service a721b1
  file = get_database_file (db_info, NULL, NULL);
Packit Service a721b1
  if (! file)
Packit Service a721b1
    return -1;
Packit Service a721b1
  mt = mtext ();
Packit Service a721b1
  if (mplist__serialize (mt, data, 1) < 0)
Packit Service a721b1
    {
Packit Service a721b1
      M17N_OBJECT_UNREF (mt);
Packit Service a721b1
      return -1;
Packit Service a721b1
    }
Packit Service a721b1
  fp = fopen (db_info->uniq_file, "w");
Packit Service a721b1
  if (! fp)
Packit Service a721b1
    {
Packit Service a721b1
      M17N_OBJECT_UNREF (mt);
Packit Service a721b1
      return -1;
Packit Service a721b1
    }
Packit Service a721b1
  if (mt->format > MTEXT_FORMAT_UTF_8)
Packit Service a721b1
    mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
Packit Service a721b1
  fwrite (MTEXT_DATA (mt), 1, mtext_nchars (mt), fp);
Packit Service a721b1
  fclose (fp);
Packit Service a721b1
  M17N_OBJECT_UNREF (mt);
Packit Service a721b1
  if ((ret = rename (db_info->uniq_file, file)) < 0)
Packit Service a721b1
    unlink (db_info->uniq_file);
Packit Service a721b1
  free (db_info->uniq_file);
Packit Service a721b1
  db_info->uniq_file = NULL;
Packit Service a721b1
  return ret;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
int
Packit Service a721b1
mdatabase__unlock (MDatabase *mdb)
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *db_info;
Packit Service a721b1
Packit Service a721b1
  if (mdb->loader != load_database)
Packit Service a721b1
    return -1;
Packit Service a721b1
  db_info = mdb->extra_info;
Packit Service a721b1
  if (! db_info->lock_file)
Packit Service a721b1
    return -1;
Packit Service a721b1
  unlink (db_info->lock_file);
Packit Service a721b1
  free (db_info->lock_file);
Packit Service a721b1
  db_info->lock_file = NULL;
Packit Service a721b1
  if (db_info->uniq_file)
Packit Service a721b1
    {
Packit Service a721b1
      unlink (db_info->uniq_file);
Packit Service a721b1
      free (db_info->uniq_file);
Packit Service a721b1
    }
Packit Service a721b1
  return 0;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mdatabase__props (MDatabase *mdb)
Packit Service a721b1
{
Packit Service a721b1
  MDatabaseInfo *db_info;
Packit Service a721b1
Packit Service a721b1
  if (mdb->loader != load_database)
Packit Service a721b1
    return NULL;
Packit Service a721b1
  db_info = mdb->extra_info;
Packit Service a721b1
  return db_info->properties;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*** @} */
Packit Service a721b1
#endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
Packit Service a721b1
Packit Service a721b1

Packit Service a721b1
/* External API */
Packit Service a721b1
Packit Service a721b1
/*** @addtogroup m17nCharset */
Packit Service a721b1
/*** @{ */
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief The symbol @c Mcharset.
Packit Service a721b1
Packit Service a721b1
    Any decoded M-text has a text property whose key is the predefined
Packit Service a721b1
    symbol @c Mcharset.  The name of @c Mcharset is
Packit Service a721b1
    <tt>"charset"</tt>.  */
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief シンボル @c Mcharset.
Packit Service a721b1
Packit Service a721b1
    デコードされた M-text は、キーが @c Mcharset
Packit Service a721b1
    であるようなテキストプロパティを持つ。
Packit Service a721b1
    シンボル @c Mcharset は <tt>"charset"</tt> という名前を持つ。  */
Packit Service a721b1
Packit Service a721b1
MSymbol Mcharset;
Packit Service a721b1
/*=*/
Packit Service a721b1
/*** @} */
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/*** @addtogroup m17nDatabase */
Packit Service a721b1
/*** @{ */
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Directory for application specific data.
Packit Service a721b1
Packit Service a721b1
    If an application program wants to provide a data specific to the
Packit Service a721b1
    program or a data overriding what supplied by the m17n database,
Packit Service a721b1
    it must set this variable to a name of directory that contains the
Packit Service a721b1
    data files before it calls the macro M17N_INIT ().  The directory
Packit Service a721b1
    may contain a file "mdb.dir" which contains a list of data
Packit Service a721b1
    definitions in the format described in @ref mdbDir "mdbDir(5)".
Packit Service a721b1
Packit Service a721b1
    The default value is NULL.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief アプリケーション固有のデータ用ディレクトリ.
Packit Service a721b1
Packit Service a721b1
    アプリケーションプログラムが、そのプログラム固有のデータや m17n 
Packit Service a721b1
    データベースを上書きするデータを提供する場合には、マクロ M17N_INIT () 
Packit Service a721b1
    を呼ぶ前にこの変数をデータファイルを含むディレクトリ名にセットしなくてはならない。ディレクトリには
Packit Service a721b1
    "mdb.dir" ファイルをおくことができる。その"mdb.dir"ファイルには、 
Packit Service a721b1
    @ref mdbDir "mdbDir(5)" で説明されているフォーマットでデータ定義のリストを記述する。
Packit Service a721b1
Packit Service a721b1
    デフォルトの値は NULL である。  */
Packit Service a721b1
Packit Service a721b1
char *mdatabase_dir;
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Look for a data in the database.
Packit Service a721b1
Packit Service a721b1
    The mdatabase_find () function searches the m17n database for a
Packit Service a721b1
    data who has tags $TAG0 through $TAG3, and returns a pointer to
Packit Service a721b1
    the data.  If such a data is not found, it returns @c NULL.  */
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief データベース中のデータを探す.
Packit Service a721b1
Packit Service a721b1
    関数 mdatabase_find () は、 m17n 言語情報ベース中で $TAG0 から 
Packit Service a721b1
    $TAG3 までのタグを持つデータを探し、それへのポインタを返す。そのようなデータがなければ
Packit Service a721b1
    @c NULL を返す。
Packit Service a721b1
Packit Service a721b1
    @latexonly \IPAlabel{mdatabase_find} @endlatexonly  */
Packit Service a721b1
Packit Service a721b1
MDatabase *
Packit Service a721b1
mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
Packit Service a721b1
{
Packit Service a721b1
  MSymbol tags[4];
Packit Service a721b1
Packit Service a721b1
  mdatabase__update ();
Packit Service a721b1
  tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
Packit Service a721b1
  return find_database (tags);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Return a data list of the m17n database.
Packit Service a721b1
Packit Service a721b1
    The mdatabase_list () function searches the m17n database for data
Packit Service a721b1
    who have tags $TAG0 through $TAG3, and returns their list by a
Packit Service a721b1
    plist.  The value #Mnil in $TAGn means a wild card that matches
Packit Service a721b1
    any tag.  Each element of the plist has key #Mt and value a
Packit Service a721b1
    pointer to type #MDatabase.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief m17n データベースのデータリストを返す.
Packit Service a721b1
Packit Service a721b1
    関数 mdatabase_list () は m17n データベース中から $TAG0 から$TAG3 
Packit Service a721b1
    までのタグを持つデータを探し、そのリストをplist として返す。 $TAGn が #Mnil
Packit Service a721b1
    であった場合には、任意のタグにマッチするワイルドカードとして取り扱われる。返される
Packit Service a721b1
    plist の各要素はキー として #Mt を、値として #MDatabase 型へのポインタを持つ。  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist = mplist (), *pl = plist;
Packit Service a721b1
  MPlist *p, *p0, *p1, *p2, *p3;
Packit Service a721b1
Packit Service a721b1
  mdatabase__update ();
Packit Service a721b1
Packit Service a721b1
  MPLIST_DO (p, mdatabase__list)
Packit Service a721b1
    {
Packit Service a721b1
      p0 = MPLIST_PLIST (p);
Packit Service a721b1
      /* P0 ::= (TAG0 (TAG1 (TAG2 (TAG3 MDB) ...) ...) ...) */
Packit Service a721b1
      if (MPLIST_SYMBOL (p0) == Masterisk
Packit Service a721b1
	  || (tag0 != Mnil && MPLIST_SYMBOL (p0) != tag0))
Packit Service a721b1
	continue;
Packit Service a721b1
      MPLIST_DO (p0, MPLIST_NEXT (p0))
Packit Service a721b1
	{
Packit Service a721b1
	  p1 = MPLIST_PLIST (p0);
Packit Service a721b1
	  if (MPLIST_SYMBOL (p1) == Masterisk)
Packit Service a721b1
	    {
Packit Service a721b1
	      if (expand_wildcard_database (p1))
Packit Service a721b1
		{
Packit Service a721b1
		  M17N_OBJECT_UNREF (plist);
Packit Service a721b1
		  return mdatabase_list (tag0, tag1, tag2, tag3);
Packit Service a721b1
		}
Packit Service a721b1
	      continue;
Packit Service a721b1
	    }
Packit Service a721b1
	  if (tag1 != Mnil && MPLIST_SYMBOL (p1) != tag1)
Packit Service a721b1
	    continue;
Packit Service a721b1
	  MPLIST_DO (p1, MPLIST_NEXT (p1))
Packit Service a721b1
	    {
Packit Service a721b1
	      p2 = MPLIST_PLIST (p1);
Packit Service a721b1
	      if (MPLIST_SYMBOL (p2) == Masterisk)
Packit Service a721b1
		{
Packit Service a721b1
		  if (expand_wildcard_database (p2))
Packit Service a721b1
		    {
Packit Service a721b1
		      M17N_OBJECT_UNREF (plist);
Packit Service a721b1
		      return mdatabase_list (tag0, tag1, tag2, tag3);
Packit Service a721b1
		    }
Packit Service a721b1
		  continue;
Packit Service a721b1
		}
Packit Service a721b1
	      if (tag2 != Mnil && MPLIST_SYMBOL (p2) != tag2)
Packit Service a721b1
		continue;
Packit Service a721b1
	      MPLIST_DO (p2, MPLIST_NEXT (p2))
Packit Service a721b1
		{
Packit Service a721b1
		  p3 = MPLIST_PLIST (p2);
Packit Service a721b1
		  if (MPLIST_SYMBOL (p3) == Masterisk)
Packit Service a721b1
		    {
Packit Service a721b1
		      if (expand_wildcard_database (p3))
Packit Service a721b1
			{
Packit Service a721b1
			  M17N_OBJECT_UNREF (plist);
Packit Service a721b1
			  return mdatabase_list (tag0, tag1, tag2, tag3);
Packit Service a721b1
			}
Packit Service a721b1
		      continue;
Packit Service a721b1
		    }
Packit Service a721b1
		  if (tag3 != Mnil && MPLIST_SYMBOL (p3) != tag3)
Packit Service a721b1
		    continue;
Packit Service a721b1
		  p3 = MPLIST_NEXT (p3);
Packit Service a721b1
		  pl = mplist_add (pl, Mt, MPLIST_VAL (p3));
Packit Service a721b1
		}
Packit Service a721b1
	    }
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
  if (MPLIST_TAIL_P (plist))
Packit Service a721b1
    M17N_OBJECT_UNREF (plist);
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Define a data of the m17n database.
Packit Service a721b1
Packit Service a721b1
    The mdatabase_define () function defines a data that has tags
Packit Service a721b1
    $TAG0 through $TAG3 and additional information $EXTRA_INFO.
Packit Service a721b1
Packit Service a721b1
    $LOADER is a pointer to a function that loads the data from the
Packit Service a721b1
    database.  This function is called from the mdatabase_load ()
Packit Service a721b1
    function with the two arguments $TAGS and $EXTRA_INFO.  Here,
Packit Service a721b1
    $TAGS is the array of $TAG0 through $TAG3.
Packit Service a721b1
Packit Service a721b1
    If $LOADER is @c NULL, the default loader of the m17n library is
Packit Service a721b1
    used.  In this case, $EXTRA_INFO must be a string specifying a
Packit Service a721b1
    filename that contains the data.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    If the operation was successful, mdatabase_define () returns a
Packit Service a721b1
    pointer to the defined data, which can be used as an argument to
Packit Service a721b1
    mdatabase_load ().  Otherwise, it returns @c NULL.  */
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief m17n データベースのデータを定義する.
Packit Service a721b1
Packit Service a721b1
    関数 mdatabase_define () は $TAG0 から $TAG3 までのタグおよび付加情報 
Packit Service a721b1
    $EXTRA_INFO を持つデータを定義する。
Packit Service a721b1
Packit Service a721b1
    $LOADER はそのデータのロードに用いられる関数へのポインタである。この関数は
Packit Service a721b1
    mdatabase_load () から $TAGS と $EXTRA_INFO という二つの引数付きで呼び出される。ここで 
Packit Service a721b1
    $TAGS は $TAG0 から $TAG3 までの配列である。
Packit Service a721b1
Packit Service a721b1
    もし $LOADER が @c NULL なら、m17n ライブラリ標準のローダが使われる。この場合には
Packit Service a721b1
    $EXTRA_INFO はデータを含むファイル名でなくてはならない。
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    処理に成功すれば mdatabase_define () 
Packit Service a721b1
    は定義されたデータベースへのポインタを返す。このポインタは関数 mdatabase_load () 
Packit Service a721b1
    の引数として用いることができる。そうでなければ @c NULL を返す。
Packit Service a721b1
Packit Service a721b1
    @latexonly \IPAlabel{mdatabase_define} @endlatexonly  */
Packit Service a721b1
Packit Service a721b1
/***
Packit Service a721b1
    @seealso
Packit Service a721b1
    mdatabase_load (),  mdatabase_define ()  */
Packit Service a721b1
Packit Service a721b1
MDatabase *
Packit Service a721b1
mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3,
Packit Service a721b1
		  void *(*loader) (MSymbol *, void *),
Packit Service a721b1
		  void *extra_info)
Packit Service a721b1
{
Packit Service a721b1
  MDatabase *mdb;
Packit Service a721b1
  MSymbol tags[4];
Packit Service a721b1
Packit Service a721b1
  tags[0] = tag0, tags[1] = tag1, tags[2] = tag2, tags[3] = tag3;
Packit Service a721b1
  if (! loader)
Packit Service a721b1
    loader = load_database;
Packit Service a721b1
  mdb = register_database (tags, loader, extra_info, MDB_STATUS_EXPLICIT, NULL);
Packit Service a721b1
  return mdb;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Load a data from the database.
Packit Service a721b1
Packit Service a721b1
    The mdatabase_load () function loads a data specified in $MDB and
Packit Service a721b1
    returns the contents.  The type of contents depends on the type of
Packit Service a721b1
    the data.
Packit Service a721b1
Packit Service a721b1
    If the data is of the @e plist @e type, this function returns a
Packit Service a721b1
    pointer to @e plist.
Packit Service a721b1
Packit Service a721b1
    If the database is of the @e chartable @e type, it returns a
Packit Service a721b1
    chartable.  The default value of the chartable is set according to
Packit Service a721b1
    the second tag of the data as below:
Packit Service a721b1
Packit Service a721b1
    @li If the tag is #Msymbol, the default value is #Mnil.
Packit Service a721b1
    @li If the tag is #Minteger, the default value is -1.
Packit Service a721b1
    @li Otherwise, the default value is @c NULL.
Packit Service a721b1
Packit Service a721b1
    If the data is of the @e charset @e type, it returns a plist of length 2
Packit Service a721b1
    (keys are both #Mt).  The value of the first element is an array
Packit Service a721b1
    of integers that maps code points to the corresponding character
Packit Service a721b1
    codes.  The value of the second element is a chartable of integers
Packit Service a721b1
    that does the reverse mapping.  The charset must be defined in
Packit Service a721b1
    advance.  */
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief データベースからデータをロードする.
Packit Service a721b1
Packit Service a721b1
    関数 mdatabase_load () は $MDB 
Packit Service a721b1
    が指すデータをロードし、その中身を返す。返されるものはデータのタイプによって異なる。
Packit Service a721b1
Packit Service a721b1
    データが @e plistタイプ ならば、 @e plist へのポインタを返す。
Packit Service a721b1
Packit Service a721b1
    データが @e chartableタイプ ならば文字テーブルを返す。
Packit Service a721b1
    文字テーブルのデフォルト値は、データの第2タグによって以下のように決まる。
Packit Service a721b1
Packit Service a721b1
    @li タグが #Msymbol なら、デフォルト値は #Mnil
Packit Service a721b1
    @li タグが #Minteger なら、デフォルト値は -1
Packit Service a721b1
    @li それ以外なら、デフォルト値は @c NULL
Packit Service a721b1
Packit Service a721b1
    データが @e charsetタイプ ならば長さ 2 の plist を返す(キーは共に#Mt )。
Packit Service a721b1
    最初の要素の値はコードポイントを対応する文字コードにマップする整数の配列である。
Packit Service a721b1
    2番目の要素の値は逆のマップをする文字テーブルである。
Packit Service a721b1
    この文字セットは予め定義されていなければならない。
Packit Service a721b1
Packit Service a721b1
    @latexonly \IPAlabel{mdatabase_load} @endlatexonly
Packit Service a721b1
  */
Packit Service a721b1
Packit Service a721b1
/***
Packit Service a721b1
    @seealso
Packit Service a721b1
    mdatabase_load (),  mdatabase_define ()  */
Packit Service a721b1
Packit Service a721b1
void *
Packit Service a721b1
mdatabase_load (MDatabase *mdb)
Packit Service a721b1
{
Packit Service a721b1
  return (*mdb->loader) (mdb->tag, mdb->extra_info);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Get tags of a data.
Packit Service a721b1
Packit Service a721b1
    The mdatabase_tag () function returns an array of tags (symbols)
Packit Service a721b1
    that identify the data in $MDB.  The length of the array is
Packit Service a721b1
    four.  */
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief データのタグを得る.
Packit Service a721b1
Packit Service a721b1
    関数 mdatabase_tag () は、データ $MDB のタグ(シンボル)の配列を返す。配列の長さは
Packit Service a721b1
    4 である。
Packit Service a721b1
Packit Service a721b1
    @latexonly \IPAlabel{mdatabase_tag} @endlatexonly  */
Packit Service a721b1
Packit Service a721b1
MSymbol *
Packit Service a721b1
mdatabase_tag (MDatabase *mdb)
Packit Service a721b1
{
Packit Service a721b1
  return mdb->tag;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*** @} */
Packit Service a721b1
Packit Service a721b1
/*
Packit Service a721b1
  Local Variables:
Packit Service a721b1
  coding: euc-japan
Packit Service a721b1
  End:
Packit Service a721b1
*/