(chise_ft_get_value): Use escape forms for some special characters.
[chise/libchise.git] / chise.c
diff --git a/chise.c b/chise.c
index 4c790e1..3397991 100644 (file)
--- a/chise.c
+++ b/chise.c
@@ -1,3 +1,23 @@
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#ifndef HAVE_STRNLEN
+/* original in mysql, strings/strnlen.c.
+uint strnlen(register const char *s, register uint maxlen)
+{
+  const char *end= (const char *)memchr(s, '\0', maxlen);
+  return end ? (uint) (end - s) : maxlen;
+}
+*/
+static inline int
+strnlen (register const char *s, register int maxlen)
+{
+  const char *end= (const char *)memchr(s, '\0', maxlen);
+  return end ? (int) (end - s) : maxlen;
+}
+#endif
+
 #include "chise.h"
 
 #define xzero(lvalue) ((void) memset (&(lvalue), '\0', sizeof (lvalue)))
@@ -52,8 +72,8 @@ chise_dt_get_char (CHISE_Decoding_Table *db, int code_point)
   if (!status)
     {
       unsigned char *str
-       = (unsigned char *)chise_value_to_c_string (&valdatum);
-      int len = strlen (str);
+       = (unsigned char *)chise_value_data (&valdatum);
+      int len = strnlen (str, chise_value_size (&valdatum));
       int i = 0;
 
       if ( (len >= 2) && (str[i++] == '?') )
@@ -67,6 +87,16 @@ chise_dt_get_char (CHISE_Decoding_Table *db, int code_point)
              if (len < 3)
                return -1;
              c = str[i++];
+             if (c == '^')
+               {
+                 if (len < 4)
+                   return -1;
+                 c = str[i++];
+                 if (c == '?')
+                   return 0x7F;
+                 else
+                   return c & (0x80 | 0x1F);
+               }
            }
          if ( c < 0xC0 )
            {
@@ -140,49 +170,110 @@ int chise_ft_get_value (CHISE_Feature_Table *db,
   unsigned char key_buf[8];
 
   key_buf[0] = '?';
-  if (cid <= 0x7f)
+  if (cid == '\t')
+    {
+      key_buf[1] = '\\';
+      key_buf[2] = 't';
+      key_buf[3] = '\0';
+    }
+  else if (cid == '\n')
+    {
+      key_buf[1] = '\\';
+      key_buf[2] = 'n';
+      key_buf[3] = '\0';
+    }
+  else if (cid == '\r')
+    {
+      key_buf[1] = '\\';
+      key_buf[2] = 'r';
+      key_buf[3] = '\0';
+    }
+  else if (cid == 0x1C)
+    {
+      key_buf[1] = '\\';
+      key_buf[2] = '^';
+      key_buf[3] = '\\';
+      key_buf[4] = '\\';
+      key_buf[5] = '\0';
+    }
+  else if (cid <= 0x1F)
+    {
+      key_buf[1] = '\\';
+      key_buf[2] = '^';
+      key_buf[3] = '@' + cid;
+      key_buf[4] = '\0';
+    }
+  else if ( (cid == ' ') || (cid == '"') ||
+           (cid == '#') || (cid == '\'') ||
+           (cid == '(') || (cid == ')') ||
+           (cid == ',') || (cid == '.') ||
+           (cid == ';') || (cid == '?') ||
+           (cid == '[') || (cid == '\\') ||
+           (cid == ']') || (cid == '`') )
+    {
+      key_buf[1] = '\\';
+      key_buf[2] = cid;
+      key_buf[3] = '\0';
+    }
+  else if (cid <= 0x7E)
     {
       key_buf[1] = cid;
       key_buf[2] = '\0';
     }
-  else if (cid <= 0x7ff)
+  else if (cid == 0x7F)
+    {
+      key_buf[1] = '\\';
+      key_buf[2] = '^';
+      key_buf[3] = '?';
+      key_buf[4] = '\0';
+    }
+  else if (cid <= 0x9F)
     {
-      key_buf[1] = (cid >> 6) | 0xc0;
-      key_buf[2] = (cid & 0x3f) | 0x80;
+      key_buf[1] = '\\';
+      key_buf[2] = '^';
+      key_buf[3] = ((cid + '@') >> 6) | 0xC0;
+      key_buf[4] = ((cid + '@') & 0x3F) | 0x80;
+      key_buf[5] = '\0';
+
+    }
+  else if (cid <= 0x7FF)
+    {
+      key_buf[1] = (cid >> 6) | 0xC0;
+      key_buf[2] = (cid & 0x3F) | 0x80;
       key_buf[3] = '\0';
     }
-  else if (cid <= 0xffff)
+  else if (cid <= 0xFFFF)
     {
-      key_buf[1] = (cid >> 12) | 0xe0;
-      key_buf[2]= ((cid >>  6) & 0x3f) | 0x80;
-      key_buf[3]=  (cid        & 0x3f) | 0x80;
+      key_buf[1] = (cid >> 12) | 0xE0;
+      key_buf[2]= ((cid >>  6) & 0x3F) | 0x80;
+      key_buf[3]=  (cid        & 0x3F) | 0x80;
       key_buf[4] = '\0';
     }
-  else if (cid <= 0x1fffff)
+  else if (cid <= 0x1FFFFF)
     {
-      key_buf[1]=  (cid >> 18) | 0xf0;
-      key_buf[2]= ((cid >> 12) & 0x3f) | 0x80;
-      key_buf[3]= ((cid >>  6) & 0x3f) | 0x80;
-      key_buf[4]=  (cid        & 0x3f) | 0x80;
+      key_buf[1]=  (cid >> 18) | 0xF0;
+      key_buf[2]= ((cid >> 12) & 0x3F) | 0x80;
+      key_buf[3]= ((cid >>  6) & 0x3F) | 0x80;
+      key_buf[4]=  (cid        & 0x3F) | 0x80;
       key_buf[5] = '\0';
     }
-  else if (cid <= 0x3ffffff)
+  else if (cid <= 0x3FFFFFF)
     {
-      key_buf[1]=  (cid >> 24) | 0xf8;
-      key_buf[2]= ((cid >> 18) & 0x3f) | 0x80;
-      key_buf[3]= ((cid >> 12) & 0x3f) | 0x80;
-      key_buf[4]= ((cid >>  6) & 0x3f) | 0x80;
-      key_buf[5]=  (cid        & 0x3f) | 0x80;
+      key_buf[1]=  (cid >> 24) | 0xF8;
+      key_buf[2]= ((cid >> 18) & 0x3F) | 0x80;
+      key_buf[3]= ((cid >> 12) & 0x3F) | 0x80;
+      key_buf[4]= ((cid >>  6) & 0x3F) | 0x80;
+      key_buf[5]=  (cid        & 0x3F) | 0x80;
       key_buf[6] = '\0';
     }
   else
     {
-      key_buf[1]=  (cid >> 30) | 0xfc;
-      key_buf[2]= ((cid >> 24) & 0x3f) | 0x80;
-      key_buf[3]= ((cid >> 18) & 0x3f) | 0x80;
-      key_buf[4]= ((cid >> 12) & 0x3f) | 0x80;
-      key_buf[5]= ((cid >>  6) & 0x3f) | 0x80;
-      key_buf[6]=  (cid        & 0x3f) | 0x80;
+      key_buf[1]=  (cid >> 30) | 0xFC;
+      key_buf[2]= ((cid >> 24) & 0x3F) | 0x80;
+      key_buf[3]= ((cid >> 18) & 0x3F) | 0x80;
+      key_buf[4]= ((cid >> 12) & 0x3F) | 0x80;
+      key_buf[5]= ((cid >>  6) & 0x3F) | 0x80;
+      key_buf[6]=  (cid        & 0x3F) | 0x80;
       key_buf[7] = '\0';
     }
   return
@@ -199,16 +290,17 @@ chise_open_attribute_table (CHISE_Attribute_Table **db,
 {
   DB* dbase;
   int status;
-  int len;
+  int len, flen, i;
   int size;
-  char *db_file_name;
+  char *db_file_name, *sp;
 
   status = db_create (&dbase, NULL, 0);
   if (status)
     return -1;
 
   len = strlen (db_dir);
-  size = len + strlen (encoding) + strlen (feature) + 4;
+  flen = strlen (feature);
+  size = len + strlen (encoding) + flen * 3 + 4;
   db_file_name = alloca (size);
   strcpy (db_file_name, db_dir);
   if (db_file_name[len - 1] != '/')
@@ -218,7 +310,21 @@ chise_open_attribute_table (CHISE_Attribute_Table **db,
     }
   strcat (db_file_name, encoding);
   strcat (db_file_name, "/");
-  strcat (db_file_name, feature);
+  /* strcat (db_file_name, feature); */
+  sp = &db_file_name[strlen (db_file_name)];
+  for (i = 0; i < flen; i++)
+    {
+      int c = feature[i];
+
+      if ( (c == '/') || (c == '%') )
+       {
+         sprintf (sp, "%%%02X", c);
+         sp += 3;
+       }
+      else
+       *sp++ = c;
+    }
+  *sp = '\0';
   status = dbase->open (dbase, db_file_name, NULL,
                        real_subtype, accessmask, modemask);
   if (status)