(struct CHISE_DS): Definition of members are 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 #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
223 struct CHISE_DS
224 {
225   CHISE_DS_Type type;
226   unsigned char *location;
227 };
228
229 CHISE_DS*
230 chise_open_data_source (CHISE_DS_Type type, char *location)
231 {
232   CHISE_DS *ds = (CHISE_DS*)malloc (sizeof (CHISE_DS));
233   size_t len = strlen (location);
234
235   if (ds == NULL)
236     return NULL;
237
238   ds->type = type;
239   ds->location = (unsigned char*)malloc (len + 1);
240   if (ds->location == NULL)
241     {
242       free (ds);
243       return NULL;
244     }
245   strcpy (ds->location, location);
246   return ds;
247 }
248
249 int
250 chise_ds_close (CHISE_DS *ds)
251 {
252   if (ds->location != NULL)
253     free (ds->location);
254   free (ds);
255   return 0;
256 }
257
258
259 CHISE_Decoding_Table*
260 chise_ds_open_decoding_table (CHISE_DS *ds, const char *ccs,
261                               DBTYPE real_subtype,
262                               u_int32_t accessmask, int modemask)
263 {
264   return
265     chise_open_attribute_table (ds,
266                                 ccs, "system-char-id",
267                                 real_subtype, accessmask, modemask);
268 }
269
270 int
271 chise_dt_close (CHISE_Decoding_Table *table)
272 {
273   if (table)
274     return chise_close_attribute_table (table);
275   return -1;
276 }
277
278 CHISE_Char_ID
279 chise_dt_get_char (CHISE_Decoding_Table *table, int code_point)
280 {
281   CHISE_Value valdatum;
282   int status = 0;
283   char key_buf[16];
284
285   sprintf(key_buf, "%d", code_point);
286   status = chise_get_attribute_table (table, key_buf, &valdatum);
287   if (!status)
288     {
289       unsigned char *str
290         = (unsigned char *)chise_value_data (&valdatum);
291       int len = strnlen (str, chise_value_size (&valdatum));
292
293       return chise_char_id_parse_c_string (str, len);
294     }
295   return -1;
296 }
297
298 int
299 chise_dt_put_char (CHISE_Decoding_Table *table,
300                    int code_point, CHISE_Char_ID cid)
301 {
302   CHISE_Value valdatum;
303   char key_buf[16], val_buf[8];
304
305   sprintf(key_buf, "%d", code_point);
306   chise_format_char_id (cid, val_buf, 8);
307   return chise_put_attribute_table (table, key_buf, val_buf);
308 }
309
310
311
312 CHISE_Feature_Table*
313 chise_ds_open_feature_table (CHISE_DS *ds, const char *feature,
314                              DBTYPE real_subtype,
315                              u_int32_t accessmask, int modemask)
316 {
317   return
318     chise_open_attribute_table (ds,
319                                 "system-char-id", feature,
320                                 real_subtype, accessmask, modemask);
321 }
322
323 int
324 chise_ft_close (CHISE_Feature_Table *table)
325 {
326   if (table)
327     return chise_close_attribute_table (table);
328   return -1;
329 }
330
331 int
332 chise_ft_get_value (CHISE_Feature_Table *table,
333                     CHISE_Char_ID cid, CHISE_Value *valdatum)
334 {
335   unsigned char key_buf[8];
336
337   chise_format_char_id (cid, key_buf, 8);
338   return chise_get_attribute_table (table, key_buf, valdatum);
339 }
340
341 void
342 chise_ft_iterate (CHISE_Feature_Table *table,
343                   int (*func) (CHISE_Feature_Table *table,
344                                CHISE_Char_ID cid, CHISE_Value *valdatum))
345 {
346   DBT keydatum, valdatum;
347   DBC *dbcp;
348   int status;
349
350   xzero (keydatum);
351   xzero (valdatum);
352
353   status = table->db->cursor (table->db, NULL, &dbcp, 0);
354   for (status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_FIRST);
355        status == 0;
356        status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_NEXT))
357     {
358       unsigned char *key_str = (unsigned char *)keydatum.data;
359       int key_len = strnlen (key_str, keydatum.size);
360       CHISE_Char_ID key = chise_char_id_parse_c_string (key_str, key_len);
361       int ret;
362
363       if (ret = func (table, key, &valdatum))
364         break;
365     }
366   dbcp->c_close (dbcp);
367 }
368
369 CHISE_Attribute_Table*
370 chise_open_attribute_table (CHISE_DS *ds,
371                             const char *encoding, const char *feature,
372                             DBTYPE real_subtype,
373                             u_int32_t accessmask, int modemask)
374 {
375   CHISE_Attribute_Table* table;
376   char *db_dir;
377   DB* dbase;
378   int status;
379   int len, flen, i;
380   int size;
381   char *db_file_name, *sp;
382
383   if (ds == NULL)
384     return NULL;
385
386   table = (CHISE_Attribute_Table*)malloc (sizeof (CHISE_Attribute_Table));
387   if (table == NULL)
388     return NULL;
389
390   table->ds = ds;
391
392   status = db_create (&dbase, NULL, 0);
393   if (status)
394     {
395       free (table);
396       return NULL;
397     }
398
399   db_dir = ds->location;
400   len = strlen (db_dir);
401   flen = strlen (feature);
402   size = len + strlen (encoding) + flen * 3 + 4;
403   db_file_name = alloca (size);
404   strcpy (db_file_name, db_dir);
405   if (db_file_name[len - 1] != '/')
406     {
407       db_file_name[len++] = '/';
408       db_file_name[len] = '\0';
409     }
410   strcat (db_file_name, encoding);
411   strcat (db_file_name, "/");
412   /* strcat (db_file_name, feature); */
413   sp = &db_file_name[strlen (db_file_name)];
414   for (i = 0; i < flen; i++)
415     {
416       int c = feature[i];
417
418       if ( (c == '/') || (c == '%') )
419         {
420           sprintf (sp, "%%%02X", c);
421           sp += 3;
422         }
423       else
424         *sp++ = c;
425     }
426   *sp = '\0';
427   status = dbase->open (dbase, db_file_name, NULL,
428                         real_subtype, accessmask, modemask);
429   if (status)
430     {
431       dbase->close (dbase, 0);
432       free (table);
433       return NULL;
434     }
435   table->db = dbase;
436   return table;
437 }
438
439 int
440 chise_close_attribute_table (CHISE_Attribute_Table *table)
441 {
442   if (table->db)
443     {
444       table->db->sync  (table->db, 0);
445       table->db->close (table->db, 0);
446     }
447   free (table);
448   return 0;
449 }
450
451 int
452 chise_get_attribute_table (CHISE_Attribute_Table *table,
453                            char *key, CHISE_Value *valdatum)
454 {
455   DBT keydatum;
456   int status = 0;
457
458   /* DB Version 2 requires DBT's to be zeroed before use. */
459   xzero (keydatum);
460   xzero (*valdatum);
461
462   keydatum.data = key;
463   keydatum.size = strlen (key);
464
465   status = table->db->get (table->db, NULL, &keydatum, valdatum, 0);
466   return status;
467 }
468
469 int
470 chise_put_attribute_table (CHISE_Attribute_Table *table,
471                            char *key, char *value)
472 {
473   DBT keydatum, valdatum;
474   int status = 0;
475
476   /* DB Version 2 requires DBT's to be zeroed before use. */
477   xzero (keydatum);
478   xzero (valdatum);
479
480   keydatum.data = key;
481   keydatum.size = strlen (key);
482
483   valdatum.data = value;
484   valdatum.size = strlen (value);
485
486   status = table->db->put (table->db, NULL, &keydatum, &valdatum, 0);
487   return status;
488 }