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