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