From 0574b9cbd51f74500dc6678a8ecc039c5189d45b Mon Sep 17 00:00:00 2001 From: handa Date: Tue, 18 Oct 2005 01:30:32 +0000 Subject: [PATCH] Include . (MAX_TIME): New macro. (Masterisk): New variable. (get_database_stream): Argument changed to (MDatabaseInfo *). Callers changed. (get_dir_info): Renamed from duplicate_dirname. Callers changed. (find_database): New function. (update_database_list): New function. (mdatabase__init): Initialize Masterisk. Setup mdb_list by calling update_database_list. (mdatabase__check): New function. (mdatabase_find): Use update_database and find_database. Don't handle MDatabaseHookFunc. (mdatabase_list): Call update_database at first. (mdatabase_define): Adjusted for the change of mdb->extra_info. --- src/database.c | 323 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 220 insertions(+), 103 deletions(-) diff --git a/src/database.c b/src/database.c index 98db4c2..d75aecb 100644 --- a/src/database.c +++ b/src/database.c @@ -119,6 +119,7 @@ #include #include #include +#include #include "m17n.h" #include "m17n-misc.h" @@ -134,6 +135,10 @@ #define MDB_DIR "mdb.dir" #define MDB_DIR_LEN 8 +#define MAX_TIME(TIME1, TIME2) ((TIME1) >= (TIME2) ? (TIME1) : (TIME2)) + +static MSymbol Masterisk; + /** Structure for a data in the m17n database. */ struct MDatabase @@ -422,29 +427,40 @@ gen_database_name (char *buf, MSymbol *tags) } static FILE * -get_database_stream (char *filename) +get_database_stream (MDatabaseInfo *db_info) { FILE *fp = NULL; + struct stat buf; - if (filename[0] == '/') - fp = fopen (filename, "r"); + if (db_info->filename[0] == '/') + { + if (stat (db_info->filename, &buf) == 0 + && (fp = fopen (db_info->filename, "r"))) + db_info->time = MAX_TIME (buf.st_mtime, buf.st_ctime); + } else { MPlist *plist; char *path; - int filelen = strlen (filename); + int filelen = strlen (db_info->filename); USE_SAFE_ALLOCA; MPLIST_DO (plist, mdatabase__dir_list) { - int require = strlen ((char *) MPLIST_VAL (plist)) + filelen + 1; + MDatabaseInfo *dir_info = MPLIST_VAL (plist); + int require = strlen (dir_info->filename) + filelen + 1; SAFE_ALLOCA (path, require); - strcpy (path, (char *) MPLIST_VAL (plist)); - strcat (path, filename); - fp = fopen (path, "r"); - if (fp) - break; + strcpy (path, dir_info->filename); + strcat (path, db_info->filename); + if (stat (path, &buf) == 0 + && (fp = fopen (path, "r"))) + { + free (db_info->filename); + db_info->filename = strdup (path); + db_info->time = MAX_TIME (buf.st_mtime, buf.st_ctime); + break; + } } SAFE_FREE (path); } @@ -454,7 +470,7 @@ get_database_stream (char *filename) static void * load_database (MSymbol *tags, void *extra_info) { - FILE *fp = get_database_stream ((char *) extra_info); + FILE *fp = get_database_stream ((MDatabaseInfo *) extra_info); void *value; if (! fp) @@ -474,83 +490,88 @@ load_database (MSymbol *tags, void *extra_info) } -/** Copy DIRNAME to a newly allocated memory and return it. If +/** If DIRNAME is a readable directory, allocate MDatabaseInfo and + copy DIRNAME to a newly allocated memory and return it. If DIRNAME does not end with a slash, append a slash to the new memory. */ -static char * -duplicate_dirname (char *dirname) +static MDatabaseInfo * +get_dir_info (char *dirname) { struct stat buf; int len; - char *str; + MDatabaseInfo *dir_info; if (! dirname - || stat (dirname, &buf) < 0) + || stat (dirname, &buf) < 0 + || ! (buf.st_mode & S_IFDIR)) return NULL; + MSTRUCT_MALLOC (dir_info, MERROR_DB); len = strlen (dirname); - MTABLE_MALLOC (str, len + 2, MERROR_DB); - memcpy (str, dirname, len + 1); - if (str[len - 1] != '/') + MTABLE_MALLOC (dir_info->filename, len + 2, MERROR_DB); + memcpy (dir_info->filename, dirname, len + 1); + if (dir_info->filename[len - 1] != '/') { - str[len] = '/'; - str[len + 1] = '\0'; + dir_info->filename[len] = '/'; + dir_info->filename[len + 1] = '\0'; } - return str; + /* Set this to zero so that the first call of update_database_list + surely checks this directory. */ + dir_info->time = 0; + return dir_info; } - -/* Internal API */ +static MDatabase * +find_database (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3) +{ + int i; -/** List of database directories. */ -MPlist *mdatabase__dir_list; + for (i = 0; i < mdb_list.used; i++) + { + MDatabase *mdb = mdb_list.mdbs + i; -MSymbol M_database_hook; + if (tag0 == mdb->tag[0] + && tag1 == mdb->tag[1] + && tag2 == mdb->tag[2] + && tag3 == mdb->tag[3]) + return mdb; + } + return NULL; +} -int -mdatabase__init () +static void +update_database_list () { - char *dir; - int i; MPlist *plist; - FILE *fp; char *path; USE_SAFE_ALLOCA; - Mchar_table = msymbol ("char-table"); - M_database_hook = msymbol (" database-hook"); - - mdatabase__dir_list = mplist (); - /** The macro M17NDIR specifies a directory where the system-wide - MDB_DIR file exists. */ - if ((dir = duplicate_dirname (M17NDIR))) - mplist_set (mdatabase__dir_list, Mt, dir); - - /* The variable mdatabase_dir specifies a directory where an - application program specific MDB_DIR file exists. */ - if ((dir = duplicate_dirname (mdatabase_dir))) - mplist_push (mdatabase__dir_list, Mt, dir); - - /* The environment variable M17NDIR (if non-NULL) specifies a - directory where a user specific MDB_DIR file exists. */ - if ((dir = duplicate_dirname (getenv ("M17NDIR")))) - mplist_push (mdatabase__dir_list, Mt, dir); + /* Usually this avoids path to be reallocated. */ + SAFE_ALLOCA (path, 256); - MLIST_INIT1 (&mdb_list, mdbs, 256); MPLIST_DO (plist, mdatabase__dir_list) { + MDatabaseInfo *dir_info = MPLIST_VAL (plist); + struct stat statbuf; MPlist *pl, *p; - int len; + int i, j, len; + FILE *fp; - dir = (char *) MPLIST_VAL (plist); - len = strlen (dir); + if (stat (dir_info->filename, &statbuf) < 0) + continue; + if (dir_info->time >= statbuf.st_ctime + && dir_info->time >= statbuf.st_mtime) + continue; + dir_info->time = MAX_TIME (statbuf.st_ctime, statbuf.st_mtime); + len = strlen (dir_info->filename); #ifdef PATH_MAX if (len + MDB_DIR_LEN >= PATH_MAX) continue; #endif /* PATH_MAX */ - SAFE_ALLOCA (path, len + MDB_DIR_LEN); - memcpy (path, dir, len); + SAFE_ALLOCA (path, len + MDB_DIR_LEN + 1); + memcpy (path, dir_info->filename, len); memcpy (path + len, MDB_DIR, MDB_DIR_LEN); + path[len + MDB_DIR_LEN] = '\0'; if (! (fp = fopen (path, "r"))) continue; pl = mplist__from_file (fp, NULL); @@ -563,22 +584,23 @@ mdatabase__init () MPlist *p1; MText *mt; int nbytes; + int with_wildcard = 0; if (! MPLIST_PLIST_P (p)) continue; + p1 = MPLIST_PLIST (p); + if (! MPLIST_SYMBOL_P (p1)) + continue; for (i = 0, p1 = MPLIST_PLIST (p); i < 4 && MPLIST_KEY (p1) == Msymbol; i++, p1 = MPLIST_NEXT (p1)) - mdb.tag[i] = MPLIST_SYMBOL (p1); + with_wildcard |= ((mdb.tag[i] = MPLIST_SYMBOL (p1)) == Masterisk); if (i == 0 + || mdb.tag[0] == Masterisk || ! MPLIST_MTEXT_P (p1)) continue; for (; i < 4; i++) mdb.tag[i] = Mnil; - if (mdatabase_find (mdb.tag[0], mdb.tag[1], - mdb.tag[2], mdb.tag[3])) - continue; - mdb.loader = load_database; mt = MPLIST_MTEXT (p1); if (mt->format >= MTEXT_FORMAT_UTF_16LE) @@ -588,18 +610,116 @@ mdatabase__init () if (nbytes > PATH_MAX) continue; #endif /* PATH_MAX */ - SAFE_ALLOCA (path, nbytes + 1); - memcpy (path, mt->data, nbytes); - path[nbytes] = '\0'; - mdb.extra_info = (void *) strdup (path); - if (! mdb.extra_info) - MEMORY_FULL (MERROR_DB); - MLIST_APPEND1 (&mdb_list, mdbs, mdb, MERROR_DB); + if (with_wildcard + && mdb.tag[0] != Mchar_table + && mdb.tag[0] != Mcharset) + { + glob_t globbuf; + MPlist *load_key; + + SAFE_ALLOCA (path, len + nbytes + 1); + memcpy (path, dir_info->filename, len); + memcpy (path + len, mt->data, nbytes); + path[len + nbytes] = '\0'; + + if (glob (path, GLOB_NOSORT | GLOB_NOCHECK, NULL, &globbuf) != 0) + continue; + load_key = mplist (); + for (i = 0; i < globbuf.gl_pathc; i++) + { + if (! (fp = fopen (globbuf.gl_pathv[i], "r"))) + continue; + p1 = mplist__from_file (fp, load_key); + fclose (fp); + if (! p1) + continue; + if (MPLIST_PLIST_P (p1)) + { + MPlist *p0; + MDatabase mdb2; + + for (j = 0, p0 = MPLIST_PLIST (p1); + j < 4 && MPLIST_SYMBOL_P (p0); + j++, p0 = MPLIST_NEXT (p0)) + mdb2.tag[j] = MPLIST_SYMBOL (p0); + for (; j < 4; j++) + mdb2.tag[j] = Mnil; + for (j = 0; j < 4; j++) + if (mdb.tag[j] == Masterisk + ? mdb2.tag[j] == Mnil + : (mdb.tag[j] != Mnil && mdb.tag[j] != mdb2.tag[j])) + break; + if (j == 4 + && ! find_database (mdb2.tag[0], mdb2.tag[1], + mdb2.tag[2], mdb2.tag[3])) + { + mdb2.loader = load_database; + mdb2.extra_info = calloc (1, sizeof (MDatabaseInfo)); + if (! mdb2.extra_info) + MEMORY_FULL (MERROR_DB); + ((MDatabaseInfo*) mdb2.extra_info)->filename + = strdup (globbuf.gl_pathv[i]); + MLIST_APPEND1 (&mdb_list, mdbs, mdb2, MERROR_DB); + } + } + M17N_OBJECT_UNREF (p1); + } + M17N_OBJECT_UNREF (load_key); + globfree (&globbuf); + } + else + { + if (find_database (mdb.tag[0], mdb.tag[1], + mdb.tag[2], mdb.tag[3])) + continue; + SAFE_ALLOCA (path, nbytes + 1); + memcpy (path, mt->data, nbytes); + path[nbytes] = '\0'; + mdb.extra_info = calloc (1, sizeof (MDatabaseInfo)); + if (! mdb.extra_info) + MEMORY_FULL (MERROR_DB); + ((MDatabaseInfo*) mdb.extra_info)->filename = strdup (path); + MLIST_APPEND1 (&mdb_list, mdbs, mdb, MERROR_DB); + } } M17N_OBJECT_UNREF (pl); } SAFE_FREE (path); +} + + +/* Internal API */ + +/** List of database directories. */ +MPlist *mdatabase__dir_list; + +int +mdatabase__init () +{ + MDatabaseInfo *dir_info; + + Mchar_table = msymbol ("char-table"); + Masterisk = msymbol ("*"); + + mdatabase__dir_list = mplist (); + /** The macro M17NDIR specifies a directory where the system-wide + MDB_DIR file exists. */ + if ((dir_info = get_dir_info (M17NDIR))) + mplist_set (mdatabase__dir_list, Mt, dir_info); + + /* The variable mdatabase_dir specifies a directory where an + application program specific MDB_DIR file exists. */ + if ((dir_info = get_dir_info (mdatabase_dir))) + mplist_push (mdatabase__dir_list, Mt, dir_info); + + /* The environment variable M17NDIR (if non-NULL) specifies a + directory where a user specific MDB_DIR file exists. */ + if ((dir_info = get_dir_info (getenv ("M17NDIR")))) + mplist_push (mdatabase__dir_list, Mt, dir_info); + + MLIST_INIT1 (&mdb_list, mdbs, 256); + update_database_list (); mdatabase__finder = ((void *(*) (MSymbol, MSymbol, MSymbol, MSymbol)) mdatabase_find); @@ -623,7 +743,12 @@ mdatabase__fini (void) MDatabase *mdb = mdb_list.mdbs + i; if (mdb->loader == load_database) - free (mdb->extra_info); + { + MDatabaseInfo *db_info = mdb->extra_info; + + free (db_info->filename); + free (db_info); + } } MLIST_FREE1 (&mdb_list, mdbs); } @@ -642,7 +767,7 @@ mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys) MERROR (MERROR_DB, NULL); MDEBUG_PRINT1 (" [DATABASE] loading <%s>.\n", gen_database_name (buf, mdb->tag)); - fp = get_database_stream ((char *) mdb->extra_info); + fp = get_database_stream ((MDatabaseInfo *) mdb->extra_info); if (! fp) MERROR (MERROR_DB, NULL); plist = mplist__from_file (fp, keys); @@ -651,6 +776,20 @@ mdatabase__load_for_keys (MDatabase *mdb, MPlist *keys) } +/* Check if the database MDB should be reloaded or not. */ + +int +mdatabase__check (MDatabase *mdb) +{ + MDatabaseInfo *db_info = (MDatabaseInfo *) mdb->extra_info; + struct stat buf; + + if (stat (db_info->filename, &buf) < 0) + return -1; + return (db_info->time >= buf.st_ctime + && db_info->time >= buf.st_mtime); +} + /*** @} */ #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */ @@ -705,24 +844,8 @@ char *mdatabase_dir; MDatabase * mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3) { - int i; - MDatabaseHookFunc func - = (MDatabaseHookFunc) msymbol_get (tag0, M_database_hook); - - if (func) - func (tag0, tag1, tag2, tag3); - - for (i = 0; i < mdb_list.used; i++) - { - MDatabase *mdb = mdb_list.mdbs + i; - - if (tag0 == mdb->tag[0] - && tag1 == mdb->tag[1] - && tag2 == mdb->tag[2] - && tag3 == mdb->tag[3]) - return mdb; - } - return NULL; + update_database_list (); + return find_database (tag0, tag1, tag2, tag3); } /*=*/ @@ -742,17 +865,13 @@ mdatabase_find (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3) ¤Ç¤¢¤Ã¤¿¾ì¹ç¤Ë¤Ï¡¢Ç¤°Õ¤Î¥¿¥°¤Ë¥Þ¥Ã¥Á¤¹¤ë¥ï¥¤¥ë¥É¥«¡¼¥É¤È¤·¤Æ¼è¤ê°·¤ï¤ì¤ë¡£ÊÖ¤µ¤ì¤ë plist ¤Î³ÆÍ×ÁǤϥ­¡¼ ¤È¤·¤Æ #Mt ¤ò¡¢ÃͤȤ·¤Æ #MDatabase ·¿¤Ø¤Î¥Ý¥¤¥ó¥¿¤ò»ý¤Ä¡£ */ - MPlist * mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3) { int i; MPlist *plist = NULL, *pl; - MDatabaseHookFunc func - = (MDatabaseHookFunc) msymbol_get (tag0, M_database_hook); - if (func) - func (tag0, tag1, tag2, tag3); + update_database_list (); for (i = 0; i < mdb_list.used; i++) { @@ -771,8 +890,6 @@ mdatabase_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3) return plist; } - - /*=*/ /***en @brief Define a data of the m17n database. @@ -824,11 +941,6 @@ mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3, void *extra_info) { MDatabase *mdb; - MDatabaseHookFunc func - = (MDatabaseHookFunc) msymbol_get (tag0, M_database_hook); - - if (func) - func (tag0, tag1, tag2, tag3); mdb = mdatabase_find (tag0, tag1, tag2, tag3); if (! mdb) @@ -844,9 +956,14 @@ mdatabase_define (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3, mdb->loader = loader ? loader : load_database; if (mdb->loader == load_database) { - if (mdb->extra_info) - free (mdb->extra_info); - mdb->extra_info = strdup ((char *) extra_info); + MDatabaseInfo *db_info = mdb->extra_info; + + if (db_info) + free (db_info->filename); + else + db_info = mdb->extra_info = malloc (sizeof (MDatabaseInfo)); + db_info->filename = strdup ((char *) extra_info); + db_info->time = 0; } else mdb->extra_info = extra_info; -- 1.7.10.4