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