Modify to avoid warning.
[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_Table*
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->db == NULL)
395     {
396       CHISE_DS *ds = ccs->ds;
397
398       ccs->db = CHISE_Attribute_Table_open (ds->location,
399                                             ccs->name, "system-char-id",
400                                             ds->subtype,
401                                             DB_RDONLY, ds->modemask);
402       if (ccs->db == NULL)
403         return -1;
404       ccs->access = DB_RDONLY;
405     }
406
407   sprintf(key_buf, "%d", code_point);
408   status = chise_attribute_table_get (ccs->db, key_buf, &valdatum);
409   if (!status)
410     {
411       unsigned char *str
412         = (unsigned char *)chise_value_data (&valdatum);
413       int len = strnlen (str, chise_value_size (&valdatum));
414
415       return chise_char_id_parse_c_string (str, len);
416     }
417   return -1;
418 }
419
420 int
421 chise_ccs_set_decoded_char (CHISE_CCS ccs,
422                             int code_point, CHISE_Char_ID cid)
423 {
424   char key_buf[16], val_buf[8];
425
426   if ((ccs->access & DB_CREATE) == 0)
427     {
428       if (ccs->db != NULL)
429         {
430           CHISE_Attribute_Table_close (ccs->db);
431           ccs->db = NULL;
432         }
433       ccs->access = 0;
434     }
435   if (ccs->db == NULL)
436     {
437       CHISE_DS *ds = ccs->ds;
438
439       ccs->db
440         = CHISE_Attribute_Table_open (ds->location,
441                                       ccs->name, "system-char-id",
442                                       ds->subtype, DB_CREATE, ds->modemask);
443       if (ccs->db == NULL)
444         return -1;
445       ccs->access = DB_CREATE;
446     }
447
448   sprintf(key_buf, "%d", code_point);
449   chise_format_char_id (cid, val_buf, 8);
450   return chise_attribute_table_put (ccs->db, key_buf, val_buf);
451 }
452
453
454 CHISE_Attribute_Table*
455 CHISE_Attribute_Table_open (const unsigned char *db_dir,
456                             const char *encoding, const char *feature,
457                             DBTYPE real_subtype,
458                             u_int32_t accessmask, int modemask)
459 {
460   DB* dbase;
461   int status;
462   int len, flen, i;
463   int size;
464   char *db_file_name, *sp;
465
466   status = db_create (&dbase, NULL, 0);
467   if (status)
468     return NULL;
469
470   len = strlen (db_dir);
471   flen = strlen (feature);
472   size = len + strlen (encoding) + flen * 3 + 4;
473   db_file_name = alloca (size);
474   strcpy (db_file_name, db_dir);
475   if (db_file_name[len - 1] != '/')
476     {
477       db_file_name[len++] = '/';
478       db_file_name[len] = '\0';
479     }
480   strcat (db_file_name, encoding);
481   strcat (db_file_name, "/");
482   /* strcat (db_file_name, feature); */
483   sp = &db_file_name[strlen (db_file_name)];
484   for (i = 0; i < flen; i++)
485     {
486       int c = feature[i];
487
488       if ( (c == '/') || (c == '%') )
489         {
490           sprintf (sp, "%%%02X", c);
491           sp += 3;
492         }
493       else
494         *sp++ = c;
495     }
496   *sp = '\0';
497   status = dbase->open (dbase, db_file_name, NULL,
498                         real_subtype, accessmask, modemask);
499   if (status)
500     {
501       dbase->close (dbase, 0);
502       return NULL;
503     }
504   return dbase;
505 }
506
507 int
508 CHISE_Attribute_Table_close (CHISE_Attribute_Table *db)
509 {
510   if (db)
511     {
512       db->sync  (db, 0);
513       db->close (db, 0);
514     }
515   return 0;
516 }
517
518 int
519 chise_attribute_table_get (CHISE_Attribute_Table *db,
520                            char *key, CHISE_Value *valdatum)
521 {
522   DBT keydatum;
523   int status = 0;
524
525   /* DB Version 2 requires DBT's to be zeroed before use. */
526   xzero (keydatum);
527   xzero (*valdatum);
528
529   keydatum.data = key;
530   keydatum.size = strlen (key);
531
532   status = db->get (db, NULL, &keydatum, valdatum, 0);
533   return status;
534 }
535
536 int
537 chise_attribute_table_put (CHISE_Attribute_Table *db,
538                            char *key, unsigned char *value)
539 {
540   DBT keydatum, valdatum;
541   int status = 0;
542
543   /* DB Version 2 requires DBT's to be zeroed before use. */
544   xzero (keydatum);
545   xzero (valdatum);
546
547   keydatum.data = key;
548   keydatum.size = strlen (key);
549
550   valdatum.data = value;
551   valdatum.size = strlen (value);
552
553   status = db->put (db, NULL, &keydatum, &valdatum, 0);
554   return status;
555 }
556
557 CHISE_Char_ID
558 chise_char_id_parse_c_string (unsigned char *str, size_t len)
559 {
560   int i = 0;
561
562   if ( (len >= 2) && (str[i++] == '?') )
563     {
564       unsigned char c = str[i++];
565       int counter;
566       CHISE_Char_ID cid;
567
568       if (c == '\\')
569         {
570           if (len < 3)
571             return -1;
572           c = str[i++];
573           if (c == '^')
574             {
575               if (len < 4)
576                 return -1;
577               c = str[i++];
578               if (c == '?')
579                 return 0x7F;
580               else
581                 return c & (0x80 | 0x1F);
582             }
583         }
584       if ( c < 0xC0 )
585         {
586           cid = c;
587           counter = 0;
588         }
589       else if ( c < 0xE0 )
590         {
591           cid = c & 0x1f;
592           counter = 1;
593         }
594       else if ( c < 0xF0 )
595         {
596           cid = c & 0x0f;
597           counter = 2;
598         }
599       else if ( c < 0xF8 )
600         {
601           cid = c & 0x07;
602           counter = 3;
603         }
604       else if ( c < 0xFC )
605         {
606           cid = c & 0x03;
607           counter = 4;
608         }
609       else
610         {
611           cid = c & 0x01;
612           counter = 5;
613         }
614
615       if (counter + 2 <= len)
616         {
617           int j;
618
619           for (j = 0; j < counter; j++)
620             cid = (cid << 6) | (str[j + i] & 0x3F);
621           return cid;
622         }
623     }
624   return -1;
625 }
626
627 int
628 chise_format_char_id (CHISE_Char_ID cid, unsigned char *dest, size_t len)
629 {
630   int i = 0;
631
632   dest[i++] = '?';
633   if (cid == '\t')
634     {
635       dest[i++] = '\\';
636       dest[i++] = 't';
637       dest[i] = '\0';
638       return i;
639     }
640   else if (cid == '\n')
641     {
642       dest[i++] = '\\';
643       dest[i++] = 'n';
644       dest[i] = '\0';
645       return i;
646     }
647   else if (cid == '\r')
648     {
649       dest[i++] = '\\';
650       dest[i++] = 'r';
651       dest[i] = '\0';
652       return i;
653     }
654   else if (cid == 0x1C)
655     {
656       dest[i++] = '\\';
657       dest[i++] = '^';
658       dest[i++] = '\\';
659       dest[i++] = '\\';
660       dest[i] = '\0';
661       return i;
662     }
663   else if (cid <= 0x1F)
664     {
665       dest[i++] = '\\';
666       dest[i++] = '^';
667       dest[i++] = '@' + cid;
668       dest[i] = '\0';
669       return i;
670     }
671   else if ( (cid == ' ') || (cid == '"') ||
672             (cid == '#') || (cid == '\'') ||
673             (cid == '(') || (cid == ')') ||
674             (cid == ',') || (cid == '.') ||
675             (cid == ';') || (cid == '?') ||
676             (cid == '[') || (cid == '\\') ||
677             (cid == ']') || (cid == '`') )
678     {
679       dest[i++] = '\\';
680       dest[i++] = cid;
681       dest[i] = '\0';
682       return i;
683     }
684   else if (cid <= 0x7E)
685     {
686       dest[i++] = cid;
687       dest[i] = '\0';
688       return i;
689     }
690   else if (cid == 0x7F)
691     {
692       dest[i++] = '\\';
693       dest[i++] = '^';
694       dest[i++] = '?';
695       dest[i] = '\0';
696       return i;
697     }
698   else if (cid <= 0x9F)
699     {
700       dest[i++] = '\\';
701       dest[i++] = '^';
702       dest[i++] = ((cid + '@') >> 6) | 0xC0;
703       dest[i++] = ((cid + '@') & 0x3F) | 0x80;
704       dest[i] = '\0';
705       return i;
706     }
707   else if (cid <= 0x7FF)
708     {
709       dest[i++] = (cid >> 6) | 0xC0;
710       dest[i++] = (cid & 0x3F) | 0x80;
711       dest[i] = '\0';
712       return i;
713     }
714   else if (cid <= 0xFFFF)
715     {
716       dest[i++] = (cid >> 12) | 0xE0;
717       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
718       dest[i++]=  (cid        & 0x3F) | 0x80;
719       dest[i] = '\0';
720       return i;
721     }
722   else if (cid <= 0x1FFFFF)
723     {
724       dest[i++]=  (cid >> 18) | 0xF0;
725       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
726       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
727       dest[i++]=  (cid        & 0x3F) | 0x80;
728       dest[i] = '\0';
729       return i;
730     }
731   else if (cid <= 0x3FFFFFF)
732     {
733       dest[i++]=  (cid >> 24) | 0xF8;
734       dest[i++]= ((cid >> 18) & 0x3F) | 0x80;
735       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
736       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
737       dest[i++]=  (cid        & 0x3F) | 0x80;
738       dest[i] = '\0';
739       return i;
740     }
741   else
742     {
743       dest[i++]=  (cid >> 30) | 0xFC;
744       dest[i++]= ((cid >> 24) & 0x3F) | 0x80;
745       dest[i++]= ((cid >> 18) & 0x3F) | 0x80;
746       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
747       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
748       dest[i++]=  (cid        & 0x3F) | 0x80;
749       dest[i] = '\0';
750       return i;
751     }
752 }