(chise_char_id_parse_c_string): New function.
[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_open_data_source (CHISE_DS *ds, CHISE_DS_Type type, char *location)
97 {
98   ds->type = type;
99   ds->location = location;
100   return 0;
101 }
102
103 int
104 chise_close_data_source (CHISE_DS *ds)
105 {
106   ds->type = CHISE_DS_NONE;
107   ds->location = NULL;
108   return 0;
109 }
110
111
112 int
113 chise_open_decoding_table (CHISE_Decoding_Table **db,
114                            CHISE_DS *ds, const char *ccs,
115                            DBTYPE real_subtype,
116                            u_int32_t accessmask, int modemask)
117 {
118   return
119     chise_open_attribute_table (db, ds->location,
120                                 ccs, "system-char-id",
121                                 real_subtype, accessmask, modemask);
122 }
123
124 int
125 chise_close_decoding_table (CHISE_Decoding_Table *db)
126 {
127   if (db)
128     return chise_close_attribute_table (db);
129   return -1;
130 }
131
132 CHISE_Char_ID
133 chise_dt_get_char (CHISE_Decoding_Table *db, int code_point)
134 {
135   CHISE_Value valdatum;
136   int status = 0;
137   char key_buf[16];
138
139   sprintf(key_buf, "%d", code_point);
140   status = chise_get_attribute_table (db, key_buf, &valdatum);
141   if (!status)
142     {
143       unsigned char *str
144         = (unsigned char *)chise_value_data (&valdatum);
145       int len = strnlen (str, chise_value_size (&valdatum));
146
147       return chise_char_id_parse_c_string (str, len);
148     }
149   return -1;
150 }
151
152
153
154 int
155 chise_open_feature_table (CHISE_Feature_Table **db,
156                           CHISE_DS *ds, const char *feature,
157                           DBTYPE real_subtype,
158                           u_int32_t accessmask, int modemask)
159 {
160   return
161     chise_open_attribute_table (db, ds->location,
162                                 "system-char-id", feature,
163                                 real_subtype, accessmask, modemask);
164 }
165
166 int
167 chise_close_feature_table (CHISE_Feature_Table *db)
168 {
169   if (db)
170     return chise_close_attribute_table (db);
171   return -1;
172 }
173
174 int chise_ft_get_value (CHISE_Feature_Table *db,
175                         CHISE_Char_ID cid, CHISE_Value *valdatum)
176 {
177   unsigned char key_buf[8];
178
179   key_buf[0] = '?';
180   if (cid == '\t')
181     {
182       key_buf[1] = '\\';
183       key_buf[2] = 't';
184       key_buf[3] = '\0';
185     }
186   else if (cid == '\n')
187     {
188       key_buf[1] = '\\';
189       key_buf[2] = 'n';
190       key_buf[3] = '\0';
191     }
192   else if (cid == '\r')
193     {
194       key_buf[1] = '\\';
195       key_buf[2] = 'r';
196       key_buf[3] = '\0';
197     }
198   else if (cid == 0x1C)
199     {
200       key_buf[1] = '\\';
201       key_buf[2] = '^';
202       key_buf[3] = '\\';
203       key_buf[4] = '\\';
204       key_buf[5] = '\0';
205     }
206   else if (cid <= 0x1F)
207     {
208       key_buf[1] = '\\';
209       key_buf[2] = '^';
210       key_buf[3] = '@' + cid;
211       key_buf[4] = '\0';
212     }
213   else if ( (cid == ' ') || (cid == '"') ||
214             (cid == '#') || (cid == '\'') ||
215             (cid == '(') || (cid == ')') ||
216             (cid == ',') || (cid == '.') ||
217             (cid == ';') || (cid == '?') ||
218             (cid == '[') || (cid == '\\') ||
219             (cid == ']') || (cid == '`') )
220     {
221       key_buf[1] = '\\';
222       key_buf[2] = cid;
223       key_buf[3] = '\0';
224     }
225   else if (cid <= 0x7E)
226     {
227       key_buf[1] = cid;
228       key_buf[2] = '\0';
229     }
230   else if (cid == 0x7F)
231     {
232       key_buf[1] = '\\';
233       key_buf[2] = '^';
234       key_buf[3] = '?';
235       key_buf[4] = '\0';
236     }
237   else if (cid <= 0x9F)
238     {
239       key_buf[1] = '\\';
240       key_buf[2] = '^';
241       key_buf[3] = ((cid + '@') >> 6) | 0xC0;
242       key_buf[4] = ((cid + '@') & 0x3F) | 0x80;
243       key_buf[5] = '\0';
244
245     }
246   else if (cid <= 0x7FF)
247     {
248       key_buf[1] = (cid >> 6) | 0xC0;
249       key_buf[2] = (cid & 0x3F) | 0x80;
250       key_buf[3] = '\0';
251     }
252   else if (cid <= 0xFFFF)
253     {
254       key_buf[1] = (cid >> 12) | 0xE0;
255       key_buf[2]= ((cid >>  6) & 0x3F) | 0x80;
256       key_buf[3]=  (cid        & 0x3F) | 0x80;
257       key_buf[4] = '\0';
258     }
259   else if (cid <= 0x1FFFFF)
260     {
261       key_buf[1]=  (cid >> 18) | 0xF0;
262       key_buf[2]= ((cid >> 12) & 0x3F) | 0x80;
263       key_buf[3]= ((cid >>  6) & 0x3F) | 0x80;
264       key_buf[4]=  (cid        & 0x3F) | 0x80;
265       key_buf[5] = '\0';
266     }
267   else if (cid <= 0x3FFFFFF)
268     {
269       key_buf[1]=  (cid >> 24) | 0xF8;
270       key_buf[2]= ((cid >> 18) & 0x3F) | 0x80;
271       key_buf[3]= ((cid >> 12) & 0x3F) | 0x80;
272       key_buf[4]= ((cid >>  6) & 0x3F) | 0x80;
273       key_buf[5]=  (cid        & 0x3F) | 0x80;
274       key_buf[6] = '\0';
275     }
276   else
277     {
278       key_buf[1]=  (cid >> 30) | 0xFC;
279       key_buf[2]= ((cid >> 24) & 0x3F) | 0x80;
280       key_buf[3]= ((cid >> 18) & 0x3F) | 0x80;
281       key_buf[4]= ((cid >> 12) & 0x3F) | 0x80;
282       key_buf[5]= ((cid >>  6) & 0x3F) | 0x80;
283       key_buf[6]=  (cid        & 0x3F) | 0x80;
284       key_buf[7] = '\0';
285     }
286   return
287     chise_get_attribute_table (db, key_buf, valdatum);
288 }
289
290 void
291 chise_ft_iterate (CHISE_Feature_Table *dbp,
292                   int (*func) (CHISE_Feature_Table *db,
293                                CHISE_Char_ID cid, CHISE_Value *valdatum))
294 {
295   DBT keydatum, valdatum;
296   DBC *dbcp;
297   int status;
298
299   xzero (keydatum);
300   xzero (valdatum);
301
302   status = dbp->cursor (dbp, NULL, &dbcp, 0);
303   for (status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_FIRST);
304        status == 0;
305        status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_NEXT))
306     {
307       unsigned char *key_str = (unsigned char *)keydatum.data;
308       int key_len = strnlen (key_str, keydatum.size);
309       CHISE_Char_ID key = chise_char_id_parse_c_string (key_str, key_len);
310       int ret;
311
312       if (ret = func (dbp, key, &valdatum))
313         break;
314     }
315   dbcp->c_close (dbcp);
316 }
317
318 int
319 chise_open_attribute_table (CHISE_Attribute_Table **db,
320                             const char *db_dir,
321                             const char *encoding, const char *feature,
322                             DBTYPE real_subtype,
323                             u_int32_t accessmask, int modemask)
324 {
325   DB* dbase;
326   int status;
327   int len, flen, i;
328   int size;
329   char *db_file_name, *sp;
330
331   status = db_create (&dbase, NULL, 0);
332   if (status)
333     return -1;
334
335   len = strlen (db_dir);
336   flen = strlen (feature);
337   size = len + strlen (encoding) + flen * 3 + 4;
338   db_file_name = alloca (size);
339   strcpy (db_file_name, db_dir);
340   if (db_file_name[len - 1] != '/')
341     {
342       db_file_name[len++] = '/';
343       db_file_name[len] = '\0';
344     }
345   strcat (db_file_name, encoding);
346   strcat (db_file_name, "/");
347   /* strcat (db_file_name, feature); */
348   sp = &db_file_name[strlen (db_file_name)];
349   for (i = 0; i < flen; i++)
350     {
351       int c = feature[i];
352
353       if ( (c == '/') || (c == '%') )
354         {
355           sprintf (sp, "%%%02X", c);
356           sp += 3;
357         }
358       else
359         *sp++ = c;
360     }
361   *sp = '\0';
362   status = dbase->open (dbase, db_file_name, NULL,
363                         real_subtype, accessmask, modemask);
364   if (status)
365     {
366       dbase->close (dbase, 0);
367       return -1;
368     }
369   *db = dbase;
370   return 0;
371 }
372
373 int
374 chise_close_attribute_table (CHISE_Attribute_Table *db)
375 {
376   if (db)
377     {
378       db->sync  (db, 0);
379       db->close (db, 0);
380     }
381   return 0;
382 }
383
384 int
385 chise_get_attribute_table (CHISE_Attribute_Table *db,
386                            char *key, CHISE_Value *valdatum)
387 {
388   DBT keydatum;
389   int status = 0;
390
391   /* DB Version 2 requires DBT's to be zeroed before use. */
392   xzero (keydatum);
393   xzero (*valdatum);
394
395   keydatum.data = key;
396   keydatum.size = strlen (key);
397
398   status = db->get (db, NULL, &keydatum, valdatum, 0);
399   return status;
400 }