On Unix, zebra/z'mbol uses automake.
[idzebra-moved-to-github.git] / index / zebraapi.c
1 /*
2  * Copyright (C) 1995-2000, Index Data
3  * All rights reserved.
4  *
5  * $Log: zebraapi.c,v $
6  * Revision 1.30  2000-04-05 09:49:35  adam
7  * On Unix, zebra/z'mbol uses automake.
8  *
9  * Revision 1.29  2000/03/20 19:08:36  adam
10  * Added remote record import using Z39.50 extended services and Segment
11  * Requests.
12  *
13  * Revision 1.28  2000/03/15 15:00:30  adam
14  * First work on threaded version.
15  *
16  * Revision 1.27  2000/02/24 12:31:17  adam
17  * Added zebra_string_norm.
18  *
19  * Revision 1.26  1999/11/30 13:48:03  adam
20  * Improved installation. Updated for inclusion of YAZ header files.
21  *
22  * Revision 1.25  1999/11/04 15:00:45  adam
23  * Implemented delete result set(s).
24  *
25  * Revision 1.24  1999/10/14 14:33:50  adam
26  * Added truncation 5=106.
27  *
28  * Revision 1.23  1999/09/07 11:36:32  adam
29  * Minor changes.
30  *
31  * Revision 1.22  1999/08/02 10:13:47  adam
32  * Fixed bug regarding zebra_hits.
33  *
34  * Revision 1.21  1999/07/14 10:59:26  adam
35  * Changed functions isc_getmethod, isams_getmethod.
36  * Improved fatal error handling (such as missing EXPLAIN schema).
37  *
38  * Revision 1.20  1999/07/06 12:28:04  adam
39  * Updated record index structure. Format includes version ID. Compression
40  * algorithm ID is stored for each record block.
41  *
42  * Revision 1.19  1999/05/26 07:49:13  adam
43  * C++ compilation.
44  *
45  * Revision 1.18  1999/05/15 14:36:38  adam
46  * Updated dictionary. Implemented "compression" of dictionary.
47  *
48  * Revision 1.17  1999/05/12 13:08:06  adam
49  * First version of ISAMS.
50  *
51  * Revision 1.16  1999/02/19 10:38:30  adam
52  * Implemented chdir-setting.
53  *
54  * Revision 1.15  1999/02/17 12:18:12  adam
55  * Fixed zebra_close so that a NULL pointer is ignored.
56  *
57  * Revision 1.14  1999/02/02 14:51:11  adam
58  * Updated WIN32 code specific sections. Changed header.
59  *
60  * Revision 1.13  1998/12/16 12:23:30  adam
61  * Added facility for database name mapping using resource mapdb.
62  *
63  * Revision 1.12  1998/11/16 10:18:10  adam
64  * Better error reporting for result sets.
65  *
66  * Revision 1.11  1998/10/16 08:14:34  adam
67  * Updated record control system.
68  *
69  * Revision 1.10  1998/09/22 10:03:42  adam
70  * Changed result sets to be persistent in the sense that they can
71  * be re-searched if needed.
72  * Fixed memory leak in rsm_or.
73  *
74  * Revision 1.9  1998/09/02 13:53:17  adam
75  * Extra parameter decode added to search routines to implement
76  * persistent queries.
77  *
78  * Revision 1.8  1998/08/24 17:29:23  adam
79  * Minor changes.
80  *
81  * Revision 1.7  1998/06/24 12:16:13  adam
82  * Support for relations on text operands. Open range support in
83  * DFA module (i.e. [-j], [g-]).
84  *
85  * Revision 1.6  1998/06/22 11:36:47  adam
86  * Added authentication check facility to zebra.
87  *
88  * Revision 1.5  1998/06/13 00:14:08  adam
89  * Minor changes.
90  *
91  * Revision 1.4  1998/06/12 12:22:12  adam
92  * Work on Zebra API.
93  *
94  * Revision 1.3  1998/05/27 16:57:44  adam
95  * Zebra returns surrogate diagnostic for single records when
96  * appropriate.
97  *
98  * Revision 1.2  1998/05/20 10:12:19  adam
99  * Implemented automatic EXPLAIN database maintenance.
100  * Modified Zebra to work with ASN.1 compiled version of YAZ.
101  *
102  * Revision 1.1  1998/03/05 08:45:13  adam
103  * New result set model and modular ranking system. Moved towards
104  * descent server API. System information stored as "SGML" records.
105  *
106  */
107
108 #include <assert.h>
109 #include <stdio.h>
110 #ifdef WIN32
111 #include <io.h>
112 #include <process.h>
113 #include <direct.h>
114 #else
115 #include <unistd.h>
116 #endif
117
118 #include <yaz/diagbib1.h>
119 #include "zserver.h"
120 #include <charmap.h>
121
122 static void zebra_chdir (ZebraService zh)
123 {
124     const char *dir = res_get (zh->res, "chdir");
125     if (!dir)
126         return;
127     logf (LOG_DEBUG, "chdir %s", dir);
128 #ifdef WIN32
129     _chdir(dir);
130 #else
131     chdir (dir);
132 #endif
133 }
134
135 static int extract_rec_in_mem (ZebraHandle zh, const char *recordType,
136                                const char *buf, size_t buf_size,
137                                const char *databaseName, int delete_flag,
138                                int test_mode, int *sysno,
139                                int store_keys, int store_data,
140                                const char *match_criteria);
141
142 static int explain_extract (void *handle, Record rec, data1_node *n);
143 static void extract_index (ZebraHandle zh);
144
145 static void zebra_register_unlock (ZebraHandle zh);
146
147 static int zebra_register_lock (ZebraHandle zh)
148 {
149     zh->errCode = 0;
150     zh->errString = 0;
151     if (!zh->service->active)
152     {
153         zh->errCode = 1019;
154         return 1;
155     }
156     return 0;
157 }
158
159 static void zebra_register_unlock (ZebraHandle zh)
160 {
161 }
162
163 ZebraHandle zebra_open (ZebraService zs)
164 {
165     ZebraHandle zh;
166
167     assert (zs);
168     if (zs->stop_flag)
169     {
170         zh->errCode = 1019;
171         return 0;
172     }
173
174     zh = (ZebraHandle) xmalloc (sizeof(*zh));
175
176     zh->service = zs;
177     zh->sets = 0;
178     zh->destroyed = 0;
179     zh->errCode = 0;
180     zh->errString = 0;
181
182     zh->key_buf = 0;
183     zh->admin_databaseName = 0;
184     
185     zebra_mutex_cond_lock (&zs->session_lock);
186
187     zh->next = zs->sessions;
188     zs->sessions = zh;
189
190     zebra_mutex_cond_unlock (&zs->session_lock);
191     return zh;
192 }
193
194 static int zebra_register_activate (ZebraService zh);
195 static int zebra_register_deactivate (ZebraService zh);
196
197 ZebraService zebra_start (const char *configName)
198 {
199     ZebraService zh = xmalloc (sizeof(*zh));
200
201     yaz_log (LOG_LOG, "zebra_start %s", configName);
202
203     zh->configName = xstrdup(configName);
204     zh->sessions = 0;
205     zh->stop_flag = 0;
206     zh->active = 0;
207     zebra_mutex_cond_init (&zh->session_lock);
208     zebra_register_activate (zh);
209     return zh;
210 }
211
212 static int zebra_register_activate (ZebraService zh)
213 {
214     if (zh->active)
215         return 0;
216     yaz_log (LOG_LOG, "zebra_register_activate");
217     if (!(zh->res = res_open (zh->configName)))
218     {
219         logf (LOG_WARN, "Failed to read resources `%s'", zh->configName);
220         return -1;
221     }
222     zebra_chdir (zh);
223     zh->dh = data1_create ();
224     if (!zh->dh)
225         return -1;
226     zh->bfs = bfs_create (res_get (zh->res, "register"));
227     if (!zh->bfs)
228     {
229         data1_destroy(zh->dh);
230         return -1;
231     }
232     bf_lockDir (zh->bfs, res_get (zh->res, "lockDir"));
233     data1_set_tabpath (zh->dh, res_get(zh->res, "profilePath"));
234     zh->registerState = -1;  /* trigger open of registers! */
235     zh->registerChange = 0;
236     zh->recTypes = recTypes_init (zh->dh);
237     recTypes_default_handlers (zh->recTypes);
238
239     zh->records = NULL;
240     zh->zebra_maps = zebra_maps_open (zh->res);
241     zh->rank_classes = NULL;
242
243     zh->records = 0;
244     zh->dict = 0;
245     zh->sortIdx = 0;
246     zh->isams = 0;
247     zh->isam = 0;
248     zh->isamc = 0;
249     zh->isamd = 0;
250     zh->zei = 0;
251     
252     zebraRankInstall (zh, rank1_class);
253
254     if (!res_get (zh->res, "passwd"))
255         zh->passwd_db = NULL;
256     else
257     {
258         zh->passwd_db = passwd_db_open ();
259         if (!zh->passwd_db)
260             logf (LOG_WARN|LOG_ERRNO, "passwd_db_open failed");
261         else
262             passwd_db_file (zh->passwd_db, res_get (zh->res, "passwd"));
263     }
264
265     if (!(zh->records = rec_open (zh->bfs, 1, 0)))
266     {
267         logf (LOG_WARN, "rec_open");
268         return -1;
269     }
270     if (!(zh->dict = dict_open (zh->bfs, FNAME_DICT, 40, 1, 0)))
271     {
272         logf (LOG_WARN, "dict_open");
273         return -1;
274     }
275     if (!(zh->sortIdx = sortIdx_open (zh->bfs, 0)))
276     {
277         logf (LOG_WARN, "sortIdx_open");
278         return -1;
279     }
280     if (res_get_match (zh->res, "isam", "s", ISAM_DEFAULT))
281     {
282         struct ISAMS_M_s isams_m;
283         if (!(zh->isams = isams_open (zh->bfs, FNAME_ISAMS, 1,
284                                       key_isams_m(zh->res, &isams_m))))
285         {
286             logf (LOG_WARN, "isams_open");
287             return -1;
288         }
289     }
290 #if ZMBOL
291     else if (res_get_match (zh->res, "isam", "i", ISAM_DEFAULT))
292     {
293         if (!(zh->isam = is_open (zh->bfs, FNAME_ISAM, key_compare, 1,
294                                   sizeof (struct it_key), zh->res)))
295         {
296             logf (LOG_WARN, "is_open");
297             return -1;
298         }
299     }
300     else if (res_get_match (zh->res, "isam", "c", ISAM_DEFAULT))
301     {
302         struct ISAMC_M_s isamc_m;
303         if (!(zh->isamc = isc_open (zh->bfs, FNAME_ISAMC,
304                                     1, key_isamc_m(zh->res, &isamc_m))))
305         {
306             logf (LOG_WARN, "isc_open");
307             return -1;
308         }
309     }
310     else if (res_get_match (zh->res, "isam", "d", ISAM_DEFAULT))
311     {
312         struct ISAMD_M_s isamd_m;
313         
314         if (!(zh->isamd = isamd_open (zh->bfs, FNAME_ISAMD,
315                                       1, key_isamd_m(zh->res, &isamd_m))))
316         {
317             logf (LOG_WARN, "isamd_open");
318             return -1;
319         }
320     }
321 #endif
322     zh->zei = zebraExplain_open (zh->records, zh->dh,
323                                  zh->res, 1, 0 /* rGroup */,
324                                  explain_extract);
325     if (!zh->zei)
326     {
327         logf (LOG_WARN, "Cannot obtain EXPLAIN information");
328         return -1;
329     }
330     zh->active = 1;
331     yaz_log (LOG_LOG, "zebra_register_activate ok");
332     return 0;
333 }
334
335 void zebra_admin_shutdown (ZebraHandle zh)
336 {
337     zebraExplain_flush (zh->service->zei, 1, zh);
338     extract_index (zh);
339
340     zebra_mutex_cond_lock (&zh->service->session_lock);
341     zh->service->stop_flag = 1;
342     if (!zh->service->sessions)
343         zebra_register_deactivate(zh->service);
344     zebra_mutex_cond_unlock (&zh->service->session_lock);
345 }
346
347 void zebra_admin_start (ZebraHandle zh)
348 {
349     ZebraService zs = zh->service;
350     zh->errCode = 0;
351     zebra_mutex_cond_lock (&zs->session_lock);
352     if (!zs->stop_flag)
353         zebra_register_activate(zs);
354     zebra_mutex_cond_unlock (&zs->session_lock);
355 }
356
357 static int zebra_register_deactivate (ZebraService zh)
358 {
359     zh->stop_flag = 0;
360     if (!zh->active)
361         return 0;
362     yaz_log(LOG_LOG, "zebra_register_deactivate");
363     zebra_chdir (zh);
364     if (zh->records)
365     {
366         zebraExplain_close (zh->zei, 1);
367         dict_close (zh->dict);
368         sortIdx_close (zh->sortIdx);
369         if (zh->isams)
370             isams_close (zh->isams);
371 #if ZMBOL
372         if (zh->isam)
373             is_close (zh->isam);
374         if (zh->isamc)
375             isc_close (zh->isamc);
376         if (zh->isamd)
377             isamd_close (zh->isamd);
378 #endif
379         rec_close (&zh->records);
380     }
381     recTypes_destroy (zh->recTypes);
382     zebra_maps_close (zh->zebra_maps);
383     zebraRankDestroy (zh);
384     bfs_destroy (zh->bfs);
385     data1_destroy (zh->dh);
386
387     if (zh->passwd_db)
388         passwd_db_close (zh->passwd_db);
389     res_close (zh->res);
390     zh->active = 0;
391     return 0;
392 }
393
394 void zebra_stop(ZebraService zh)
395 {
396     if (!zh)
397         return ;
398     yaz_log (LOG_LOG, "zebra_stop");
399
400     assert (!zh->sessions);
401
402     zebra_mutex_cond_destroy (&zh->session_lock);
403
404     zebra_register_deactivate(zh);
405     xfree (zh->configName);
406     xfree (zh);
407 }
408
409 void zebra_close (ZebraHandle zh)
410 {
411     ZebraService zs = zh->service;
412     struct zebra_session **sp;
413     if (!zh)
414         return ;
415     resultSetDestroy (zh, -1, 0, 0);
416
417     if (zh->key_buf)
418     {
419         xfree (zh->key_buf);
420         zh->key_buf = 0;
421     }
422     xfree (zh->admin_databaseName);
423     zebra_mutex_cond_lock (&zs->session_lock);
424     sp = &zs->sessions;
425     while (1)
426     {
427         assert (*sp);
428         if (*sp == zh)
429         {
430             *sp = (*sp)->next;
431             break;
432         }
433         sp = &(*sp)->next;
434     }
435     if (!zs->sessions && zs->stop_flag)
436         zebra_register_deactivate(zs);
437     zebra_mutex_cond_unlock (&zs->session_lock);
438     xfree (zh);
439 }
440
441 struct map_baseinfo {
442     ZebraHandle zh;
443     NMEM mem;
444     int num_bases;
445     char **basenames;
446     int new_num_bases;
447     char **new_basenames;
448     int new_num_max;
449 };
450         
451 void map_basenames_func (void *vp, const char *name, const char *value)
452 {
453     struct map_baseinfo *p = (struct map_baseinfo *) vp;
454     int i, no;
455     char fromdb[128], todb[8][128];
456     
457     no =
458         sscanf (value, "%127s %127s %127s %127s %127s %127s %127s %127s %127s",
459                 fromdb, todb[0], todb[1], todb[2], todb[3], todb[4],
460                 todb[5], todb[6], todb[7]);
461     if (no < 2)
462         return ;
463     no--;
464     for (i = 0; i<p->num_bases; i++)
465         if (p->basenames[i] && !strcmp (p->basenames[i], fromdb))
466         {
467             p->basenames[i] = 0;
468             for (i = 0; i < no; i++)
469             {
470                 if (p->new_num_bases == p->new_num_max)
471                     return;
472                 p->new_basenames[(p->new_num_bases)++] = 
473                     nmem_strdup (p->mem, todb[i]);
474             }
475             return;
476         }
477 }
478
479 void map_basenames (ZebraHandle zh, ODR stream,
480                     int *num_bases, char ***basenames)
481 {
482     struct map_baseinfo info;
483     struct map_baseinfo *p = &info;
484     int i;
485
486     info.zh = zh;
487     info.num_bases = *num_bases;
488     info.basenames = *basenames;
489     info.new_num_max = 128;
490     info.new_num_bases = 0;
491     info.new_basenames = (char **)
492         odr_malloc (stream, sizeof(*info.new_basenames) * info.new_num_max);
493     info.mem = stream->mem;
494
495     res_trav (zh->service->res, "mapdb", &info, map_basenames_func);
496     
497     for (i = 0; i<p->num_bases; i++)
498         if (p->basenames[i] && p->new_num_bases < p->new_num_max)
499         {
500             p->new_basenames[(p->new_num_bases)++] = 
501                 nmem_strdup (p->mem, p->basenames[i]);
502         }
503     *num_bases = info.new_num_bases;
504     *basenames = info.new_basenames;
505     for (i = 0; i<*num_bases; i++)
506         logf (LOG_LOG, "base %s", (*basenames)[i]);
507 }
508
509 void zebra_search_rpn (ZebraHandle zh, ODR stream, ODR decode,
510                        Z_RPNQuery *query, int num_bases, char **basenames, 
511                        const char *setname)
512 {
513     zh->hits = 0;
514     if (zebra_register_lock (zh))
515         return;
516     map_basenames (zh, stream, &num_bases, &basenames);
517     resultSetAddRPN (zh, stream, decode, query, num_bases, basenames, setname);
518
519     zebra_register_unlock (zh);
520 }
521
522 void zebra_records_retrieve (ZebraHandle zh, ODR stream,
523                              const char *setname, Z_RecordComposition *comp,
524                              oid_value input_format, int num_recs,
525                              ZebraRetrievalRecord *recs)
526 {
527     ZebraPosSet poset;
528     int i, *pos_array;
529
530     if (zebra_register_lock (zh))
531         return;
532     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
533     for (i = 0; i<num_recs; i++)
534         pos_array[i] = recs[i].position;
535     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
536     if (!poset)
537     {
538         logf (LOG_DEBUG, "zebraPosSetCreate error");
539         zh->errCode = 30;
540         zh->errString = nmem_strdup (stream->mem, setname);
541     }
542     else
543     {
544         for (i = 0; i<num_recs; i++)
545         {
546             if (!poset[i].sysno)
547             {
548                 char num_str[20];
549
550                 sprintf (num_str, "%d", pos_array[i]);  
551                 zh->errCode = 13;
552                 zh->errString = nmem_strdup (stream->mem, num_str);
553                 break;
554             }
555             else
556             {
557                 recs[i].errCode =
558                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
559                                         stream, input_format, comp,
560                                         &recs[i].format, &recs[i].buf,
561                                         &recs[i].len,
562                                         &recs[i].base);
563                 recs[i].errString = NULL;
564             }
565         }
566         zebraPosSetDestroy (zh, poset, num_recs);
567     }
568     zebra_register_unlock (zh);
569     xfree (pos_array);
570 }
571
572 void zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
573                  oid_value attributeset,
574                  int num_bases, char **basenames,
575                  int *position, int *num_entries, ZebraScanEntry **entries,
576                  int *is_partial)
577 {
578     if (zebra_register_lock (zh))
579     {
580         *entries = 0;
581         *num_entries = 0;
582         return;
583     }
584     map_basenames (zh, stream, &num_bases, &basenames);
585     rpn_scan (zh, stream, zapt, attributeset,
586               num_bases, basenames, position,
587               num_entries, entries, is_partial);
588     zebra_register_unlock (zh);
589 }
590
591 void zebra_sort (ZebraHandle zh, ODR stream,
592                  int num_input_setnames, const char **input_setnames,
593                  const char *output_setname, Z_SortKeySpecList *sort_sequence,
594                  int *sort_status)
595 {
596     if (zebra_register_lock (zh))
597         return;
598     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
599                    output_setname, sort_sequence, sort_status);
600     zebra_register_unlock (zh);
601 }
602
603 int zebra_deleleResultSet(ZebraHandle zh, int function,
604                           int num_setnames, char **setnames,
605                           int *statuses)
606 {
607     int i, status;
608     if (zebra_register_lock (zh))
609         return Z_DeleteStatus_systemProblemAtTarget;
610     switch (function)
611     {
612     case Z_DeleteRequest_list:
613         resultSetDestroy (zh, num_setnames, setnames, statuses);
614         break;
615     case Z_DeleteRequest_all:
616         resultSetDestroy (zh, -1, 0, statuses);
617         break;
618     }
619     zebra_register_unlock (zh);
620     status = Z_DeleteStatus_success;
621     for (i = 0; i<num_setnames; i++)
622         if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
623             status = statuses[i];
624     return status;
625 }
626
627 int zebra_errCode (ZebraHandle zh)
628 {
629     return zh->errCode;
630 }
631
632 const char *zebra_errString (ZebraHandle zh)
633 {
634     return diagbib1_str (zh->errCode);
635 }
636
637 char *zebra_errAdd (ZebraHandle zh)
638 {
639     return zh->errString;
640 }
641
642 int zebra_hits (ZebraHandle zh)
643 {
644     return zh->hits;
645 }
646
647 int zebra_auth (ZebraService zh, const char *user, const char *pass)
648 {
649     if (!zh->passwd_db || !passwd_db_auth (zh->passwd_db, user, pass))
650         return 0;
651     return 1;
652 }
653
654 void zebra_admin_import_begin (ZebraHandle zh, const char *database)
655 {
656     if (zebra_register_lock (zh))
657         return;
658     xfree (zh->admin_databaseName);
659     zh->admin_databaseName = xstrdup(database);
660     zebra_register_unlock(zh);
661 }
662
663 void zebra_admin_import_end (ZebraHandle zh)
664 {
665     zebraExplain_flush (zh->service->zei, 1, zh);
666     extract_index (zh);
667 }
668
669 void zebra_admin_import_segment (ZebraHandle zh, Z_Segment *segment)
670 {
671     int sysno;
672     int i;
673     if (zebra_register_lock (zh))
674         return;
675     for (i = 0; i<segment->num_segmentRecords; i++)
676     {
677         Z_NamePlusRecord *npr = segment->segmentRecords[i];
678         const char *databaseName = npr->databaseName;
679
680         if (!databaseName)
681             databaseName = zh->admin_databaseName;
682         printf ("--------------%d--------------------\n", i);
683         if (npr->which == Z_NamePlusRecord_intermediateFragment)
684         {
685             Z_FragmentSyntax *fragment = npr->u.intermediateFragment;
686             if (fragment->which == Z_FragmentSyntax_notExternallyTagged)
687             {
688                 Odr_oct *oct = fragment->u.notExternallyTagged;
689                 printf ("%.*s", (oct->len > 100 ? 100 : oct->len) ,
690                         oct->buf);
691                 
692                 sysno = 0;
693                 extract_rec_in_mem (zh, "grs.sgml",
694                                     oct->buf, oct->len,
695                                     databaseName,
696                                     0 /* delete_flag */,
697                                     0 /* test_mode */,
698                                     &sysno /* sysno */,
699                                     1 /* store_keys */,
700                                     1 /* store_data */,
701                                     0 /* match criteria */);
702             }
703         }
704     }
705     zebra_register_unlock(zh);
706 }
707
708 void zebra_admin_create (ZebraHandle zh, const char *database)
709 {
710     ZebraService zs = zh->service;
711     if (zebra_register_lock(zh))
712     {
713         zh->errCode = 1019;
714         return;
715     }
716     /* announce database */
717     if (zebraExplain_newDatabase (zs->zei, database, 0 /* explainDatabase */))
718     {
719         zh->errCode = 224;
720         zh->errString = "Database already exist";
721     }
722     zebra_register_unlock(zh);
723 }
724
725 int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
726                        const char *input_str, int input_len,
727                        char *output_str, int output_len)
728 {
729     WRBUF wrbuf;
730     if (!zh->service->zebra_maps)
731         return -1;
732     wrbuf = zebra_replace(zh->service->zebra_maps, reg_id, "",
733                           input_str, input_len);
734     if (!wrbuf)
735         return -2;
736     if (wrbuf_len(wrbuf) >= output_len)
737         return -3;
738     if (wrbuf_len(wrbuf))
739         memcpy (output_str, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
740     output_str[wrbuf_len(wrbuf)] = '\0';
741     return wrbuf_len(wrbuf);
742 }
743
744 static void extract_init (struct recExtractCtrl *p, RecWord *w)
745 {
746     w->zebra_maps = p->zebra_maps;
747     w->seqnos = p->seqno;
748     w->attrSet = VAL_BIB1;
749     w->attrUse = 1016;
750     w->reg_type = 'w';
751     w->extractCtrl = p;
752 }
753
754 static void extract_add_index_string (RecWord *p, const char *string,
755                                       int length)
756 {
757     char *dst;
758     unsigned char attrSet;
759     unsigned short attrUse;
760     int lead = 0;
761     int diff = 0;
762     int *pseqno = &p->seqnos[p->reg_type];
763     ZebraHandle zh = p->extractCtrl->handle;
764     struct recKeys *keys = &zh->keys;
765
766     if (keys->buf_used+1024 > keys->buf_max)
767     {
768         char *b;
769
770         b = (char *) xmalloc (keys->buf_max += 128000);
771         if (keys->buf_used > 0)
772             memcpy (b, keys->buf, keys->buf_used);
773         xfree (keys->buf);
774         keys->buf = b;
775     }
776     dst = keys->buf + keys->buf_used;
777
778     attrSet = p->attrSet;
779     if (keys->buf_used > 0 && keys->prevAttrSet == attrSet)
780         lead |= 1;
781     else
782         keys->prevAttrSet = attrSet;
783     attrUse = p->attrUse;
784     if (keys->buf_used > 0 && keys->prevAttrUse == attrUse)
785         lead |= 2;
786     else
787         keys->prevAttrUse = attrUse;
788 #if 1
789     diff = 1 + *pseqno - keys->prevSeqNo;
790     if (diff >= 1 && diff <= 15)
791         lead |= (diff << 2);
792     else
793         diff = 0;
794 #endif
795     keys->prevSeqNo = *pseqno;
796     
797     *dst++ = lead;
798
799     if (!(lead & 1))
800     {
801         memcpy (dst, &attrSet, sizeof(attrSet));
802         dst += sizeof(attrSet);
803     }
804     if (!(lead & 2))
805     {
806         memcpy (dst, &attrUse, sizeof(attrUse));
807         dst += sizeof(attrUse);
808     }
809     *dst++ = p->reg_type;
810     memcpy (dst, string, length);
811     dst += length;
812     *dst++ = '\0';
813
814     if (!diff)
815     {
816         memcpy (dst, pseqno, sizeof(*pseqno));
817         dst += sizeof(*pseqno);
818     }
819     keys->buf_used = dst - keys->buf;
820     if (*pseqno)
821         (*pseqno)++;
822 }
823
824 static void extract_add_sort_string (RecWord *p, const char *string,
825                                      int length)
826 {
827     struct sortKey *sk;
828     ZebraHandle zh = p->extractCtrl->handle;
829     struct sortKey *sortKeys = zh->sortKeys;
830
831     for (sk = sortKeys; sk; sk = sk->next)
832         if (sk->attrSet == p->attrSet && sk->attrUse == p->attrUse)
833             return;
834
835     sk = (struct sortKey *) xmalloc (sizeof(*sk));
836     sk->next = sortKeys;
837     sortKeys = sk;
838
839     sk->string = (char *) xmalloc (length);
840     sk->length = length;
841     memcpy (sk->string, string, length);
842
843     sk->attrSet = p->attrSet;
844     sk->attrUse = p->attrUse;
845 }
846
847 static void extract_add_string (RecWord *p, const char *string, int length)
848 {
849     assert (length > 0);
850     if (zebra_maps_is_sort (p->zebra_maps, p->reg_type))
851         extract_add_sort_string (p, string, length);
852     else
853         extract_add_index_string (p, string, length);
854 }
855
856 static void extract_add_incomplete_field (RecWord *p)
857 {
858     const char *b = p->string;
859     int remain = p->length;
860     const char **map = 0;
861
862     if (remain > 0)
863         map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
864
865     while (map)
866     {
867         char buf[IT_MAX_WORD+1];
868         int i, remain;
869
870         /* Skip spaces */
871         while (map && *map && **map == *CHR_SPACE)
872         {
873             remain = p->length - (b - p->string);
874             if (remain > 0)
875                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
876             else
877                 map = 0;
878         }
879         if (!map)
880             break;
881         i = 0;
882         while (map && *map && **map != *CHR_SPACE)
883         {
884             const char *cp = *map;
885
886             while (i < IT_MAX_WORD && *cp)
887                 buf[i++] = *(cp++);
888             remain = p->length - (b - p->string);
889             if (remain > 0)
890                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
891             else
892                 map = 0;
893         }
894         if (!i)
895             return;
896         extract_add_string (p, buf, i);
897     }
898     (p->seqnos[p->reg_type])++; /* to separate this from next one  */
899 }
900
901 static void extract_add_complete_field (RecWord *p)
902 {
903     const char *b = p->string;
904     char buf[IT_MAX_WORD+1];
905     const char **map = 0;
906     int i = 0, remain = p->length;
907
908     if (remain > 0)
909         map = zebra_maps_input (p->zebra_maps, p->reg_type, &b, remain);
910
911     while (remain > 0 && i < IT_MAX_WORD)
912     {
913         while (map && *map && **map == *CHR_SPACE)
914         {
915             remain = p->length - (b - p->string);
916             if (remain > 0)
917                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
918             else
919                 map = 0;
920         }
921         if (!map)
922             break;
923
924         if (i && i < IT_MAX_WORD)
925             buf[i++] = *CHR_SPACE;
926         while (map && *map && **map != *CHR_SPACE)
927         {
928             const char *cp = *map;
929
930             if (i >= IT_MAX_WORD)
931                 break;
932             while (i < IT_MAX_WORD && *cp)
933                 buf[i++] = *(cp++);
934             remain = p->length  - (b - p->string);
935             if (remain > 0)
936                 map = zebra_maps_input (p->zebra_maps, p->reg_type, &b,
937                                         remain);
938             else
939                 map = 0;
940         }
941     }
942     if (!i)
943         return;
944     extract_add_string (p, buf, i);
945 }
946
947 static void extract_token_add (RecWord *p)
948 {
949     WRBUF wrbuf;
950     if ((wrbuf = zebra_replace(p->zebra_maps, p->reg_type, 0,
951                                p->string, p->length)))
952     {
953         p->string = wrbuf_buf(wrbuf);
954         p->length = wrbuf_len(wrbuf);
955     }
956     if (zebra_maps_is_complete (p->zebra_maps, p->reg_type))
957         extract_add_complete_field (p);
958     else
959         extract_add_incomplete_field(p);
960 }
961
962 static void extract_schema_add (struct recExtractCtrl *p, Odr_oid *oid)
963 {
964     ZebraHandle zh = (ZebraHandle) (p->handle);
965     zebraExplain_addSchema (zh->service->zei, oid);
966 }
967
968 static void extract_flushSortKeys (ZebraHandle zh, SYSNO sysno,
969                                    int cmd, struct sortKey **skp)
970 {
971     struct sortKey *sk = *skp;
972     SortIdx sortIdx = zh->service->sortIdx;
973
974     sortIdx_sysno (sortIdx, sysno);
975     while (sk)
976     {
977         struct sortKey *sk_next = sk->next;
978         sortIdx_type (sortIdx, sk->attrUse);
979         sortIdx_add (sortIdx, sk->string, sk->length);
980         xfree (sk->string);
981         xfree (sk);
982         sk = sk_next;
983     }
984     *skp = 0;
985 }
986
987 struct encode_info {
988     int  sysno;
989     int  seqno;
990     int  cmd;
991     char buf[768];
992 };
993
994 void encode_key_init (struct encode_info *i)
995 {
996     i->sysno = 0;
997     i->seqno = 0;
998     i->cmd = -1;
999 }
1000
1001 char *encode_key_int (int d, char *bp)
1002 {
1003     if (d <= 63)
1004         *bp++ = d;
1005     else if (d <= 16383)
1006     {
1007         *bp++ = 64 + (d>>8);
1008         *bp++ = d  & 255;
1009     }
1010     else if (d <= 4194303)
1011     {
1012         *bp++ = 128 + (d>>16);
1013         *bp++ = (d>>8) & 255;
1014         *bp++ = d & 255;
1015     }
1016     else
1017     {
1018         *bp++ = 192 + (d>>24);
1019         *bp++ = (d>>16) & 255;
1020         *bp++ = (d>>8) & 255;
1021         *bp++ = d & 255;
1022     }
1023     return bp;
1024 }
1025
1026 void encode_key_write (char *k, struct encode_info *i, FILE *outf)
1027 {
1028     struct it_key key;
1029     char *bp = i->buf;
1030
1031     while ((*bp++ = *k++))
1032         ;
1033     memcpy (&key, k+1, sizeof(struct it_key));
1034     bp = encode_key_int ( (key.sysno - i->sysno) * 2 + *k, bp);
1035     if (i->sysno != key.sysno)
1036     {
1037         i->sysno = key.sysno;
1038         i->seqno = 0;
1039     }
1040     else if (!i->seqno && !key.seqno && i->cmd == *k)
1041         return;
1042     bp = encode_key_int (key.seqno - i->seqno, bp);
1043     i->seqno = key.seqno;
1044     i->cmd = *k;
1045     if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
1046     {
1047         logf (LOG_FATAL|LOG_ERRNO, "fwrite");
1048         exit (1);
1049     }
1050 }
1051
1052 static void extract_flushWriteKeys (ZebraHandle zh)
1053 {
1054     FILE *outf;
1055     char out_fname[200];
1056     char *prevcp, *cp;
1057     struct encode_info encode_info;
1058     int ptr_i = zh->ptr_i;
1059 #if SORT_EXTRA
1060     int i;
1061 #endif
1062     if (!zh->key_buf || ptr_i <= 0)
1063         return;
1064
1065     (zh->key_file_no)++;
1066     logf (LOG_LOG, "sorting section %d", (zh->key_file_no));
1067 #if !SORT_EXTRA
1068     qsort (zh->key_buf + zh->ptr_top - ptr_i, ptr_i, sizeof(char*),
1069             key_qsort_compare);
1070     extract_get_fname_tmp (zh, out_fname, zh->key_file_no);
1071
1072     if (!(outf = fopen (out_fname, "wb")))
1073     {
1074         logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
1075         exit (1);
1076     }
1077     logf (LOG_LOG, "writing section %d", zh->key_file_no);
1078     prevcp = cp = (zh->key_buf)[zh->ptr_top - ptr_i];
1079     
1080     encode_key_init (&encode_info);
1081     encode_key_write (cp, &encode_info, outf);
1082     
1083     while (--ptr_i > 0)
1084     {
1085         cp = (zh->key_buf)[zh->ptr_top - ptr_i];
1086         if (strcmp (cp, prevcp))
1087         {
1088             encode_key_init (&encode_info);
1089             encode_key_write (cp, &encode_info, outf);
1090             prevcp = cp;
1091         }
1092         else
1093             encode_key_write (cp + strlen(cp), &encode_info, outf);
1094     }
1095 #else
1096     qsort (key_buf + ptr_top-ptr_i, ptr_i, sizeof(char*), key_x_compare);
1097     extract_get_fname_tmp (out_fname, key_file_no);
1098
1099     if (!(outf = fopen (out_fname, "wb")))
1100     {
1101         logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
1102         exit (1);
1103     }
1104     logf (LOG_LOG, "writing section %d", key_file_no);
1105     i = ptr_i;
1106     prevcp =  key_buf[ptr_top-i];
1107     while (1)
1108         if (!--i || strcmp (prevcp, key_buf[ptr_top-i]))
1109         {
1110             key_y_len = strlen(prevcp)+1;
1111 #if 0
1112             logf (LOG_LOG, "key_y_len: %2d %02x %02x %s",
1113                       key_y_len, prevcp[0], prevcp[1], 2+prevcp);
1114 #endif
1115             qsort (key_buf + ptr_top-ptr_i, ptr_i - i,
1116                                    sizeof(char*), key_y_compare);
1117             cp = key_buf[ptr_top-ptr_i];
1118             --key_y_len;
1119             encode_key_init (&encode_info);
1120             encode_key_write (cp, &encode_info, outf);
1121             while (--ptr_i > i)
1122             {
1123                 cp = key_buf[ptr_top-ptr_i];
1124                 encode_key_write (cp+key_y_len, &encode_info, outf);
1125             }
1126             if (!i)
1127                 break;
1128             prevcp = key_buf[ptr_top-ptr_i];
1129         }
1130 #endif
1131     if (fclose (outf))
1132     {
1133         logf (LOG_FATAL|LOG_ERRNO, "fclose %s", out_fname);
1134         exit (1);
1135     }
1136     logf (LOG_LOG, "finished section %d", zh->key_file_no);
1137     zh->ptr_i = 0;
1138     zh->key_buf_used = 0;
1139 }
1140
1141 static void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
1142                                      int cmd, struct recKeys *reckeys)
1143 {
1144     unsigned char attrSet = (unsigned char) -1;
1145     unsigned short attrUse = (unsigned short) -1;
1146     int seqno = 0;
1147     int off = 0;
1148     ZebraExplainInfo zei = zh->service->zei;
1149
1150     if (!zh->key_buf)
1151     {
1152         int mem = 8*1024*1024;
1153         zh->key_buf = (char**) xmalloc (mem);
1154         zh->ptr_top = mem/sizeof(char*);
1155         zh->ptr_i = 0;
1156         zh->key_buf_used = 0;
1157         zh->key_file_no = 0;
1158     }
1159     zebraExplain_recordCountIncrement (zei, cmd ? 1 : -1);
1160     while (off < reckeys->buf_used)
1161     {
1162         const char *src = reckeys->buf + off;
1163         struct it_key key;
1164         int lead, ch;
1165     
1166         lead = *src++;
1167
1168         if (!(lead & 1))
1169         {
1170             memcpy (&attrSet, src, sizeof(attrSet));
1171             src += sizeof(attrSet);
1172         }
1173         if (!(lead & 2))
1174         {
1175             memcpy (&attrUse, src, sizeof(attrUse));
1176             src += sizeof(attrUse);
1177         }
1178         if (zh->key_buf_used + 1024 > (zh->ptr_top-zh->ptr_i)*sizeof(char*))
1179             extract_flushWriteKeys (zh);
1180         ++(zh->ptr_i);
1181         (zh->key_buf)[zh->ptr_top - zh->ptr_i] =
1182             (char*)zh->key_buf + zh->key_buf_used;
1183
1184         ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
1185         if (ch < 0)
1186             ch = zebraExplain_addSU (zei, attrSet, attrUse);
1187         assert (ch > 0);
1188         zh->key_buf_used +=
1189             key_SU_code (ch,((char*)zh->key_buf) + zh->key_buf_used);
1190
1191         while (*src)
1192             ((char*)zh->key_buf) [(zh->key_buf_used)++] = *src++;
1193         src++;
1194         ((char*)(zh->key_buf))[(zh->key_buf_used)++] = '\0';
1195         ((char*)(zh->key_buf))[(zh->key_buf_used)++] = cmd;
1196
1197         if (lead & 60)
1198             seqno += ((lead>>2) & 15)-1;
1199         else
1200         {
1201             memcpy (&seqno, src, sizeof(seqno));
1202             src += sizeof(seqno);
1203         }
1204         key.seqno = seqno;
1205         key.sysno = sysno;
1206         memcpy ((char*)zh->key_buf + zh->key_buf_used, &key, sizeof(key));
1207         (zh->key_buf_used) += sizeof(key);
1208         off = src - reckeys->buf;
1209     }
1210     assert (off == reckeys->buf_used);
1211 }
1212
1213 static void extract_index (ZebraHandle zh)
1214 {
1215     extract_flushWriteKeys (zh);
1216     zebra_index_merge (zh);
1217 }
1218
1219 static int explain_extract (void *handle, Record rec, data1_node *n)
1220 {
1221     ZebraHandle zh = (ZebraHandle) handle;
1222     struct recExtractCtrl extractCtrl;
1223     int i;
1224
1225     if (zebraExplain_curDatabase (zh->service->zei,
1226                                   rec->info[recInfo_databaseName]))
1227     {
1228         abort();
1229         if (zebraExplain_newDatabase (zh->service->zei,
1230                                       rec->info[recInfo_databaseName], 0))
1231             abort ();
1232     }
1233
1234     zh->keys.buf_used = 0;
1235     zh->keys.prevAttrUse = -1;
1236     zh->keys.prevAttrSet = -1;
1237     zh->keys.prevSeqNo = 0;
1238     zh->sortKeys = 0;
1239     
1240     extractCtrl.init = extract_init;
1241     extractCtrl.tokenAdd = extract_token_add;
1242     extractCtrl.schemaAdd = extract_schema_add;
1243     extractCtrl.dh = zh->service->dh;
1244     for (i = 0; i<256; i++)
1245         extractCtrl.seqno[i] = 0;
1246     extractCtrl.zebra_maps = zh->service->zebra_maps;
1247     extractCtrl.flagShowRecords = 0;
1248     extractCtrl.handle = handle;
1249     
1250     grs_extract_tree(&extractCtrl, n);
1251
1252     logf (LOG_LOG, "flush explain record, sysno=%d", rec->sysno);
1253
1254     if (rec->size[recInfo_delKeys])
1255     {
1256         struct recKeys delkeys;
1257         struct sortKey *sortKeys = 0;
1258
1259         delkeys.buf_used = rec->size[recInfo_delKeys];
1260         delkeys.buf = rec->info[recInfo_delKeys];
1261         extract_flushSortKeys (zh, rec->sysno, 0, &sortKeys);
1262         extract_flushRecordKeys (zh, rec->sysno, 0, &delkeys);
1263     }
1264     extract_flushRecordKeys (zh, rec->sysno, 1, &zh->keys);
1265     extract_flushSortKeys (zh, rec->sysno, 1, &zh->sortKeys);
1266
1267     xfree (rec->info[recInfo_delKeys]);
1268     rec->size[recInfo_delKeys] = zh->keys.buf_used;
1269     rec->info[recInfo_delKeys] = zh->keys.buf;
1270     zh->keys.buf = NULL;
1271     zh->keys.buf_max = 0;
1272     return 0;
1273 }
1274
1275 static int extract_rec_in_mem (ZebraHandle zh, const char *recordType,
1276                                const char *buf, size_t buf_size,
1277                                const char *databaseName, int delete_flag,
1278                                int test_mode, int *sysno,
1279                                int store_keys, int store_data,
1280                                const char *match_criteria)
1281 {
1282     RecordAttr *recordAttr;
1283     struct recExtractCtrl extractCtrl;
1284     int i, r;
1285     RecType recType;
1286     char subType[1024];
1287     void *clientData;
1288     const char *fname = "<no file>";
1289     Record rec;
1290     long recordOffset = 0;
1291     struct zebra_fetch_control fc;
1292
1293     fc.fd = -1;
1294     fc.record_int_buf = buf;
1295     fc.record_int_len = buf_size;
1296     fc.record_int_pos = 0;
1297     fc.offset_end = 0;
1298     fc.record_offset = 0;
1299
1300     extractCtrl.offset = 0;
1301     extractCtrl.readf = zebra_record_int_read;
1302     extractCtrl.seekf = zebra_record_int_seek;
1303     extractCtrl.tellf = zebra_record_int_tell;
1304     extractCtrl.endf = zebra_record_int_end;
1305     extractCtrl.fh = &fc;
1306
1307     /* announce database */
1308     if (zebraExplain_curDatabase (zh->service->zei, databaseName))
1309     {
1310         if (zebraExplain_newDatabase (zh->service->zei, databaseName, 0))
1311             return 0;
1312     }
1313     if (!(recType =
1314           recType_byName (zh->service->recTypes, recordType, subType,
1315                           &clientData)))
1316     {
1317         logf (LOG_WARN, "No such record type: %s", recordType);
1318         return 0;
1319     }
1320
1321     zh->keys.buf_used = 0;
1322     zh->keys.prevAttrUse = -1;
1323     zh->keys.prevAttrSet = -1;
1324     zh->keys.prevSeqNo = 0;
1325     zh->sortKeys = 0;
1326
1327     extractCtrl.subType = subType;
1328     extractCtrl.init = extract_init;
1329     extractCtrl.tokenAdd = extract_token_add;
1330     extractCtrl.schemaAdd = extract_schema_add;
1331     extractCtrl.dh = zh->service->dh;
1332     extractCtrl.handle = zh;
1333     extractCtrl.zebra_maps = zh->service->zebra_maps;
1334     extractCtrl.flagShowRecords = 0;
1335     for (i = 0; i<256; i++)
1336     {
1337         if (zebra_maps_is_positioned(zh->service->zebra_maps, i))
1338             extractCtrl.seqno[i] = 1;
1339         else
1340             extractCtrl.seqno[i] = 0;
1341     }
1342
1343     r = (*recType->extract)(clientData, &extractCtrl);
1344
1345     if (r == RECCTRL_EXTRACT_EOF)
1346         return 0;
1347     else if (r == RECCTRL_EXTRACT_ERROR)
1348     {
1349         /* error occured during extraction ... */
1350 #if 1
1351         yaz_log (LOG_WARN, "extract error");
1352 #else
1353         if (rGroup->flagRw &&
1354             records_processed < rGroup->fileVerboseLimit)
1355         {
1356             logf (LOG_WARN, "fail %s %s %ld", rGroup->recordType,
1357                   fname, (long) recordOffset);
1358         }
1359 #endif
1360         return 0;
1361     }
1362     if (zh->keys.buf_used == 0)
1363     {
1364         /* the extraction process returned no information - the record
1365            is probably empty - unless flagShowRecords is in use */
1366         if (test_mode)
1367             return 1;
1368         logf (LOG_WARN, "No keys generated for record");
1369         logf (LOG_WARN, " The file is probably empty");
1370         return 1;
1371     }
1372     /* match criteria */
1373
1374     if (! *sysno)
1375     {
1376         /* new record */
1377         if (delete_flag)
1378         {
1379             logf (LOG_LOG, "delete %s %s %ld", recordType,
1380                   fname, (long) recordOffset);
1381             logf (LOG_WARN, "cannot delete record above (seems new)");
1382             return 1;
1383         }
1384         logf (LOG_LOG, "add %s %s %ld", recordType, fname,
1385               (long) recordOffset);
1386         rec = rec_new (zh->service->records);
1387
1388         *sysno = rec->sysno;
1389
1390         recordAttr = rec_init_attr (zh->service->zei, rec);
1391
1392 #if 0
1393         if (matchStr)
1394         {
1395             dict_insert (matchDict, matchStr, sizeof(*sysno), sysno);
1396         }
1397 #endif
1398         extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
1399         extract_flushSortKeys (zh, *sysno, 1, &zh->sortKeys);
1400     }
1401     else
1402     {
1403         /* record already exists */
1404         struct recKeys delkeys;
1405
1406         rec = rec_get (zh->service->records, *sysno);
1407         assert (rec);
1408         
1409         recordAttr = rec_init_attr (zh->service->zei, rec);
1410
1411         if (recordAttr->runNumber ==
1412             zebraExplain_runNumberIncrement (zh->service->zei, 0))
1413         {
1414             logf (LOG_LOG, "skipped %s %s %ld", recordType,
1415                   fname, (long) recordOffset);
1416             rec_rm (&rec);
1417             return 1;
1418         }
1419         delkeys.buf_used = rec->size[recInfo_delKeys];
1420         delkeys.buf = rec->info[recInfo_delKeys];
1421         extract_flushSortKeys (zh, *sysno, 0, &zh->sortKeys);
1422         extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
1423         if (delete_flag)
1424         {
1425             /* record going to be deleted */
1426             if (!delkeys.buf_used)
1427             {
1428                 logf (LOG_LOG, "delete %s %s %ld", recordType,
1429                       fname, (long) recordOffset);
1430                 logf (LOG_WARN, "cannot delete file above, storeKeys false");
1431             }
1432             else
1433             {
1434                 logf (LOG_LOG, "delete %s %s %ld", recordType,
1435                       fname, (long) recordOffset);
1436 #if 0
1437                 if (matchStr)
1438                     dict_delete (matchDict, matchStr);
1439 #endif
1440                 rec_del (zh->service->records, &rec);
1441             }
1442             rec_rm (&rec);
1443             return 1;
1444         }
1445         else
1446         {
1447             /* record going to be updated */
1448             if (!delkeys.buf_used)
1449             {
1450                 logf (LOG_LOG, "update %s %s %ld", recordType,
1451                       fname, (long) recordOffset);
1452                 logf (LOG_WARN, "cannot update file above, storeKeys false");
1453             }
1454             else
1455             {
1456                 logf (LOG_LOG, "update %s %s %ld", recordType,
1457                       fname, (long) recordOffset);
1458                 extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
1459             }
1460         }
1461     }
1462     /* update file type */
1463     xfree (rec->info[recInfo_fileType]);
1464     rec->info[recInfo_fileType] =
1465         rec_strdup (recordType, &rec->size[recInfo_fileType]);
1466
1467     /* update filename */
1468     xfree (rec->info[recInfo_filename]);
1469     rec->info[recInfo_filename] =
1470         rec_strdup (fname, &rec->size[recInfo_filename]);
1471
1472     /* update delete keys */
1473     xfree (rec->info[recInfo_delKeys]);
1474     if (zh->keys.buf_used > 0 && store_keys == 1)
1475     {
1476         rec->size[recInfo_delKeys] = zh->keys.buf_used;
1477         rec->info[recInfo_delKeys] = zh->keys.buf;
1478         zh->keys.buf = NULL;
1479         zh->keys.buf_max = 0;
1480     }
1481     else
1482     {
1483         rec->info[recInfo_delKeys] = NULL;
1484         rec->size[recInfo_delKeys] = 0;
1485     }
1486
1487     /* save file size of original record */
1488     zebraExplain_recordBytesIncrement (zh->service->zei,
1489                                        - recordAttr->recordSize);
1490 #if 0
1491     recordAttr->recordSize = fi->file_moffset - recordOffset;
1492     if (!recordAttr->recordSize)
1493         recordAttr->recordSize = fi->file_max - recordOffset;
1494 #else
1495     recordAttr->recordSize = buf_size;
1496 #endif
1497     zebraExplain_recordBytesIncrement (zh->service->zei,
1498                                        recordAttr->recordSize);
1499
1500     /* set run-number for this record */
1501     recordAttr->runNumber =
1502         zebraExplain_runNumberIncrement (zh->service->zei, 0);
1503
1504     /* update store data */
1505     xfree (rec->info[recInfo_storeData]);
1506     if (store_data == 1)
1507     {
1508         rec->size[recInfo_storeData] = recordAttr->recordSize;
1509         rec->info[recInfo_storeData] = (char *)
1510             xmalloc (recordAttr->recordSize);
1511 #if 1
1512         memcpy (rec->info[recInfo_storeData], buf, recordAttr->recordSize);
1513 #else
1514         if (lseek (fi->fd, recordOffset, SEEK_SET) < 0)
1515         {
1516             logf (LOG_ERRNO|LOG_FATAL, "seek to %ld in %s",
1517                   (long) recordOffset, fname);
1518             exit (1);
1519         }
1520         if (read (fi->fd, rec->info[recInfo_storeData], recordAttr->recordSize)
1521             < recordAttr->recordSize)
1522         {
1523             logf (LOG_ERRNO|LOG_FATAL, "read %d bytes of %s",
1524                   recordAttr->recordSize, fname);
1525             exit (1);
1526         }
1527 #endif
1528     }
1529     else
1530     {
1531         rec->info[recInfo_storeData] = NULL;
1532         rec->size[recInfo_storeData] = 0;
1533     }
1534     /* update database name */
1535     xfree (rec->info[recInfo_databaseName]);
1536     rec->info[recInfo_databaseName] =
1537         rec_strdup (databaseName, &rec->size[recInfo_databaseName]); 
1538
1539     /* update offset */
1540     recordAttr->recordOffset = recordOffset;
1541     
1542     /* commit this record */
1543     rec_put (zh->service->records, &rec);
1544
1545     return 0;
1546 }