Add `AC_CANONICAL_TARGET'; use `AC_PROG_LIBTOOL' instead of
[chise/libchise.git] / chise.c
diff --git a/chise.c b/chise.c
index b5ede8a..e76172b 100644 (file)
--- a/chise.c
+++ b/chise.c
@@ -1,4 +1,8 @@
 #include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
@@ -6,6 +10,8 @@
 #include "chise.h"
 #include "chise-name.h"
 
+const unsigned char chise_db_dir[] = CHISE_DB_DIR;
+const unsigned char chise_system_db_dir[] = CHISE_SI_DB_DIR;
 
 CHISE_Feature_Table*
 chise_ds_open_feature_table (CHISE_DS *ds, const char *feature);
@@ -23,7 +29,8 @@ typedef DB CHISE_Attribute_Table;
 
 CHISE_Attribute_Table*
 CHISE_Attribute_Table_open (const unsigned char *db_dir,
-                           const char *encoding, const char *feature,
+                           const char *category,
+                           const char *key_type, const char *name,
                            DBTYPE real_subtype,
                            u_int32_t accessmask, int modemask);
 
@@ -56,8 +63,8 @@ struct CHISE_DS
 };
 
 CHISE_DS*
-CHISE_DS_open (CHISE_DS_Type type, char *location,
-              DBTYPE subtype, int modemask)
+CHISE_DS_open (CHISE_DS_Type type, const unsigned char *location,
+              int subtype, int modemask)
 {
   CHISE_DS *ds = (CHISE_DS*)malloc (sizeof (CHISE_DS));
   size_t len = strlen (location);
@@ -66,7 +73,7 @@ CHISE_DS_open (CHISE_DS_Type type, char *location,
     return NULL;
 
   ds->type = type;
-  ds->subtype = subtype;
+  ds->subtype = ( (subtype != 0) ? subtype : DB_HASH );
   ds->modemask = modemask;
   ds->location = (unsigned char*)malloc (len + 1);
   if (ds->location == NULL)
@@ -148,6 +155,99 @@ chise_ds_get_ccs (CHISE_DS *ds, const unsigned char *ccs)
   return ct;
 }
 
+int
+chise_ds_foreach_char_feature_name (CHISE_DS *ds,
+                                   int (*func) (CHISE_DS *ds,
+                                                unsigned char *name))
+{
+  unsigned char *dname
+    = alloca (strlen (ds->location) + sizeof ("/character/feature") + 1);
+  DIR *dir;
+  struct dirent *de;
+
+  strcpy (dname, ds->location);
+  strcat (dname, "/character/feature");
+
+  if ( (dir = opendir (dname)) == NULL)
+    return -1;
+
+  while ( (de = readdir (dir)) != NULL )
+    {
+      if ( (strcmp (de->d_name, ".") != 0) &&
+          (strcmp (de->d_name, "..") != 0) )
+       {
+         int i, need_to_decode = 0;
+         unsigned char *cp;
+         unsigned char *name;
+         unsigned char *np;
+
+         for (cp = de->d_name, i = 0; *cp != '\0'; i++)
+           {
+             if (*cp++ == '%')
+               need_to_decode = 1;
+           }
+         if (need_to_decode)
+           {
+             int index = -1;
+             int ch, c[2];
+             int hex[2];
+
+             name = (unsigned char *) alloca (i);
+             cp = de->d_name;
+             np = name;
+
+             while ( (ch = *cp++) != '\0')
+               {
+                 if (ch == '%')
+                   {
+                     if (index >= 0)
+                       {
+                         *np++ = '%';
+                         if (index == 1)
+                           *np++ = c[0];
+                       }
+                     index = 0;
+                   }
+                 else if (index >= 0)
+                   {
+                     c[index] = ch;
+
+                     if ( ('0' <= ch) && (ch <= '9') )
+                       hex[index++] = ch - '0';
+                     else if ( ('A' <= ch) && (ch <= 'F') )
+                       hex[index++] = ch - 'A' + 10;
+                     else if ( ('a' <= ch) && (ch <= 'f') )
+                       hex[index++] = ch - 'a' + 10;
+                     else
+                       {
+                         *np++ = '%';
+                         if (index == 1)
+                           *np++ = c[0];
+                         *np++ = ch;
+                         index = -1;
+                         continue;
+                       }
+                     if (index == 2)
+                       {
+                         *np++ = (hex[0] << 4) | hex[1];
+                         index = -1;
+                         continue;
+                       }
+                   }
+                 else
+                   *np++ = ch;
+               }
+             *np = '\0';
+           }  
+         else
+           name = de->d_name;
+
+         if (func (ds, name))
+           return closedir (dir);
+       }
+    }
+  return closedir (dir);
+}
 
 struct CHISE_Feature_Table
 {
@@ -207,11 +307,14 @@ chise_ft_close (CHISE_Feature_Table *table)
   return status;
 }
 
-static int
+int
 chise_feature_setup_db (CHISE_Feature feature, int writable)
 {
   u_int32_t access;
 
+  if (feature == NULL)
+    return -1;
+
   if (writable)
     {
       if ((feature->access & DB_CREATE) == 0)
@@ -233,8 +336,8 @@ chise_feature_setup_db (CHISE_Feature feature, int writable)
       CHISE_DS *ds = feature->ds;
 
       feature->db
-       = CHISE_Attribute_Table_open (ds->location,
-                                     "system-char-id", feature->name,
+       = CHISE_Attribute_Table_open (ds->location, "character",
+                                     "feature", feature->name,
                                      ds->subtype, access, ds->modemask);
       if (feature->db == NULL)
        return -1;
@@ -244,6 +347,35 @@ chise_feature_setup_db (CHISE_Feature feature, int writable)
 }
 
 int
+chise_feature_sync (CHISE_Feature feature)
+{
+  int status;
+
+  if (feature->db == NULL)
+    status = 0;
+  else
+    status = CHISE_Attribute_Table_close (feature->db);
+  feature->db = NULL;
+  feature->access = 0;
+  return status;
+}
+
+int
+chise_char_set_feature_value (CHISE_Char_ID cid,
+                             CHISE_Feature feature,
+                             unsigned char *value)
+{
+  unsigned char key_buf[8];
+
+  if (feature == NULL)
+    return -1;
+  if (chise_feature_setup_db (feature, 1))
+    return -1;
+  chise_format_char_id (cid, key_buf, 8);
+  return chise_attribute_table_put (feature->db, key_buf, value);
+}
+
+int
 chise_char_load_feature_value (CHISE_Char_ID cid,
                               CHISE_Feature_Table *table,
                               CHISE_Value *valdatum)
@@ -280,10 +412,10 @@ chise_char_gets_feature_value (CHISE_Char_ID cid,
 }
 
 int
-chise_char_feature_value_iterate (CHISE_Feature feature,
-                                 int (*func) (CHISE_Char_ID cid,
-                                              CHISE_Feature feature,
-                                              CHISE_Value *valdatum))
+chise_feature_foreach_char_with_value (CHISE_Feature feature,
+                                      int (*func) (CHISE_Char_ID cid,
+                                                   CHISE_Feature feature,
+                                                   CHISE_Value *valdatum))
 {
   DBT keydatum, valdatum;
   DBC *dbcp;
@@ -371,6 +503,45 @@ chise_ccst_close (CHISE_CCS_Table *table)
 }
 
 int
+chise_ccs_setup_db (CHISE_CCS ccs, int writable)
+{
+  u_int32_t access;
+
+  if (ccs == NULL)
+    return -1;
+
+  if (writable)
+    {
+      if ((ccs->access & DB_CREATE) == 0)
+       {
+         if (ccs->db != NULL)
+           {
+             CHISE_Attribute_Table_close (ccs->db);
+             ccs->db = NULL;
+           }
+         ccs->access = 0;
+       }
+      access = DB_CREATE;
+    }
+  else
+    access = DB_RDONLY;
+
+  if (ccs->db == NULL)
+    {
+      CHISE_DS *ds = ccs->ds;
+
+      ccs->db
+       = CHISE_Attribute_Table_open (ds->location, "character",
+                                     "by_feature", ccs->name,
+                                     ds->subtype, access, ds->modemask);
+      if (ccs->db == NULL)
+       return -1;
+      ccs->access = access;
+    }
+  return 0;
+}
+
+int
 chise_ccs_sync (CHISE_CCS ccs)
 {
   int status;
@@ -394,18 +565,8 @@ chise_ccs_decode (CHISE_CCS ccs, int code_point)
   if (ccs == NULL)
     return -1;
 
-  if (ccs->db == NULL)
-    {
-      CHISE_DS *ds = ccs->ds;
-
-      ccs->db = CHISE_Attribute_Table_open (ds->location,
-                                           ccs->name, "system-char-id",
-                                           ds->subtype,
-                                           DB_RDONLY, ds->modemask);
-      if (ccs->db == NULL)
-       return -1;
-      ccs->access = DB_RDONLY;
-    }
+  if (chise_ccs_setup_db (ccs, 0))
+    return -1;  
 
   sprintf(key_buf, "%d", code_point);
   status = chise_attribute_table_get (ccs->db, key_buf, &valdatum);
@@ -429,27 +590,8 @@ chise_ccs_set_decoded_char (CHISE_CCS ccs,
   if (ccs == NULL)
     return -1;
 
-  if ((ccs->access & DB_CREATE) == 0)
-    {
-      if (ccs->db != NULL)
-       {
-         CHISE_Attribute_Table_close (ccs->db);
-         ccs->db = NULL;
-       }
-      ccs->access = 0;
-    }
-  if (ccs->db == NULL)
-    {
-      CHISE_DS *ds = ccs->ds;
-
-      ccs->db
-       = CHISE_Attribute_Table_open (ds->location,
-                                     ccs->name, "system-char-id",
-                                     ds->subtype, DB_CREATE, ds->modemask);
-      if (ccs->db == NULL)
-       return -1;
-      ccs->access = DB_CREATE;
-    }
+  if (chise_ccs_setup_db (ccs, 1))
+    return -1;  
 
   sprintf(key_buf, "%d", code_point);
   chise_format_char_id (cid, val_buf, 8);
@@ -459,23 +601,28 @@ chise_ccs_set_decoded_char (CHISE_CCS ccs,
 
 CHISE_Attribute_Table*
 CHISE_Attribute_Table_open (const unsigned char *db_dir,
-                           const char *encoding, const char *feature,
+                           const char *category,
+                           const char *key_type, const char *name,
                            DBTYPE real_subtype,
                            u_int32_t accessmask, int modemask)
 {
   DB* dbase;
   int status;
-  int len, flen, i;
+  int len, name_len, i;
   int size;
   char *db_file_name, *sp;
+  struct stat statbuf;
 
   status = db_create (&dbase, NULL, 0);
   if (status)
     return NULL;
 
+  if ( (accessmask & DB_CREATE) && stat (db_dir, &statbuf) )
+    mkdir (db_dir, modemask);
+
   len = strlen (db_dir);
-  flen = strlen (feature);
-  size = len + strlen (encoding) + flen * 3 + 4;
+  name_len = strlen (name);
+  size = len + strlen (category) + strlen (key_type) + name_len * 3 + 5;
   db_file_name = alloca (size);
   strcpy (db_file_name, db_dir);
   if (db_file_name[len - 1] != '/')
@@ -483,13 +630,22 @@ CHISE_Attribute_Table_open (const unsigned char *db_dir,
       db_file_name[len++] = '/';
       db_file_name[len] = '\0';
     }
-  strcat (db_file_name, encoding);
+
+  strcat (db_file_name, category);
+  if ( (accessmask & DB_CREATE) && stat (db_file_name, &statbuf) )
+    mkdir (db_file_name, modemask);
   strcat (db_file_name, "/");
-  /* strcat (db_file_name, feature); */
+
+  strcat (db_file_name, key_type);
+  if ( (accessmask & DB_CREATE) && stat (db_file_name, &statbuf) )
+    mkdir (db_file_name, modemask);
+  strcat (db_file_name, "/");
+
+  /* strcat (db_file_name, name); */
   sp = &db_file_name[strlen (db_file_name)];
-  for (i = 0; i < flen; i++)
+  for (i = 0; i < name_len; i++)
     {
-      int c = feature[i];
+      int c = name[i];
 
       if ( (c == '/') || (c == '%') )
        {