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