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