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