(concord_ds_open_genre): Use <char*> instead of <unsigned char*> for
[chise/concord.git] / concord.c
1 /* Copyright (C) 2003,2004,2005,2006 MORIOKA Tomohiko
2    This file is part of the CONCORD Library.
3
4    The CONCORD 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 CONCORD 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 CONCORD 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 "concord.h"
29 #include "concord-name.h"
30 #include "concord-bdb.h"
31
32
33 int
34 CONCORD_String_size (const CONCORD_String s)
35 {
36   return s->size;
37 }
38
39 unsigned char*
40 CONCORD_String_data (const CONCORD_String s)
41 {
42   return s->data;
43 }
44
45 CONCORD_Genre concord_ds_open_genre (CONCORD_DS ds, const char* name);
46
47 int concord_close_genre (CONCORD_Genre genre);
48
49
50 CONCORD_Feature
51 concord_genre_open_feature (CONCORD_Genre genre, const char* name);
52
53 int concord_close_feature (CONCORD_Feature feature);
54
55
56 CONCORD_INDEX
57 concord_genre_open_index (CONCORD_Genre genre, const char* index);
58
59 CONCORD_Feature
60 concord_genre_get_feature_0 (CONCORD_Genre genre, const char* name);
61
62 int concord_close_index (CONCORD_INDEX table);
63
64
65 CONCORD_Object
66 concord_default_read_object (const unsigned char* string, size_t length);
67
68
69 struct CONCORD_DS_Table
70 {
71   CONCORD_Backend_Type type;
72   char *location;
73   CONCORD_NAME_TABLE* genre_names;
74   DBTYPE subtype;
75   int modemask;
76
77   CONCORD_Object object_nil;
78   CONCORD_Object (*read_object) (const unsigned char* str, size_t length);
79 };
80
81 CONCORD_Object
82 concord_default_read_object (const unsigned char* str, size_t length)
83 {
84   unsigned char* buf = malloc (length + 1);
85
86   if (buf == NULL)
87     return NULL;
88   strncpy ((char*)buf, (char*)str, length);
89   buf[length] = '\0';
90   return buf;
91 }
92
93 CONCORD_DS
94 concord_open_ds (CONCORD_Backend_Type type, const char* location,
95                  int subtype, int modemask)
96 {
97   CONCORD_DS ds = (CONCORD_DS)malloc (sizeof (CONCORD_DS_Table));
98   size_t len = strlen (location);
99
100   if (ds == NULL)
101     return NULL;
102
103   ds->type = type;
104   ds->subtype = ( (subtype != 0) ? subtype : DB_HASH );
105   ds->modemask = modemask;
106   ds->location = (char*)malloc (len + 1);
107   if (ds->location == NULL)
108     goto location_failure;
109
110   strcpy (ds->location, location);
111
112   ds->genre_names = concord_make_name_table ();
113   if (ds->genre_names == NULL)
114     {
115       free (ds->location);
116     location_failure:
117       free (ds);
118       return NULL;
119     }
120
121   ds->object_nil = NULL;
122   ds->read_object = &concord_default_read_object;
123
124   return ds;
125 }
126
127 int
128 concord_close_ds (CONCORD_DS ds)
129 {
130   if (ds->location != NULL)
131     free (ds->location);
132   if (ds->genre_names != NULL)
133     concord_destroy_name_table (ds->genre_names);
134   free (ds);
135   return 0;
136 }
137
138 char*
139 concord_ds_location (CONCORD_DS ds)
140 {
141   return ds->location;
142 }
143
144 int
145 concord_ds_set_object_failure (CONCORD_DS ds, CONCORD_Object object_nil)
146 {
147   ds->object_nil = object_nil;
148   return 0;
149 }
150
151 int
152 concord_ds_set_read_object_function (CONCORD_DS ds,
153                                      CONCORD_Object (*read_object)
154                                      (const unsigned char* str,
155                                       size_t length))
156 {
157   ds->read_object = read_object;
158   return 0;
159 }
160
161 CONCORD_Genre
162 concord_ds_get_genre (CONCORD_DS ds, const char* name)
163 {
164   CONCORD_Genre genre;
165
166   genre = concord_name_table_get (ds->genre_names, name);
167   if (genre != NULL)
168     return genre;
169
170   genre = concord_ds_open_genre (ds, name);
171   if (genre == NULL)
172     return NULL;
173
174   if (concord_name_table_put (ds->genre_names, name, genre))
175     {
176       concord_close_genre (genre);
177       return NULL;
178     }
179   return genre;
180 }
181
182 int
183 concord_ds_foreach_genre_name (CONCORD_DS ds,
184                                int (*func) (CONCORD_DS ds, char* name))
185 {
186   char* dname = ds->location;
187   DIR *dir;
188   struct dirent *de;
189
190   if ( (dir = opendir (dname)) == NULL)
191     return -1;
192
193   while ( (de = readdir (dir)) != NULL )
194     {
195       if ( (strcmp (de->d_name, ".") != 0) &&
196            (strcmp (de->d_name, "..") != 0) )
197         {
198           int i, need_to_decode = 0;
199           unsigned char *cp;
200           char *name;
201           unsigned char *np;
202
203           for (cp = (unsigned char*)de->d_name, i = 0; *cp != '\0'; i++)
204             {
205               if (*cp++ == '%')
206                 need_to_decode = 1;
207             }
208           if (need_to_decode)
209             {
210               int index = -1;
211               int ch, c[2];
212               int hex[2];
213
214               name = (char*) alloca (i);
215               cp = (unsigned char*)de->d_name;
216               np = (unsigned char*)name;
217
218               while ( (ch = *cp++) != '\0')
219                 {
220                   if (ch == '%')
221                     {
222                       if (index >= 0)
223                         {
224                           *np++ = '%';
225                           if (index == 1)
226                             *np++ = c[0];
227                         }
228                       index = 0;
229                     }
230                   else if (index >= 0)
231                     {
232                       c[index] = ch;
233
234                       if ( ('0' <= ch) && (ch <= '9') )
235                         hex[index++] = ch - '0';
236                       else if ( ('A' <= ch) && (ch <= 'F') )
237                         hex[index++] = ch - 'A' + 10;
238                       else if ( ('a' <= ch) && (ch <= 'f') )
239                         hex[index++] = ch - 'a' + 10;
240                       else
241                         {
242                           *np++ = '%';
243                           if (index == 1)
244                             *np++ = c[0];
245                           *np++ = ch;
246                           index = -1;
247                           continue;
248                         }
249                       if (index == 2)
250                         {
251                           *np++ = (hex[0] << 4) | hex[1];
252                           index = -1;
253                           continue;
254                         }
255                     }
256                   else
257                     *np++ = ch;
258                 }
259               *np = '\0';
260             }  
261           else
262             name = de->d_name;
263
264           if (func (ds, name))
265             return closedir (dir);
266         }
267     }
268   return closedir (dir);
269 }
270
271
272 struct CONCORD_Genre_Table
273 {
274   CONCORD_DS ds;
275   char *name;
276   CONCORD_NAME_TABLE* feature_names;
277   CONCORD_NAME_TABLE* index_names;
278 };
279
280 CONCORD_Genre
281 concord_ds_open_genre (CONCORD_DS ds, const char* name)
282 {
283   CONCORD_Genre genre;
284   size_t len = strlen (name);
285
286   if (ds == NULL)
287     return NULL;
288
289   genre = (CONCORD_Genre)malloc (sizeof (CONCORD_Genre_Table));
290   if (genre == NULL)
291     return NULL;
292
293   genre->ds = ds;
294   genre->name = (char*)malloc (len + 1);
295   if (genre->name == NULL)
296     {
297       free (genre);
298       return NULL;
299     }
300   strcpy (genre->name, name);
301
302   genre->feature_names = concord_make_name_table ();
303   if (genre->feature_names == NULL)
304     {
305       free (genre->name);
306       free (genre);
307       return NULL;
308     }
309
310   genre->index_names = concord_make_name_table ();
311   if (genre->index_names == NULL)
312     {
313       free (genre->feature_names);
314       free (genre->name);
315       free (genre);
316       return NULL;
317     }
318   return genre;
319 }
320
321 int
322 concord_close_genre (CONCORD_Genre genre)
323 {
324   int status;
325
326   if (genre == NULL)
327     return -1;
328
329   if (genre->name == NULL)
330     status = -1;
331   else
332     {
333       free (genre->name);
334       status = 0;
335     }
336
337   if (genre->feature_names != NULL)
338     concord_destroy_name_table (genre->feature_names);
339
340   if (genre->index_names != NULL)
341     concord_destroy_name_table (genre->index_names);
342
343   free (genre);
344   return status;
345 }
346
347 char*
348 concord_genre_get_name (CONCORD_Genre genre)
349 {
350   return genre->name;
351 }
352
353 CONCORD_DS
354 concord_genre_get_data_source (CONCORD_Genre genre)
355 {
356   return genre->ds;
357 }
358
359 int
360 concord_genre_foreach_feature_name (CONCORD_Genre genre,
361                                     int (*func) (CONCORD_Genre genre,
362                                                  char* name))
363 {
364   char *dname
365     = alloca (strlen (genre->ds->location)
366               + 1 + strlen (genre->name) + sizeof ("/feature") + 1);
367   DIR *dir;
368   struct dirent *de;
369
370   strcpy (dname, genre->ds->location);
371   strcat (dname, "/");
372   strcat (dname, genre->name);
373   strcat (dname, "/feature");
374
375   if ( (dir = opendir (dname)) == NULL)
376     return -1;
377
378   while ( (de = readdir (dir)) != NULL )
379     {
380       if ( (strcmp (de->d_name, ".") != 0) &&
381            (strcmp (de->d_name, "..") != 0) )
382         {
383           int i, need_to_decode = 0;
384           unsigned char *cp;
385           char *name;
386           unsigned char *np;
387
388           for (cp = (unsigned char*)de->d_name, i = 0; *cp != '\0'; i++)
389             {
390               if (*cp++ == '%')
391                 need_to_decode = 1;
392             }
393           if (need_to_decode)
394             {
395               int index = -1;
396               int ch, c[2];
397               int hex[2];
398
399               name = (char*) alloca (i);
400               cp = (unsigned char*)de->d_name;
401               np = (unsigned char*)name;
402
403               while ( (ch = *cp++) != '\0')
404                 {
405                   if (ch == '%')
406                     {
407                       if (index >= 0)
408                         {
409                           *np++ = '%';
410                           if (index == 1)
411                             *np++ = c[0];
412                         }
413                       index = 0;
414                     }
415                   else if (index >= 0)
416                     {
417                       c[index] = ch;
418
419                       if ( ('0' <= ch) && (ch <= '9') )
420                         hex[index++] = ch - '0';
421                       else if ( ('A' <= ch) && (ch <= 'F') )
422                         hex[index++] = ch - 'A' + 10;
423                       else if ( ('a' <= ch) && (ch <= 'f') )
424                         hex[index++] = ch - 'a' + 10;
425                       else
426                         {
427                           *np++ = '%';
428                           if (index == 1)
429                             *np++ = c[0];
430                           *np++ = ch;
431                           index = -1;
432                           continue;
433                         }
434                       if (index == 2)
435                         {
436                           *np++ = (hex[0] << 4) | hex[1];
437                           index = -1;
438                           continue;
439                         }
440                     }
441                   else
442                     *np++ = ch;
443                 }
444               *np = '\0';
445             }  
446           else
447             name = de->d_name;
448
449           if (func (genre, name))
450             return closedir (dir);
451         }
452     }
453   return closedir (dir);
454 }
455
456 CONCORD_Feature
457 concord_genre_get_feature_0 (CONCORD_Genre genre, const char* name)
458 {
459   CONCORD_Feature feature;
460
461   feature = concord_name_table_get (genre->feature_names, name);
462   if (feature != NULL)
463     return feature;
464
465   feature = concord_genre_open_feature (genre, name);
466   if (feature == NULL)
467     return NULL;
468
469   if (concord_name_table_put (genre->feature_names, name, feature))
470     {
471       concord_close_feature (feature);
472       return NULL;
473     }
474   return feature;
475 }
476
477 CONCORD_Feature
478 concord_genre_get_feature (CONCORD_Genre genre, const char* name)
479 {
480   CONCORD_Genre g_feature
481     = concord_ds_get_genre (genre->ds, "feature");
482
483   if (g_feature != NULL)
484     {
485       CONCORD_Feature p_true_name
486         = concord_genre_get_feature_0 (g_feature, "true-name");
487
488       if (g_feature != NULL)
489         {
490           CONCORD_String_Tank s_true_name;
491           int status
492             = concord_obj_get_feature_value_string (name,
493                                                     p_true_name,
494                                                     &s_true_name);
495           if (status == 0)
496             {
497               char* t_name = alloca (s_true_name.size + 1);
498
499               strncpy (t_name, s_true_name.data, s_true_name.size);
500               t_name[s_true_name.size] = '\0';
501               return concord_genre_get_feature_0 (genre, t_name);
502             }
503         }
504     }
505   return concord_genre_get_feature_0 (genre, name);
506 }
507
508 CONCORD_INDEX
509 concord_genre_get_index (CONCORD_Genre genre, const char* name)
510 {
511   CONCORD_INDEX index;
512
513   index = concord_name_table_get (genre->index_names, name);
514   if (index != NULL)
515     return index;
516
517   index = concord_genre_open_index (genre, name);
518   if (index == NULL)
519     return NULL;
520
521   if (concord_name_table_put (genre->index_names, name, index))
522     {
523       concord_close_index (index);
524       return NULL;
525     }
526   return index;
527 }
528
529
530 struct CONCORD_Feature_Table
531 {
532   CONCORD_Genre genre;
533   char* name;
534   DB* db;
535   u_int32_t access;
536 };
537
538 CONCORD_Feature
539 concord_genre_open_feature (CONCORD_Genre genre, const char* feature)
540 {
541   CONCORD_Feature table;
542   size_t len = strlen (feature);
543
544   if (genre == NULL)
545     return NULL;
546
547   table = (CONCORD_Feature)malloc (sizeof (CONCORD_Feature_Table));
548   if (table == NULL)
549     return NULL;
550
551   table->genre = genre;
552   table->db = NULL;
553   table->access = 0;
554   table->name = (char*)malloc (len + 1);
555   if (table->name == NULL)
556     {
557       free (table);
558       return NULL;
559     }
560   strcpy (table->name, feature);
561   return table;
562 }
563
564 int
565 concord_close_feature (CONCORD_Feature feature)
566 {
567   int status;
568
569   if (feature == NULL)
570     return -1;
571
572   if (feature->db == NULL)
573     status = -1;
574   else
575     status = CONCORD_BDB_close (feature->db);
576
577   if (feature->name == NULL)
578     status = -1;
579   else
580     {
581       free (feature->name);
582       status = 0;
583     }
584   free (feature);
585   return status;
586 }
587
588 char*
589 concord_feature_get_name (CONCORD_Feature feature)
590 {
591   return feature->name;
592 }
593
594 CONCORD_Genre
595 concord_feature_get_genre (CONCORD_Feature feature)
596 {
597   return feature->genre;
598 }
599
600 int
601 concord_feature_setup_db (CONCORD_Feature feature, int writable)
602 {
603   u_int32_t access;
604
605   if (feature == NULL)
606     return -1;
607
608   if (writable)
609     {
610       if ((feature->access & DB_CREATE) == 0)
611         {
612           if (feature->db != NULL)
613             {
614               CONCORD_BDB_close (feature->db);
615               feature->db = NULL;
616             }
617           feature->access = 0;
618         }
619       access = DB_CREATE;
620     }
621   else
622     access = DB_RDONLY;
623
624   if (feature->db == NULL)
625     {
626       CONCORD_Genre genre = feature->genre;
627
628       feature->db
629         = CONCORD_BDB_open (genre->ds->location, genre->name,
630                             "feature", feature->name,
631                             genre->ds->subtype,
632                             access, genre->ds->modemask);
633       if (feature->db == NULL)
634         return -1;
635       feature->access = access;
636     }
637   return 0;
638 }
639
640 int
641 concord_feature_sync (CONCORD_Feature feature)
642 {
643   int status;
644
645   if (feature->db == NULL)
646     status = 0;
647   else
648     status = CONCORD_BDB_close (feature->db);
649   feature->db = NULL;
650   feature->access = 0;
651   return status;
652 }
653
654 int
655 concord_obj_put_feature_value_str (const char* object_id,
656                                    CONCORD_Feature feature,
657                                    unsigned char* value)
658 {
659   if (feature == NULL)
660     return -1;
661   if (concord_feature_setup_db (feature, 1))
662     return -1;
663   return CONCORD_BDB_put (feature->db, object_id, value);
664 }
665
666 int
667 concord_obj_get_feature_value_string (const char* object_id,
668                                       CONCORD_Feature feature,
669                                       CONCORD_String value)
670 {
671   int status;
672
673   if (concord_feature_setup_db (feature, 0))
674     return -1;
675   status = CONCORD_BDB_get (feature->db, object_id, value);
676   return status;
677 }
678
679 CONCORD_Object
680 concord_obj_get_feature_value (const char* object_id,
681                                CONCORD_Feature feature)
682 {
683   DBT valdatum;
684   int status;
685
686   if (concord_feature_setup_db (feature, 0))
687     return feature->genre->ds->object_nil;
688   status = CONCORD_BDB_get (feature->db, object_id, &valdatum);
689   if (status)
690     return feature->genre->ds->object_nil;
691   return (*feature->genre->ds->read_object)(valdatum.data, valdatum.size);
692 }
693
694 unsigned char*
695 concord_obj_gets_feature_value (const char* object_id,
696                                 CONCORD_Feature feature,
697                                 unsigned char* dst, size_t size)
698 {
699   DBT valdatum;
700   int status;
701
702   if (concord_feature_setup_db (feature, 0))
703     return NULL;
704   status = CONCORD_BDB_get (feature->db, object_id, &valdatum);
705   if (status)
706     return NULL;
707   if (size < valdatum.size)
708     return NULL;
709   strncpy ((char*)dst, valdatum.data, valdatum.size);
710   dst[valdatum.size] = '\0';
711   return dst;
712 }
713
714 int
715 concord_feature_foreach_obj_string (CONCORD_Feature feature,
716                                     int (*func)(CONCORD_String object_id,
717                                                 CONCORD_Feature feature,
718                                                 CONCORD_String value))
719 {
720   CONCORD_String_Tank key, value;
721   DBC *dbcp;
722   int status;
723
724   if (concord_feature_setup_db (feature, 0))
725     return -1;
726   xzero (key);
727   xzero (value);
728
729   status = feature->db->cursor (feature->db, NULL, &dbcp, 0);
730   for (status = dbcp->c_get (dbcp, &key, &value, DB_FIRST);
731        status == 0;
732        status = dbcp->c_get (dbcp, &key, &value, DB_NEXT))
733     {
734       int ret = func (&key, feature, &value);
735
736       if (ret)
737         break;
738     }
739   dbcp->c_close (dbcp);
740   return 0;
741 }
742
743
744 struct CONCORD_INDEX_Table
745 {
746   CONCORD_Genre genre;
747   char *name;
748   DB* db;
749   u_int32_t access;
750 };
751
752 CONCORD_INDEX
753 concord_genre_open_index (CONCORD_Genre genre, const char* index)
754 {
755   CONCORD_INDEX table;
756   size_t len = strlen (index);
757
758   if (genre == NULL)
759     return NULL;
760
761   table = (CONCORD_INDEX)malloc (sizeof (CONCORD_INDEX_Table));
762   if (table == NULL)
763     return NULL;
764
765   table->genre = genre;
766   table->db = NULL;
767   table->access = 0;
768   table->name = (char*)malloc (len + 1);
769   if (table->name == NULL)
770     {
771       free (table);
772       return NULL;
773     }
774   strcpy (table->name, index);
775   return table;
776 }
777
778 int
779 concord_close_index (CONCORD_INDEX table)
780 {
781   int status;
782
783   if (table == NULL)
784     return -1;
785
786   if (table->db == NULL)
787     status = 0;
788   else
789     status = CONCORD_BDB_close (table->db);
790
791   if (table->name == NULL)
792     status = -1;
793   else
794     {
795       free (table->name);
796       status = 0;
797     }
798   free (table);
799   return status;
800 }
801
802 int
803 concord_index_setup_db (CONCORD_INDEX index, int writable)
804 {
805   u_int32_t access;
806
807   if (index == NULL)
808     return -1;
809
810   if (writable)
811     {
812       if ((index->access & DB_CREATE) == 0)
813         {
814           if (index->db != NULL)
815             {
816               CONCORD_BDB_close (index->db);
817               index->db = NULL;
818             }
819           index->access = 0;
820         }
821       access = DB_CREATE;
822     }
823   else
824     access = DB_RDONLY;
825
826   if (index->db == NULL)
827     {
828       CONCORD_Genre genre = index->genre;
829
830       index->db
831         = CONCORD_BDB_open (genre->ds->location, genre->name,
832                             "index", index->name,
833                             genre->ds->subtype,
834                             access, genre->ds->modemask);
835       if (index->db == NULL)
836         return -1;
837       index->access = access;
838     }
839   return 0;
840 }
841
842 int
843 concord_index_sync (CONCORD_INDEX index)
844 {
845   int status;
846
847   if (index->db == NULL)
848     status = 0;
849   else
850     status = CONCORD_BDB_close (index->db);
851   index->db = NULL;
852   index->access = 0;
853   return status;
854 }
855
856 int
857 concord_index_strid_put_obj (CONCORD_INDEX index,
858                              const char* strid, char* object_id)
859 {
860   if (index == NULL)
861     return -1;
862
863   if (concord_index_setup_db (index, 1))
864     return -1;  
865
866   return CONCORD_BDB_put (index->db, strid, (unsigned char*)object_id);
867 }
868
869 int
870 concord_index_strid_get_obj_string (CONCORD_INDEX index,
871                                     const char* strid,
872                                     CONCORD_String object_id)
873 {
874   if (index == NULL)
875     return -1;
876
877   if (concord_index_setup_db (index, 0))
878     return -1;  
879
880   return CONCORD_BDB_get (index->db, strid, object_id);
881 }