update.
[chise/libchise.git] / chise.c
1 #include <stdlib.h>
2 #ifdef HAVE_CONFIG_H
3 #  include "config.h"
4 #endif
5 #include "sysdep.h"
6 #include "chise.h"
7 #include "chise-name.h"
8
9
10 CHISE_Feature_Table*
11 chise_ds_open_feature_table (CHISE_DS *ds, const char *feature);
12
13 int chise_ft_close (CHISE_Feature_Table *table);
14
15
16 CHISE_CCS_Table*
17 chise_ds_open_ccs_table (CHISE_DS *ds, const char *ccs);
18
19 int chise_ccst_close (CHISE_CCS_Table *table);
20
21
22 typedef DB CHISE_Attribute_Table;
23
24 CHISE_Attribute_Table*
25 CHISE_Attribute_Table_open (const unsigned char *db_dir,
26                             const char *encoding, const char *feature,
27                             DBTYPE real_subtype,
28                             u_int32_t accessmask, int modemask);
29
30 int CHISE_Attribute_Table_close (CHISE_Attribute_Table *db);
31
32 int chise_attribute_table_get (CHISE_Attribute_Table *db,
33                                char *key, CHISE_Value *valdatum);
34
35 int chise_attribute_table_put (CHISE_Attribute_Table *db,
36                                char *key, unsigned char *value);
37
38
39 #define xzero(lvalue) ((void) memset (&(lvalue), '\0', sizeof (lvalue)))
40
41 CHISE_Char_ID
42 chise_char_id_parse_c_string (unsigned char *str, size_t len);
43
44 int
45 chise_format_char_id (CHISE_Char_ID cid, unsigned char *dest, size_t len);
46
47
48 struct CHISE_DS
49 {
50   CHISE_DS_Type type;
51   unsigned char *location;
52   CHISE_NAME_TABLE* feature_names;
53   CHISE_NAME_TABLE* ccs_names;
54   DBTYPE subtype;
55   int modemask;
56 };
57
58 CHISE_DS*
59 CHISE_DS_open (CHISE_DS_Type type, char *location,
60                DBTYPE subtype, int modemask)
61 {
62   CHISE_DS *ds = (CHISE_DS*)malloc (sizeof (CHISE_DS));
63   size_t len = strlen (location);
64
65   if (ds == NULL)
66     return NULL;
67
68   ds->type = type;
69   ds->subtype = subtype;
70   ds->modemask = modemask;
71   ds->location = (unsigned char*)malloc (len + 1);
72   if (ds->location == NULL)
73     {
74       free (ds);
75       return NULL;
76     }
77   strcpy (ds->location, location);
78
79   ds->feature_names = chise_make_name_table ();
80   if (ds->feature_names == NULL)
81     {
82       free (ds->location);
83       free (ds);
84     }
85
86   ds->ccs_names = chise_make_name_table ();
87   if (ds->ccs_names == NULL)
88     {
89       free (ds->feature_names);
90       free (ds->location);
91       free (ds);
92     }
93   return ds;
94 }
95
96 int
97 CHISE_DS_close (CHISE_DS *ds)
98 {
99   if (ds->location != NULL)
100     free (ds->location);
101   if (ds->feature_names != NULL)
102     free (ds->feature_names);
103   if (ds->ccs_names != NULL)
104     free (ds->ccs_names);
105   free (ds);
106   return 0;
107 }
108
109 CHISE_Feature_Table*
110 chise_ds_get_feature (CHISE_DS *ds, const unsigned char *feature)
111 {
112   CHISE_Feature_Table* ft;
113
114   ft = chise_name_table_get (ds->feature_names, feature);
115   if (ft != NULL)
116     return ft;
117
118   ft = chise_ds_open_feature_table (ds, feature);
119   if (ft == NULL)
120     return NULL;
121
122   if (chise_name_table_put (ds->feature_names, feature, ft))
123     {
124       chise_ft_close (ft);
125       return NULL;
126     }
127   return ft;
128 }
129
130 CHISE_CCS
131 chise_ds_get_ccs (CHISE_DS *ds, const unsigned char *ccs)
132 {
133   CHISE_CCS_Table* ct;
134
135   ct = chise_name_table_get (ds->ccs_names, ccs);
136   if (ct != NULL)
137     return ct;
138
139   ct = chise_ds_open_ccs_table (ds, ccs);
140   if (ct == NULL)
141     return NULL;
142
143   if (chise_name_table_put (ds->ccs_names, ccs, ct))
144     {
145       chise_ccst_close (ct);
146       return NULL;
147     }
148   return ct;
149 }
150
151
152 struct CHISE_Feature_Table
153 {
154   CHISE_DS *ds;
155   unsigned char *name;
156   CHISE_Attribute_Table *db;
157   u_int32_t access;
158 };
159
160 CHISE_Feature_Table*
161 chise_ds_open_feature_table (CHISE_DS *ds, const char *feature)
162 {
163   CHISE_Feature_Table* table;
164   size_t len = strlen (feature);
165
166   if (ds == NULL)
167     return NULL;
168
169   table = (CHISE_Feature_Table*)malloc (sizeof (CHISE_Feature_Table));
170   if (table == NULL)
171     return NULL;
172
173   table->ds = ds;
174   table->db = NULL;
175   table->access = 0;
176   table->name = (unsigned char*)malloc (len + 1);
177   if (table->name == NULL)
178     {
179       free (table);
180       return NULL;
181     }
182   strcpy (table->name, feature);
183   return table;
184 }
185
186 int
187 chise_ft_close (CHISE_Feature_Table *table)
188 {
189   int status;
190
191   if (table == NULL)
192     return -1;
193
194   if (table->db == NULL)
195     status = -1;
196   else
197     status = CHISE_Attribute_Table_close (table->db);
198
199   if (table->name == NULL)
200     status = -1;
201   else
202     {
203       free (table->name);
204       status = 0;
205     }
206   free (table);
207   return status;
208 }
209
210 static int
211 chise_feature_setup_db (CHISE_Feature feature, int writable)
212 {
213   u_int32_t access;
214
215   if (writable)
216     {
217       if ((feature->access & DB_CREATE) == 0)
218         {
219           if (feature->db != NULL)
220             {
221               CHISE_Attribute_Table_close (feature->db);
222               feature->db = NULL;
223             }
224           feature->access = 0;
225         }
226       access = DB_CREATE;
227     }
228   else
229     access = DB_RDONLY;
230
231   if (feature->db == NULL)
232     {
233       CHISE_DS *ds = feature->ds;
234
235       feature->db
236         = CHISE_Attribute_Table_open (ds->location,
237                                       "system-char-id", feature->name,
238                                       ds->subtype, access, ds->modemask);
239       if (feature->db == NULL)
240         return -1;
241       feature->access = access;
242     }
243   return 0;
244 }
245
246 int
247 chise_char_load_feature_value (CHISE_Char_ID cid,
248                                CHISE_Feature_Table *table,
249                                CHISE_Value *valdatum)
250 {
251   unsigned char key_buf[8];
252
253   if (chise_feature_setup_db (table, 0))
254     return -1;
255   chise_format_char_id (cid, key_buf, 8);
256   return chise_attribute_table_get (table->db, key_buf, valdatum);
257 }
258
259 unsigned char*
260 chise_char_gets_feature_value (CHISE_Char_ID cid,
261                                CHISE_Feature_Table *table,
262                                unsigned char *buf, size_t size)
263 {
264   CHISE_Value valdatum;
265   unsigned char key_buf[8];
266   int status;
267
268   if (chise_feature_setup_db (table, 0))
269     return NULL;
270   chise_format_char_id (cid, key_buf, 8);
271   status = chise_attribute_table_get (table->db,
272                                       key_buf, &valdatum);
273   if (status)
274     return NULL;
275   if (size < valdatum.size)
276     return NULL;
277   strncpy (buf, valdatum.data, valdatum.size);
278   buf[valdatum.size] = '\0';
279   return buf;
280 }
281
282 int
283 chise_char_feature_value_iterate (CHISE_Feature feature,
284                                   int (*func) (CHISE_Char_ID cid,
285                                                CHISE_Feature feature,
286                                                CHISE_Value *valdatum))
287 {
288   DBT keydatum, valdatum;
289   DBC *dbcp;
290   int status;
291
292   if (chise_feature_setup_db (feature, 0))
293     return -1;
294   xzero (keydatum);
295   xzero (valdatum);
296
297   status = feature->db->cursor (feature->db, NULL, &dbcp, 0);
298   for (status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_FIRST);
299        status == 0;
300        status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_NEXT))
301     {
302       unsigned char *key_str = (unsigned char *)keydatum.data;
303       int key_len = strnlen (key_str, keydatum.size);
304       CHISE_Char_ID key = chise_char_id_parse_c_string (key_str, key_len);
305       int ret = func (key, feature, &valdatum);
306
307       if (ret)
308         break;
309     }
310   dbcp->c_close (dbcp);
311   return 0;
312 }
313
314
315 struct CHISE_CCS_Table
316 {
317   CHISE_DS *ds;
318   unsigned char *name;
319   CHISE_Attribute_Table *db;
320   u_int32_t access;
321 };
322
323 CHISE_CCS_Table*
324 chise_ds_open_ccs_table (CHISE_DS *ds, const char *ccs)
325 {
326   CHISE_CCS_Table* table;
327   size_t len = strlen (ccs);
328
329   if (ds == NULL)
330     return NULL;
331
332   table = (CHISE_CCS_Table*)malloc (sizeof (CHISE_CCS_Table));
333   if (table == NULL)
334     return NULL;
335
336   table->ds = ds;
337   table->db = NULL;
338   table->access = 0;
339   table->name = (unsigned char*)malloc (len + 1);
340   if (table->name == NULL)
341     {
342       free (table);
343       return NULL;
344     }
345   strcpy (table->name, ccs);
346   return table;
347 }
348
349 int
350 chise_ccst_close (CHISE_CCS_Table *table)
351 {
352   int status;
353
354   if (table == NULL)
355     return -1;
356
357   if (table->db == NULL)
358     status = 0;
359   else
360     status = CHISE_Attribute_Table_close (table->db);
361
362   if (table->name == NULL)
363     status = -1;
364   else
365     {
366       free (table->name);
367       status = 0;
368     }
369   free (table);
370   return status;
371 }
372
373 int
374 chise_ccs_sync (CHISE_CCS ccs)
375 {
376   int status;
377
378   if (ccs->db == NULL)
379     status = 0;
380   else
381     status = CHISE_Attribute_Table_close (ccs->db);
382   ccs->db = NULL;
383   ccs->access = 0;
384   return status;
385 }
386
387 CHISE_Char_ID
388 chise_ccs_decode (CHISE_CCS ccs, int code_point)
389 {
390   CHISE_Value valdatum;
391   int status = 0;
392   char key_buf[16];
393
394   if (ccs == NULL)
395     return -1;
396
397   if (ccs->db == NULL)
398     {
399       CHISE_DS *ds = ccs->ds;
400
401       ccs->db = CHISE_Attribute_Table_open (ds->location,
402                                             ccs->name, "system-char-id",
403                                             ds->subtype,
404                                             DB_RDONLY, ds->modemask);
405       if (ccs->db == NULL)
406         return -1;
407       ccs->access = DB_RDONLY;
408     }
409
410   sprintf(key_buf, "%d", code_point);
411   status = chise_attribute_table_get (ccs->db, key_buf, &valdatum);
412   if (!status)
413     {
414       unsigned char *str
415         = (unsigned char *)chise_value_data (&valdatum);
416       int len = strnlen (str, chise_value_size (&valdatum));
417
418       return chise_char_id_parse_c_string (str, len);
419     }
420   return -1;
421 }
422
423 int
424 chise_ccs_set_decoded_char (CHISE_CCS ccs,
425                             int code_point, CHISE_Char_ID cid)
426 {
427   char key_buf[16], val_buf[8];
428
429   if (ccs == NULL)
430     return -1;
431
432   if ((ccs->access & DB_CREATE) == 0)
433     {
434       if (ccs->db != NULL)
435         {
436           CHISE_Attribute_Table_close (ccs->db);
437           ccs->db = NULL;
438         }
439       ccs->access = 0;
440     }
441   if (ccs->db == NULL)
442     {
443       CHISE_DS *ds = ccs->ds;
444
445       ccs->db
446         = CHISE_Attribute_Table_open (ds->location,
447                                       ccs->name, "system-char-id",
448                                       ds->subtype, DB_CREATE, ds->modemask);
449       if (ccs->db == NULL)
450         return -1;
451       ccs->access = DB_CREATE;
452     }
453
454   sprintf(key_buf, "%d", code_point);
455   chise_format_char_id (cid, val_buf, 8);
456   return chise_attribute_table_put (ccs->db, key_buf, val_buf);
457 }
458
459
460 CHISE_Attribute_Table*
461 CHISE_Attribute_Table_open (const unsigned char *db_dir,
462                             const char *encoding, const char *feature,
463                             DBTYPE real_subtype,
464                             u_int32_t accessmask, int modemask)
465 {
466   DB* dbase;
467   int status;
468   int len, flen, i;
469   int size;
470   char *db_file_name, *sp;
471
472   status = db_create (&dbase, NULL, 0);
473   if (status)
474     return NULL;
475
476   len = strlen (db_dir);
477   flen = strlen (feature);
478   size = len + strlen (encoding) + flen * 3 + 4;
479   db_file_name = alloca (size);
480   strcpy (db_file_name, db_dir);
481   if (db_file_name[len - 1] != '/')
482     {
483       db_file_name[len++] = '/';
484       db_file_name[len] = '\0';
485     }
486   strcat (db_file_name, encoding);
487   strcat (db_file_name, "/");
488   /* strcat (db_file_name, feature); */
489   sp = &db_file_name[strlen (db_file_name)];
490   for (i = 0; i < flen; i++)
491     {
492       int c = feature[i];
493
494       if ( (c == '/') || (c == '%') )
495         {
496           sprintf (sp, "%%%02X", c);
497           sp += 3;
498         }
499       else
500         *sp++ = c;
501     }
502   *sp = '\0';
503   status = dbase->open (dbase, db_file_name, NULL,
504                         real_subtype, accessmask, modemask);
505   if (status)
506     {
507       dbase->close (dbase, 0);
508       return NULL;
509     }
510   return dbase;
511 }
512
513 int
514 CHISE_Attribute_Table_close (CHISE_Attribute_Table *db)
515 {
516   if (db)
517     {
518       db->sync  (db, 0);
519       db->close (db, 0);
520     }
521   return 0;
522 }
523
524 int
525 chise_attribute_table_get (CHISE_Attribute_Table *db,
526                            char *key, CHISE_Value *valdatum)
527 {
528   DBT keydatum;
529   int status = 0;
530
531   /* DB Version 2 requires DBT's to be zeroed before use. */
532   xzero (keydatum);
533   xzero (*valdatum);
534
535   keydatum.data = key;
536   keydatum.size = strlen (key);
537
538   status = db->get (db, NULL, &keydatum, valdatum, 0);
539   return status;
540 }
541
542 int
543 chise_attribute_table_put (CHISE_Attribute_Table *db,
544                            char *key, unsigned char *value)
545 {
546   DBT keydatum, valdatum;
547   int status = 0;
548
549   /* DB Version 2 requires DBT's to be zeroed before use. */
550   xzero (keydatum);
551   xzero (valdatum);
552
553   keydatum.data = key;
554   keydatum.size = strlen (key);
555
556   valdatum.data = value;
557   valdatum.size = strlen (value);
558
559   status = db->put (db, NULL, &keydatum, &valdatum, 0);
560   return status;
561 }
562
563 CHISE_Char_ID
564 chise_char_id_parse_c_string (unsigned char *str, size_t len)
565 {
566   int i = 0;
567
568   if ( (len >= 2) && (str[i++] == '?') )
569     {
570       unsigned char c = str[i++];
571       int counter;
572       CHISE_Char_ID cid;
573
574       if (c == '\\')
575         {
576           if (len < 3)
577             return -1;
578           c = str[i++];
579           if (c == '^')
580             {
581               if (len < 4)
582                 return -1;
583               c = str[i++];
584               if (c == '?')
585                 return 0x7F;
586               else
587                 return c & (0x80 | 0x1F);
588             }
589         }
590       if ( c < 0xC0 )
591         {
592           cid = c;
593           counter = 0;
594         }
595       else if ( c < 0xE0 )
596         {
597           cid = c & 0x1f;
598           counter = 1;
599         }
600       else if ( c < 0xF0 )
601         {
602           cid = c & 0x0f;
603           counter = 2;
604         }
605       else if ( c < 0xF8 )
606         {
607           cid = c & 0x07;
608           counter = 3;
609         }
610       else if ( c < 0xFC )
611         {
612           cid = c & 0x03;
613           counter = 4;
614         }
615       else
616         {
617           cid = c & 0x01;
618           counter = 5;
619         }
620
621       if (counter + 2 <= len)
622         {
623           int j;
624
625           for (j = 0; j < counter; j++)
626             cid = (cid << 6) | (str[j + i] & 0x3F);
627           return cid;
628         }
629     }
630   return -1;
631 }
632
633 int
634 chise_format_char_id (CHISE_Char_ID cid, unsigned char *dest, size_t len)
635 {
636   int i = 0;
637
638   dest[i++] = '?';
639   if (cid == '\t')
640     {
641       dest[i++] = '\\';
642       dest[i++] = 't';
643       dest[i] = '\0';
644       return i;
645     }
646   else if (cid == '\n')
647     {
648       dest[i++] = '\\';
649       dest[i++] = 'n';
650       dest[i] = '\0';
651       return i;
652     }
653   else if (cid == '\r')
654     {
655       dest[i++] = '\\';
656       dest[i++] = 'r';
657       dest[i] = '\0';
658       return i;
659     }
660   else if (cid == 0x1C)
661     {
662       dest[i++] = '\\';
663       dest[i++] = '^';
664       dest[i++] = '\\';
665       dest[i++] = '\\';
666       dest[i] = '\0';
667       return i;
668     }
669   else if (cid <= 0x1F)
670     {
671       dest[i++] = '\\';
672       dest[i++] = '^';
673       dest[i++] = '@' + cid;
674       dest[i] = '\0';
675       return i;
676     }
677   else if ( (cid == ' ') || (cid == '"') ||
678             (cid == '#') || (cid == '\'') ||
679             (cid == '(') || (cid == ')') ||
680             (cid == ',') || (cid == '.') ||
681             (cid == ';') || (cid == '?') ||
682             (cid == '[') || (cid == '\\') ||
683             (cid == ']') || (cid == '`') )
684     {
685       dest[i++] = '\\';
686       dest[i++] = cid;
687       dest[i] = '\0';
688       return i;
689     }
690   else if (cid <= 0x7E)
691     {
692       dest[i++] = cid;
693       dest[i] = '\0';
694       return i;
695     }
696   else if (cid == 0x7F)
697     {
698       dest[i++] = '\\';
699       dest[i++] = '^';
700       dest[i++] = '?';
701       dest[i] = '\0';
702       return i;
703     }
704   else if (cid <= 0x9F)
705     {
706       dest[i++] = '\\';
707       dest[i++] = '^';
708       dest[i++] = ((cid + '@') >> 6) | 0xC0;
709       dest[i++] = ((cid + '@') & 0x3F) | 0x80;
710       dest[i] = '\0';
711       return i;
712     }
713   else if (cid <= 0x7FF)
714     {
715       dest[i++] = (cid >> 6) | 0xC0;
716       dest[i++] = (cid & 0x3F) | 0x80;
717       dest[i] = '\0';
718       return i;
719     }
720   else if (cid <= 0xFFFF)
721     {
722       dest[i++] = (cid >> 12) | 0xE0;
723       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
724       dest[i++]=  (cid        & 0x3F) | 0x80;
725       dest[i] = '\0';
726       return i;
727     }
728   else if (cid <= 0x1FFFFF)
729     {
730       dest[i++]=  (cid >> 18) | 0xF0;
731       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
732       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
733       dest[i++]=  (cid        & 0x3F) | 0x80;
734       dest[i] = '\0';
735       return i;
736     }
737   else if (cid <= 0x3FFFFFF)
738     {
739       dest[i++]=  (cid >> 24) | 0xF8;
740       dest[i++]= ((cid >> 18) & 0x3F) | 0x80;
741       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
742       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
743       dest[i++]=  (cid        & 0x3F) | 0x80;
744       dest[i] = '\0';
745       return i;
746     }
747   else
748     {
749       dest[i++]=  (cid >> 30) | 0xFC;
750       dest[i++]= ((cid >> 24) & 0x3F) | 0x80;
751       dest[i++]= ((cid >> 18) & 0x3F) | 0x80;
752       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
753       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
754       dest[i++]=  (cid        & 0x3F) | 0x80;
755       dest[i] = '\0';
756       return i;
757     }
758 }