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