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