Update.
[chise/libchise.git] / chise.c
1 /* Copyright (C) 2003,2004 MORIOKA Tomohiko
2    This file is part of the CHISE Library.
3
4    The CHISE Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The CHISE Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the CHISE Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <dirent.h>
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27 #include "sysdep.h"
28 #include "chise.h"
29 #include "chise-name.h"
30
31 const unsigned char chise_db_dir[] = CHISE_DB_DIR;
32 const unsigned char chise_system_db_dir[] = CHISE_SI_DB_DIR;
33
34 CHISE_Feature_Table*
35 chise_ds_open_feature_table (CHISE_DS *ds, const char *feature);
36
37 int chise_ft_close (CHISE_Feature_Table *table);
38
39
40 CHISE_CCS_Table*
41 chise_ds_open_ccs_table (CHISE_DS *ds, const char *ccs);
42
43 int chise_ccst_close (CHISE_CCS_Table *table);
44
45
46 CHISE_Property_Table*
47 chise_ds_open_property_table (CHISE_DS *ds, const char *property);
48
49 int chise_pt_close (CHISE_Property_Table *table);
50
51
52 typedef DB CHISE_Attribute_Table;
53
54 CHISE_Attribute_Table*
55 CHISE_Attribute_Table_open (const unsigned char *db_dir,
56                             const char *category,
57                             const char *key_type, const char *name,
58                             DBTYPE real_subtype,
59                             u_int32_t accessmask, int modemask);
60
61 int CHISE_Attribute_Table_close (CHISE_Attribute_Table *db);
62
63 int chise_attribute_table_get (CHISE_Attribute_Table *db,
64                                char *key, CHISE_Value *valdatum);
65
66 int chise_attribute_table_put (CHISE_Attribute_Table *db,
67                                char *key, unsigned char *value);
68
69
70 #define xzero(lvalue) ((void) memset (&(lvalue), '\0', sizeof (lvalue)))
71
72 CHISE_Char_ID
73 chise_char_id_parse_c_string (unsigned char *str, size_t len);
74
75 int
76 chise_format_char_id (CHISE_Char_ID cid, unsigned char *dest, size_t len);
77
78
79 struct CHISE_DS
80 {
81   CHISE_DS_Type type;
82   unsigned char *location;
83   CHISE_NAME_TABLE* feature_names;
84   CHISE_NAME_TABLE* ccs_names;
85   CHISE_NAME_TABLE* property_names;
86   DBTYPE subtype;
87   int modemask;
88 };
89
90 CHISE_DS*
91 CHISE_DS_open (CHISE_DS_Type type, const unsigned char *location,
92                int subtype, int modemask)
93 {
94   CHISE_DS *ds = (CHISE_DS*)malloc (sizeof (CHISE_DS));
95   size_t len = strlen (location);
96
97   if (ds == NULL)
98     return NULL;
99
100   ds->type = type;
101   ds->subtype = ( (subtype != 0) ? subtype : DB_HASH );
102   ds->modemask = modemask;
103   ds->location = (unsigned char*)malloc (len + 1);
104   if (ds->location == NULL)
105     {
106       free (ds);
107       return NULL;
108     }
109   strcpy (ds->location, location);
110
111   ds->feature_names = chise_make_name_table ();
112   if (ds->feature_names == NULL)
113     {
114       free (ds->location);
115       free (ds);
116     }
117
118   ds->ccs_names = chise_make_name_table ();
119   if (ds->ccs_names == NULL)
120     {
121       free (ds->feature_names);
122       free (ds->location);
123       free (ds);
124     }
125
126   ds->property_names = chise_make_name_table ();
127   if (ds->property_names == NULL)
128     {
129       free (ds->ccs_names);
130       free (ds->feature_names);
131       free (ds->location);
132       free (ds);
133     }
134   return ds;
135 }
136
137 int
138 CHISE_DS_close (CHISE_DS *ds)
139 {
140   if (ds->location != NULL)
141     free (ds->location);
142   if (ds->feature_names != NULL)
143     chise_destroy_name_table (ds->feature_names);
144   if (ds->ccs_names != NULL)
145     chise_destroy_name_table (ds->ccs_names);
146   if (ds->property_names != NULL)
147     chise_destroy_name_table (ds->property_names);
148   free (ds);
149   return 0;
150 }
151
152 unsigned char*
153 chise_ds_location (CHISE_DS *ds)
154 {
155   return ds->location;
156 }
157
158 CHISE_Feature_Table*
159 chise_ds_get_feature (CHISE_DS *ds, const unsigned char *feature)
160 {
161   CHISE_Feature_Table* ft;
162
163   ft = chise_name_table_get (ds->feature_names, feature);
164   if (ft != NULL)
165     return ft;
166
167   ft = chise_ds_open_feature_table (ds, feature);
168   if (ft == NULL)
169     return NULL;
170
171   if (chise_name_table_put (ds->feature_names, feature, ft))
172     {
173       chise_ft_close (ft);
174       return NULL;
175     }
176   return ft;
177 }
178
179 CHISE_CCS
180 chise_ds_get_ccs (CHISE_DS *ds, const unsigned char *ccs)
181 {
182   CHISE_CCS_Table* ct;
183
184   ct = chise_name_table_get (ds->ccs_names, ccs);
185   if (ct != NULL)
186     return ct;
187
188   ct = chise_ds_open_ccs_table (ds, ccs);
189   if (ct == NULL)
190     return NULL;
191
192   if (chise_name_table_put (ds->ccs_names, ccs, ct))
193     {
194       chise_ccst_close (ct);
195       return NULL;
196     }
197   return ct;
198 }
199
200 CHISE_Property_Table*
201 chise_ds_get_property (CHISE_DS *ds, const unsigned char *property)
202 {
203   CHISE_Property_Table* pt;
204
205   pt = chise_name_table_get (ds->property_names, property);
206   if (pt != NULL)
207     return pt;
208
209   pt = chise_ds_open_property_table (ds, property);
210   if (pt == NULL)
211     return NULL;
212
213   if (chise_name_table_put (ds->property_names, property, pt))
214     {
215       chise_pt_close (pt);
216       return NULL;
217     }
218   return pt;
219 }
220
221 int
222 chise_ds_foreach_char_feature_name (CHISE_DS *ds,
223                                     int (*func) (CHISE_DS *ds,
224                                                  unsigned char *name))
225 {
226   unsigned char *dname
227     = alloca (strlen (ds->location) + sizeof ("/character/feature") + 1);
228   DIR *dir;
229   struct dirent *de;
230
231   strcpy (dname, ds->location);
232   strcat (dname, "/character/feature");
233
234   if ( (dir = opendir (dname)) == NULL)
235     return -1;
236
237   while ( (de = readdir (dir)) != NULL )
238     {
239       if ( (strcmp (de->d_name, ".") != 0) &&
240            (strcmp (de->d_name, "..") != 0) )
241         {
242           int i, need_to_decode = 0;
243           unsigned char *cp;
244           unsigned char *name;
245           unsigned char *np;
246
247           for (cp = de->d_name, i = 0; *cp != '\0'; i++)
248             {
249               if (*cp++ == '%')
250                 need_to_decode = 1;
251             }
252           if (need_to_decode)
253             {
254               int index = -1;
255               int ch, c[2];
256               int hex[2];
257
258               name = (unsigned char *) alloca (i);
259               cp = de->d_name;
260               np = name;
261
262               while ( (ch = *cp++) != '\0')
263                 {
264                   if (ch == '%')
265                     {
266                       if (index >= 0)
267                         {
268                           *np++ = '%';
269                           if (index == 1)
270                             *np++ = c[0];
271                         }
272                       index = 0;
273                     }
274                   else if (index >= 0)
275                     {
276                       c[index] = ch;
277
278                       if ( ('0' <= ch) && (ch <= '9') )
279                         hex[index++] = ch - '0';
280                       else if ( ('A' <= ch) && (ch <= 'F') )
281                         hex[index++] = ch - 'A' + 10;
282                       else if ( ('a' <= ch) && (ch <= 'f') )
283                         hex[index++] = ch - 'a' + 10;
284                       else
285                         {
286                           *np++ = '%';
287                           if (index == 1)
288                             *np++ = c[0];
289                           *np++ = ch;
290                           index = -1;
291                           continue;
292                         }
293                       if (index == 2)
294                         {
295                           *np++ = (hex[0] << 4) | hex[1];
296                           index = -1;
297                           continue;
298                         }
299                     }
300                   else
301                     *np++ = ch;
302                 }
303               *np = '\0';
304             }  
305           else
306             name = de->d_name;
307
308           if (func (ds, name))
309             return closedir (dir);
310         }
311     }
312   return closedir (dir);
313 }
314
315 struct CHISE_Feature_Table
316 {
317   CHISE_DS *ds;
318   unsigned char *name;
319   CHISE_Attribute_Table *db;
320   u_int32_t access;
321 };
322
323 CHISE_Feature_Table*
324 chise_ds_open_feature_table (CHISE_DS *ds, const char *feature)
325 {
326   CHISE_Feature_Table* table;
327   size_t len = strlen (feature);
328
329   if (ds == NULL)
330     return NULL;
331
332   table = (CHISE_Feature_Table*)malloc (sizeof (CHISE_Feature_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, feature);
346   return table;
347 }
348
349 int
350 chise_ft_close (CHISE_Feature_Table *table)
351 {
352   int status;
353
354   if (table == NULL)
355     return -1;
356
357   if (table->db == NULL)
358     status = -1;
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_feature_setup_db (CHISE_Feature feature, int writable)
375 {
376   u_int32_t access;
377
378   if (feature == NULL)
379     return -1;
380
381   if (writable)
382     {
383       if ((feature->access & DB_CREATE) == 0)
384         {
385           if (feature->db != NULL)
386             {
387               CHISE_Attribute_Table_close (feature->db);
388               feature->db = NULL;
389             }
390           feature->access = 0;
391         }
392       access = DB_CREATE;
393     }
394   else
395     access = DB_RDONLY;
396
397   if (feature->db == NULL)
398     {
399       CHISE_DS *ds = feature->ds;
400
401       feature->db
402         = CHISE_Attribute_Table_open (ds->location, "character",
403                                       "feature", feature->name,
404                                       ds->subtype, access, ds->modemask);
405       if (feature->db == NULL)
406         return -1;
407       feature->access = access;
408     }
409   return 0;
410 }
411
412 int
413 chise_feature_sync (CHISE_Feature feature)
414 {
415   int status;
416
417   if (feature->db == NULL)
418     status = 0;
419   else
420     status = CHISE_Attribute_Table_close (feature->db);
421   feature->db = NULL;
422   feature->access = 0;
423   return status;
424 }
425
426 int
427 chise_char_set_feature_value (CHISE_Char_ID cid,
428                               CHISE_Feature feature,
429                               unsigned char *value)
430 {
431   unsigned char key_buf[8];
432
433   if (feature == NULL)
434     return -1;
435   if (chise_feature_setup_db (feature, 1))
436     return -1;
437   chise_format_char_id (cid, key_buf, 8);
438   return chise_attribute_table_put (feature->db, key_buf, value);
439 }
440
441 int
442 chise_char_load_feature_value (CHISE_Char_ID cid,
443                                CHISE_Feature_Table *table,
444                                CHISE_Value *valdatum)
445 {
446   unsigned char key_buf[8];
447
448   if (chise_feature_setup_db (table, 0))
449     return -1;
450   chise_format_char_id (cid, key_buf, 8);
451   return chise_attribute_table_get (table->db, key_buf, valdatum);
452 }
453
454 unsigned char*
455 chise_char_gets_feature_value (CHISE_Char_ID cid,
456                                CHISE_Feature_Table *table,
457                                unsigned char *buf, size_t size)
458 {
459   CHISE_Value valdatum;
460   unsigned char key_buf[8];
461   int status;
462
463   if (chise_feature_setup_db (table, 0))
464     return NULL;
465   chise_format_char_id (cid, key_buf, 8);
466   status = chise_attribute_table_get (table->db,
467                                       key_buf, &valdatum);
468   if (status)
469     return NULL;
470   if (size < valdatum.size)
471     return NULL;
472   strncpy (buf, valdatum.data, valdatum.size);
473   buf[valdatum.size] = '\0';
474   return buf;
475 }
476
477 int
478 chise_feature_foreach_char_with_value (CHISE_Feature feature,
479                                        int (*func) (CHISE_Char_ID cid,
480                                                     CHISE_Feature feature,
481                                                     CHISE_Value *valdatum))
482 {
483   DBT keydatum, valdatum;
484   DBC *dbcp;
485   int status;
486
487   if (chise_feature_setup_db (feature, 0))
488     return -1;
489   xzero (keydatum);
490   xzero (valdatum);
491
492   status = feature->db->cursor (feature->db, NULL, &dbcp, 0);
493   for (status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_FIRST);
494        status == 0;
495        status = dbcp->c_get (dbcp, &keydatum, &valdatum, DB_NEXT))
496     {
497       unsigned char *key_str = (unsigned char *)keydatum.data;
498       int key_len = strnlen (key_str, keydatum.size);
499       CHISE_Char_ID key = chise_char_id_parse_c_string (key_str, key_len);
500       int ret = func (key, feature, &valdatum);
501
502       if (ret)
503         break;
504     }
505   dbcp->c_close (dbcp);
506   return 0;
507 }
508
509
510 struct CHISE_CCS_Table
511 {
512   CHISE_DS *ds;
513   unsigned char *name;
514   CHISE_Attribute_Table *db;
515   u_int32_t access;
516 };
517
518 CHISE_CCS_Table*
519 chise_ds_open_ccs_table (CHISE_DS *ds, const char *ccs)
520 {
521   CHISE_CCS_Table* table;
522   size_t len = strlen (ccs);
523
524   if (ds == NULL)
525     return NULL;
526
527   table = (CHISE_CCS_Table*)malloc (sizeof (CHISE_CCS_Table));
528   if (table == NULL)
529     return NULL;
530
531   table->ds = ds;
532   table->db = NULL;
533   table->access = 0;
534   table->name = (unsigned char*)malloc (len + 1);
535   if (table->name == NULL)
536     {
537       free (table);
538       return NULL;
539     }
540   strcpy (table->name, ccs);
541   return table;
542 }
543
544 int
545 chise_ccst_close (CHISE_CCS_Table *table)
546 {
547   int status;
548
549   if (table == NULL)
550     return -1;
551
552   if (table->db == NULL)
553     status = 0;
554   else
555     status = CHISE_Attribute_Table_close (table->db);
556
557   if (table->name == NULL)
558     status = -1;
559   else
560     {
561       free (table->name);
562       status = 0;
563     }
564   free (table);
565   return status;
566 }
567
568 int
569 chise_ccs_setup_db (CHISE_CCS ccs, int writable)
570 {
571   u_int32_t access;
572
573   if (ccs == NULL)
574     return -1;
575
576   if (writable)
577     {
578       if ((ccs->access & DB_CREATE) == 0)
579         {
580           if (ccs->db != NULL)
581             {
582               CHISE_Attribute_Table_close (ccs->db);
583               ccs->db = NULL;
584             }
585           ccs->access = 0;
586         }
587       access = DB_CREATE;
588     }
589   else
590     access = DB_RDONLY;
591
592   if (ccs->db == NULL)
593     {
594       CHISE_DS *ds = ccs->ds;
595
596       ccs->db
597         = CHISE_Attribute_Table_open (ds->location, "character",
598                                       "by_feature", ccs->name,
599                                       ds->subtype, access, ds->modemask);
600       if (ccs->db == NULL)
601         return -1;
602       ccs->access = access;
603     }
604   return 0;
605 }
606
607 int
608 chise_ccs_sync (CHISE_CCS ccs)
609 {
610   int status;
611
612   if (ccs->db == NULL)
613     status = 0;
614   else
615     status = CHISE_Attribute_Table_close (ccs->db);
616   ccs->db = NULL;
617   ccs->access = 0;
618   return status;
619 }
620
621 CHISE_Char_ID
622 chise_ccs_decode (CHISE_CCS ccs, int code_point)
623 {
624   CHISE_Value valdatum;
625   int status = 0;
626   char key_buf[16];
627
628   if (ccs == NULL)
629     return -1;
630
631   if (chise_ccs_setup_db (ccs, 0))
632     return -1;  
633
634   sprintf(key_buf, "%d", code_point);
635   status = chise_attribute_table_get (ccs->db, key_buf, &valdatum);
636   if (!status)
637     {
638       unsigned char *str
639         = (unsigned char *)chise_value_data (&valdatum);
640       int len = strnlen (str, chise_value_size (&valdatum));
641
642       return chise_char_id_parse_c_string (str, len);
643     }
644   return -1;
645 }
646
647 int
648 chise_ccs_set_decoded_char (CHISE_CCS ccs,
649                             int code_point, CHISE_Char_ID cid)
650 {
651   char key_buf[16], val_buf[8];
652
653   if (ccs == NULL)
654     return -1;
655
656   if (chise_ccs_setup_db (ccs, 1))
657     return -1;  
658
659   sprintf(key_buf, "%d", code_point);
660   chise_format_char_id (cid, val_buf, 8);
661   return chise_attribute_table_put (ccs->db, key_buf, val_buf);
662 }
663
664
665 struct CHISE_Property_Table
666 {
667   CHISE_DS *ds;
668   unsigned char *name;
669   CHISE_Attribute_Table *db;
670   u_int32_t access;
671 };
672
673 CHISE_Property_Table*
674 chise_ds_open_property_table (CHISE_DS *ds, const char *property)
675 {
676   CHISE_Property_Table* table;
677   size_t len = strlen (property);
678
679   if (ds == NULL)
680     return NULL;
681
682   table = (CHISE_Property_Table*)malloc (sizeof (CHISE_Property_Table));
683   if (table == NULL)
684     return NULL;
685
686   table->ds = ds;
687   table->db = NULL;
688   table->access = 0;
689   table->name = (unsigned char*)malloc (len + 1);
690   if (table->name == NULL)
691     {
692       free (table);
693       return NULL;
694     }
695   strcpy (table->name, property);
696   return table;
697 }
698
699 int
700 chise_pt_close (CHISE_Property_Table *table)
701 {
702   int status;
703
704   if (table == NULL)
705     return -1;
706
707   if (table->db == NULL)
708     status = -1;
709   else
710     status = CHISE_Attribute_Table_close (table->db);
711
712   if (table->name == NULL)
713     status = -1;
714   else
715     {
716       free (table->name);
717       status = 0;
718     }
719   free (table);
720   return status;
721 }
722
723 int
724 chise_property_setup_db (CHISE_Property property, int writable)
725 {
726   u_int32_t access;
727
728   if (property == NULL)
729     return -1;
730
731   if (writable)
732     {
733       if ((property->access & DB_CREATE) == 0)
734         {
735           if (property->db != NULL)
736             {
737               CHISE_Attribute_Table_close (property->db);
738               property->db = NULL;
739             }
740           property->access = 0;
741         }
742       access = DB_CREATE;
743     }
744   else
745     access = DB_RDONLY;
746
747   if (property->db == NULL)
748     {
749       CHISE_DS *ds = property->ds;
750
751       property->db
752         = CHISE_Attribute_Table_open (ds->location, "feature",
753                                       "property", property->name,
754                                       ds->subtype, access, ds->modemask);
755       if (property->db == NULL)
756         return -1;
757       property->access = access;
758     }
759   return 0;
760 }
761
762 int
763 chise_property_sync (CHISE_Property property)
764 {
765   int status;
766
767   if (property->db == NULL)
768     status = 0;
769   else
770     status = CHISE_Attribute_Table_close (property->db);
771   property->db = NULL;
772   property->access = 0;
773   return status;
774 }
775
776 int
777 chise_feature_set_property_value (CHISE_Feature feature,
778                                   CHISE_Property property,
779                                   unsigned char *value)
780 {
781   if (property == NULL)
782     return -1;
783   if (chise_property_setup_db (property, 1))
784     return -1;
785   return chise_attribute_table_put (property->db, feature->name, value);
786 }
787
788 int
789 chise_feature_load_property_value (CHISE_Feature feature,
790                                    CHISE_Property_Table *table,
791                                    CHISE_Value *valdatum)
792 {
793   if (chise_property_setup_db (table, 0))
794     return -1;
795   return chise_attribute_table_get (table->db, feature->name, valdatum);
796 }
797
798 unsigned char*
799 chise_feature_gets_property_value (CHISE_Feature feature,
800                                    CHISE_Property_Table *table,
801                                    unsigned char *buf, size_t size)
802 {
803   CHISE_Value valdatum;
804   int status;
805
806   if (chise_property_setup_db (table, 0))
807     return NULL;
808   status = chise_attribute_table_get (table->db,
809                                       feature->name, &valdatum);
810   if (status)
811     return NULL;
812   if (size < valdatum.size)
813     return NULL;
814   strncpy (buf, valdatum.data, valdatum.size);
815   buf[valdatum.size] = '\0';
816   return buf;
817 }
818
819
820 CHISE_Attribute_Table*
821 CHISE_Attribute_Table_open (const unsigned char *db_dir,
822                             const char *category,
823                             const char *key_type, const char *name,
824                             DBTYPE real_subtype,
825                             u_int32_t accessmask, int modemask)
826 {
827   DB* dbase;
828   int status;
829   int len, name_len, i;
830   int size;
831   char *db_file_name, *sp;
832   struct stat statbuf;
833
834   status = db_create (&dbase, NULL, 0);
835   if (status)
836     return NULL;
837
838   if ( (accessmask & DB_CREATE) && stat (db_dir, &statbuf) )
839     mkdir (db_dir, modemask);
840
841   len = strlen (db_dir);
842   name_len = strlen (name);
843   size = len + strlen (category) + strlen (key_type) + name_len * 3 + 5;
844   db_file_name = alloca (size);
845   strcpy (db_file_name, db_dir);
846   if (db_file_name[len - 1] != '/')
847     {
848       db_file_name[len++] = '/';
849       db_file_name[len] = '\0';
850     }
851
852   strcat (db_file_name, category);
853   if ( (accessmask & DB_CREATE) && stat (db_file_name, &statbuf) )
854     mkdir (db_file_name, modemask);
855   strcat (db_file_name, "/");
856
857   strcat (db_file_name, key_type);
858   if ( (accessmask & DB_CREATE) && stat (db_file_name, &statbuf) )
859     mkdir (db_file_name, modemask);
860   strcat (db_file_name, "/");
861
862   /* strcat (db_file_name, name); */
863   sp = &db_file_name[strlen (db_file_name)];
864   for (i = 0; i < name_len; i++)
865     {
866       int c = name[i];
867
868       if ( (c == '/') || (c == '%') )
869         {
870           sprintf (sp, "%%%02X", c);
871           sp += 3;
872         }
873       else
874         *sp++ = c;
875     }
876   *sp = '\0';
877 #if DB_VERSION_MAJOR < 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1)
878   status = dbase->open (dbase, db_file_name, NULL,
879                         real_subtype, accessmask, modemask);
880 #else /* DB_VERSION >= 4.1 */
881   status = dbase->open (dbase, NULL, db_file_name, NULL,
882                         real_subtype,
883                         accessmask /* | DB_AUTO_COMMIT */, modemask);
884 #endif /* DB_VERSION < 4.1 */
885   if (status)
886     {
887       dbase->close (dbase, 0);
888       return NULL;
889     }
890   return dbase;
891 }
892
893 int
894 CHISE_Attribute_Table_close (CHISE_Attribute_Table *db)
895 {
896   if (db)
897     {
898       db->sync  (db, 0);
899       db->close (db, 0);
900     }
901   return 0;
902 }
903
904 int
905 chise_attribute_table_get (CHISE_Attribute_Table *db,
906                            char *key, CHISE_Value *valdatum)
907 {
908   DBT keydatum;
909   int status = 0;
910
911   /* DB Version 2 requires DBT's to be zeroed before use. */
912   xzero (keydatum);
913   xzero (*valdatum);
914
915   keydatum.data = key;
916   keydatum.size = strlen (key);
917
918   status = db->get (db, NULL, &keydatum, valdatum, 0);
919   return status;
920 }
921
922 int
923 chise_attribute_table_put (CHISE_Attribute_Table *db,
924                            char *key, unsigned char *value)
925 {
926   DBT keydatum, valdatum;
927   int status = 0;
928
929   /* DB Version 2 requires DBT's to be zeroed before use. */
930   xzero (keydatum);
931   xzero (valdatum);
932
933   keydatum.data = key;
934   keydatum.size = strlen (key);
935
936   valdatum.data = value;
937   valdatum.size = strlen (value);
938
939   status = db->put (db, NULL, &keydatum, &valdatum, 0);
940   return status;
941 }
942
943 CHISE_Char_ID
944 chise_char_id_parse_c_string (unsigned char *str, size_t len)
945 {
946   int i = 0;
947
948   if ( (len >= 2) && (str[i++] == '?') )
949     {
950       unsigned char c = str[i++];
951       int counter;
952       CHISE_Char_ID cid;
953
954       if (c == '\\')
955         {
956           if (len < 3)
957             return -1;
958           c = str[i++];
959           if (c == '^')
960             {
961               if (len < 4)
962                 return -1;
963               c = str[i++];
964               if (c == '?')
965                 return 0x7F;
966               else
967                 return c & (0x80 | 0x1F);
968             }
969         }
970       if ( c < 0xC0 )
971         {
972           cid = c;
973           counter = 0;
974         }
975       else if ( c < 0xE0 )
976         {
977           cid = c & 0x1f;
978           counter = 1;
979         }
980       else if ( c < 0xF0 )
981         {
982           cid = c & 0x0f;
983           counter = 2;
984         }
985       else if ( c < 0xF8 )
986         {
987           cid = c & 0x07;
988           counter = 3;
989         }
990       else if ( c < 0xFC )
991         {
992           cid = c & 0x03;
993           counter = 4;
994         }
995       else
996         {
997           cid = c & 0x01;
998           counter = 5;
999         }
1000
1001       if (counter + 2 <= len)
1002         {
1003           int j;
1004
1005           for (j = 0; j < counter; j++)
1006             cid = (cid << 6) | (str[j + i] & 0x3F);
1007           return cid;
1008         }
1009     }
1010   return -1;
1011 }
1012
1013 int
1014 chise_format_char_id (CHISE_Char_ID cid, unsigned char *dest, size_t len)
1015 {
1016   int i = 0;
1017
1018   dest[i++] = '?';
1019   if (cid == '\t')
1020     {
1021       dest[i++] = '\\';
1022       dest[i++] = 't';
1023       dest[i] = '\0';
1024       return i;
1025     }
1026   else if (cid == '\n')
1027     {
1028       dest[i++] = '\\';
1029       dest[i++] = 'n';
1030       dest[i] = '\0';
1031       return i;
1032     }
1033   else if (cid == '\r')
1034     {
1035       dest[i++] = '\\';
1036       dest[i++] = 'r';
1037       dest[i] = '\0';
1038       return i;
1039     }
1040   else if (cid == 0x1C)
1041     {
1042       dest[i++] = '\\';
1043       dest[i++] = '^';
1044       dest[i++] = '\\';
1045       dest[i++] = '\\';
1046       dest[i] = '\0';
1047       return i;
1048     }
1049   else if (cid <= 0x1F)
1050     {
1051       dest[i++] = '\\';
1052       dest[i++] = '^';
1053       dest[i++] = '@' + cid;
1054       dest[i] = '\0';
1055       return i;
1056     }
1057   else if ( (cid == ' ') || (cid == '"') ||
1058             (cid == '#') || (cid == '\'') ||
1059             (cid == '(') || (cid == ')') ||
1060             (cid == ',') || (cid == '.') ||
1061             (cid == ';') || (cid == '?') ||
1062             (cid == '[') || (cid == '\\') ||
1063             (cid == ']') || (cid == '`') )
1064     {
1065       dest[i++] = '\\';
1066       dest[i++] = cid;
1067       dest[i] = '\0';
1068       return i;
1069     }
1070   else if (cid <= 0x7E)
1071     {
1072       dest[i++] = cid;
1073       dest[i] = '\0';
1074       return i;
1075     }
1076   else if (cid == 0x7F)
1077     {
1078       dest[i++] = '\\';
1079       dest[i++] = '^';
1080       dest[i++] = '?';
1081       dest[i] = '\0';
1082       return i;
1083     }
1084   else if (cid <= 0x9F)
1085     {
1086       dest[i++] = '\\';
1087       dest[i++] = '^';
1088       dest[i++] = ((cid + '@') >> 6) | 0xC0;
1089       dest[i++] = ((cid + '@') & 0x3F) | 0x80;
1090       dest[i] = '\0';
1091       return i;
1092     }
1093   else if (cid <= 0x7FF)
1094     {
1095       dest[i++] = (cid >> 6) | 0xC0;
1096       dest[i++] = (cid & 0x3F) | 0x80;
1097       dest[i] = '\0';
1098       return i;
1099     }
1100   else if (cid <= 0xFFFF)
1101     {
1102       dest[i++] = (cid >> 12) | 0xE0;
1103       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
1104       dest[i++]=  (cid        & 0x3F) | 0x80;
1105       dest[i] = '\0';
1106       return i;
1107     }
1108   else if (cid <= 0x1FFFFF)
1109     {
1110       dest[i++]=  (cid >> 18) | 0xF0;
1111       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
1112       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
1113       dest[i++]=  (cid        & 0x3F) | 0x80;
1114       dest[i] = '\0';
1115       return i;
1116     }
1117   else if (cid <= 0x3FFFFFF)
1118     {
1119       dest[i++]=  (cid >> 24) | 0xF8;
1120       dest[i++]= ((cid >> 18) & 0x3F) | 0x80;
1121       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
1122       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
1123       dest[i++]=  (cid        & 0x3F) | 0x80;
1124       dest[i] = '\0';
1125       return i;
1126     }
1127   else
1128     {
1129       dest[i++]=  (cid >> 30) | 0xFC;
1130       dest[i++]= ((cid >> 24) & 0x3F) | 0x80;
1131       dest[i++]= ((cid >> 18) & 0x3F) | 0x80;
1132       dest[i++]= ((cid >> 12) & 0x3F) | 0x80;
1133       dest[i++]= ((cid >>  6) & 0x3F) | 0x80;
1134       dest[i++]=  (cid        & 0x3F) | 0x80;
1135       dest[i] = '\0';
1136       return i;
1137     }
1138 }