update.
[chise/libchise.git] / chise.c
1 #ifdef HAVE_CONFIG_H
2 #  include "config.h"
3 #endif
4
5 #ifndef HAVE_STRNLEN
6 /* original in mysql, strings/strnlen.c.
7 uint strnlen(register const char *s, register uint maxlen)
8 {
9   const char *end= (const char *)memchr(s, '\0', maxlen);
10   return end ? (uint) (end - s) : maxlen;
11 }
12 */
13 static inline int
14 strnlen (register const char *s, register int maxlen)
15 {
16   const char *end= (const char *)memchr(s, '\0', maxlen);
17   return end ? (int) (end - s) : maxlen;
18 }
19 #endif
20
21 #include "chise.h"
22
23 #define xzero(lvalue) ((void) memset (&(lvalue), '\0', sizeof (lvalue)))
24
25 CHISE_Char_ID
26 chise_char_id_parse_c_string (unsigned char *str, int len)
27 {
28   int i = 0;
29
30   if ( (len >= 2) && (str[i++] == '?') )
31     {
32       unsigned char c = str[i++];
33       int counter;
34       CHISE_Char_ID cid;
35
36       if (c == '\\')
37         {
38           if (len < 3)
39             return -1;
40           c = str[i++];
41           if (c == '^')
42             {
43               if (len < 4)
44                 return -1;
45               c = str[i++];
46               if (c == '?')
47                 return 0x7F;
48               else
49                 return c & (0x80 | 0x1F);
50             }
51         }
52       if ( c < 0xC0 )
53         {
54           cid = c;
55           counter = 0;
56         }
57       else if ( c < 0xE0 )
58         {
59           cid = c & 0x1f;
60           counter = 1;
61         }
62       else if ( c < 0xF0 )
63         {
64           cid = c & 0x0f;
65           counter = 2;
66         }
67       else if ( c < 0xF8 )
68         {
69           cid = c & 0x07;
70           counter = 3;
71         }
72       else if ( c < 0xFC )
73         {
74           cid = c & 0x03;
75           counter = 4;
76         }
77       else
78         {
79           cid = c & 0x01;
80           counter = 5;
81         }
82
83       if (counter + 2 <= len)
84         {
85           int j;
86
87           for (j = 0; j < counter; j++)
88             cid = (cid << 6) | (str[j + i] & 0x3F);
89           return cid;
90         }
91     }
92   return -1;
93 }
94
95 int
96 chise_format_char_id (CHISE_Char_ID cid, unsigned char *dest, int len)
97 {
98   int i = 0;
99
100   dest[i++] = '?';
101   if (cid == '\t')
102     {
103       dest[i++] = '\\';
104       dest[i++] = 't';
105       dest[i] = '\0';
106       return i;
107     }
108   else if (cid == '\n')
109     {
110       dest[i++] = '\\';
111       dest[i++] = 'n';
112       dest[i] = '\0';
113       return i;
114     }
115   else if (cid == '\r')
116     {
117       dest[i++] = '\\';
118       dest[i++] = 'r';
119       dest[i] = '\0';
120       return i;
121     }
122   else if (cid == 0x1C)
123     {
124       dest[i++] = '\\';
125       dest[i++] = '^';
126       dest[i++] = '\\';
127       dest[i++] = '\\';
128       dest[i] = '\0';
129       return i;
130     }
131   else if (cid <= 0x1F)
132     {
133       dest[i++] = '\\';
134       dest[i++] = '^';
135       dest[i++] = '@' + cid;
136       dest[i] = '\0';
137       return i;
138     }
139   else if ( (cid == ' ') || (cid == '"') ||
140             (cid == '#') || (cid == '\'') ||
141             (cid == '(') || (cid == ')') ||
142             (cid == ',') || (cid == '.') ||
143             (cid == ';') || (cid == '?') ||
144             (cid == '[') || (cid == '\\') ||
145             (cid == ']') || (cid == '`') )
146     {
147       dest[i++] = '\\';
148       dest[i++] = cid;
149       dest[i] = '\0';
150       return i;
151     }
152   else if (cid <= 0x7E)
153     {
154       dest[i++] = cid;
155       dest[i] = '\0';
156       return i;
157     }
158   else if (cid == 0x7F)
159     {
160       dest[i++] = '\\';
161       dest[i++] = '^';
162       dest[i++] = '?';
163       dest[i] = '\0';
164       return i;
165     }
166   else if (cid <= 0x9F)
167     {
168       dest[i++] = '\\';
169       dest[i++] = '^';
170       dest[i++] = ((cid + '@') >> 6) | 0xC0;
171       dest[i++] = ((cid + '@') & 0x3F) | 0x80;
172       dest[i] = '\0';
173       return i;
174     }
175   else if (cid <= 0x7FF)
176     {
177       dest[i++] = (cid >> 6) | 0xC0;
178       dest[i++] = (cid & 0x3F) | 0x80;
179       dest[i] = '\0';
180       return i;
181     }
182   else if (cid <= 0xFFFF)
183     {
184       dest[i++] = (cid >> 12) | 0xE0;
185       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
186       dest[i++]=  (cid        & 0x3F) | 0x80;
187       dest[i] = '\0';
188       return i;
189     }
190   else if (cid <= 0x1FFFFF)
191     {
192       dest[i++]=  (cid >> 18) | 0xF0;
193       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
194       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
195       dest[i++]=  (cid        & 0x3F) | 0x80;
196       dest[i] = '\0';
197       return i;
198     }
199   else if (cid <= 0x3FFFFFF)
200     {
201       dest[i++]=  (cid >> 24) | 0xF8;
202       dest[i++]= ((cid >> 18) & 0x3F) | 0x80;
203       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
204       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
205       dest[i++]=  (cid        & 0x3F) | 0x80;
206       dest[i] = '\0';
207       return i;
208     }
209   else
210     {
211       dest[i++]=  (cid >> 30) | 0xFC;
212       dest[i++]= ((cid >> 24) & 0x3F) | 0x80;
213       dest[i++]= ((cid >> 18) & 0x3F) | 0x80;
214       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
215       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
216       dest[i++]=  (cid        & 0x3F) | 0x80;
217       dest[i] = '\0';
218       return i;
219     }
220 }
221
222 CHISE_DS*
223 chise_open_data_source (CHISE_DS_Type type, char *location)
224 {
225   CHISE_DS *ds = (CHISE_DS*)malloc (sizeof (CHISE_DS));
226   size_t len = strlen (location);
227
228   if (ds == NULL)
229     return NULL;
230
231   ds->type = type;
232   ds->location = (unsigned char*)malloc (len + 1);
233   if (ds->location == NULL)
234     {
235       free (ds);
236       return NULL;
237     }
238   strcpy (ds->location, location);
239   return ds;
240 }
241
242 int
243 chise_ds_close (CHISE_DS *ds)
244 {
245   if (ds->location != NULL)
246     free (ds->location);
247   free (ds);
248   return 0;
249 }
250
251
252 CHISE_Decoding_Table*
253 chise_ds_open_decoding_table (CHISE_DS *ds, const char *ccs,
254                               DBTYPE real_subtype,
255                               u_int32_t accessmask, int modemask)
256 {
257   return
258     chise_open_attribute_table (ds,
259                                 ccs, "system-char-id",
260                                 real_subtype, accessmask, modemask);
261 }
262
263 int
264 chise_dt_close (CHISE_Decoding_Table *table)
265 {
266   if (table)
267     return chise_close_attribute_table (table);
268   return -1;
269 }
270
271 CHISE_Char_ID
272 chise_dt_get_char (CHISE_Decoding_Table *table, int code_point)
273 {
274   CHISE_Value valdatum;
275   int status = 0;
276   char key_buf[16];
277
278   sprintf(key_buf, "%d", code_point);
279   status = chise_get_attribute_table (table, key_buf, &valdatum);
280   if (!status)
281     {
282       unsigned char *str
283         = (unsigned char *)chise_value_data (&valdatum);
284       int len = strnlen (str, chise_value_size (&valdatum));
285
286       return chise_char_id_parse_c_string (str, len);
287     }
288   return -1;
289 }
290
291 int
292 chise_dt_put_char (CHISE_Decoding_Table *table,
293                    int code_point, CHISE_Char_ID cid)
294 {
295   CHISE_Value valdatum;
296   char key_buf[16], val_buf[8];
297
298   sprintf(key_buf, "%d", code_point);
299   chise_format_char_id (cid, val_buf, 8);
300   return chise_put_attribute_table (table, key_buf, val_buf);
301 }
302
303
304
305 CHISE_Feature_Table*
306 chise_ds_open_feature_table (CHISE_DS *ds, const char *feature,
307                              DBTYPE real_subtype,
308                              u_int32_t accessmask, int modemask)
309 {
310   return
311     chise_open_attribute_table (ds,
312                                 "system-char-id", feature,
313                                 real_subtype, accessmask, modemask);
314 }
315
316 int
317 chise_ft_close (CHISE_Feature_Table *table)
318 {
319   if (table)
320     return chise_close_attribute_table (table);
321   return -1;
322 }
323
324 int
325 chise_ft_get_value (CHISE_Feature_Table *table,
326                     CHISE_Char_ID cid, CHISE_Value *valdatum)
327 {
328   unsigned char key_buf[8];
329
330   chise_format_char_id (cid, key_buf, 8);
331   return chise_get_attribute_table (table, key_buf, valdatum);
332 }
333
334 void
335 chise_ft_iterate (CHISE_Feature_Table *table,
336                   int (*func) (CHISE_Feature_Table *table,
337                                CHISE_Char_ID cid, CHISE_Value *valdatum))
338 {
339   DBT keydatum, valdatum;
340   DBC *dbcp;
341   int status;
342
343   xzero (keydatum);
344   xzero (valdatum);
345
346   status = table->db->cursor (table->db, NULL, &dbcp, 0);
347   for (status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_FIRST);
348        status == 0;
349        status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_NEXT))
350     {
351       unsigned char *key_str = (unsigned char *)keydatum.data;
352       int key_len = strnlen (key_str, keydatum.size);
353       CHISE_Char_ID key = chise_char_id_parse_c_string (key_str, key_len);
354       int ret;
355
356       if (ret = func (table, key, &valdatum))
357         break;
358     }
359   dbcp->c_close (dbcp);
360 }
361
362 CHISE_Attribute_Table*
363 chise_open_attribute_table (CHISE_DS *ds,
364                             const char *encoding, const char *feature,
365                             DBTYPE real_subtype,
366                             u_int32_t accessmask, int modemask)
367 {
368   CHISE_Attribute_Table* table;
369   char *db_dir;
370   DB* dbase;
371   int status;
372   int len, flen, i;
373   int size;
374   char *db_file_name, *sp;
375
376   if (ds == NULL)
377     return NULL;
378
379   table = (CHISE_Attribute_Table*)malloc (sizeof (CHISE_Attribute_Table));
380   if (table == NULL)
381     return NULL;
382
383   table->ds = ds;
384
385   status = db_create (&dbase, NULL, 0);
386   if (status)
387     {
388       free (table);
389       return NULL;
390     }
391
392   db_dir = ds->location;
393   len = strlen (db_dir);
394   flen = strlen (feature);
395   size = len + strlen (encoding) + flen * 3 + 4;
396   db_file_name = alloca (size);
397   strcpy (db_file_name, db_dir);
398   if (db_file_name[len - 1] != '/')
399     {
400       db_file_name[len++] = '/';
401       db_file_name[len] = '\0';
402     }
403   strcat (db_file_name, encoding);
404   strcat (db_file_name, "/");
405   /* strcat (db_file_name, feature); */
406   sp = &db_file_name[strlen (db_file_name)];
407   for (i = 0; i < flen; i++)
408     {
409       int c = feature[i];
410
411       if ( (c == '/') || (c == '%') )
412         {
413           sprintf (sp, "%%%02X", c);
414           sp += 3;
415         }
416       else
417         *sp++ = c;
418     }
419   *sp = '\0';
420   status = dbase->open (dbase, db_file_name, NULL,
421                         real_subtype, accessmask, modemask);
422   if (status)
423     {
424       dbase->close (dbase, 0);
425       free (table);
426       return NULL;
427     }
428   table->db = dbase;
429   return table;
430 }
431
432 int
433 chise_close_attribute_table (CHISE_Attribute_Table *table)
434 {
435   if (table->db)
436     {
437       table->db->sync  (table->db, 0);
438       table->db->close (table->db, 0);
439     }
440   free (table);
441   return 0;
442 }
443
444 int
445 chise_get_attribute_table (CHISE_Attribute_Table *table,
446                            char *key, CHISE_Value *valdatum)
447 {
448   DBT keydatum;
449   int status = 0;
450
451   /* DB Version 2 requires DBT's to be zeroed before use. */
452   xzero (keydatum);
453   xzero (*valdatum);
454
455   keydatum.data = key;
456   keydatum.size = strlen (key);
457
458   status = table->db->get (table->db, NULL, &keydatum, valdatum, 0);
459   return status;
460 }
461
462 int
463 chise_put_attribute_table (CHISE_Attribute_Table *table,
464                            char *key, char *value)
465 {
466   DBT keydatum, valdatum;
467   int status = 0;
468
469   /* DB Version 2 requires DBT's to be zeroed before use. */
470   xzero (keydatum);
471   xzero (valdatum);
472
473   keydatum.data = key;
474   keydatum.size = strlen (key);
475
476   valdatum.data = value;
477   valdatum.size = strlen (value);
478
479   status = table->db->put (table->db, NULL, &keydatum, &valdatum, 0);
480   return status;
481 }