98cc717ef1ef2bc8d7100b3abc71c9a4b5cb270a
[idzebra-moved-to-github.git] / index / extract.c
1 /* $Id: extract.c,v 1.160 2004-08-10 08:19:15 heikki Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 #include <stdio.h>
24 #include <assert.h>
25 #include <ctype.h>
26 #ifdef WIN32
27 #include <io.h>
28 #else
29 #include <unistd.h>
30 #endif
31 #include <fcntl.h>
32
33 #include "index.h"
34 #include <direntz.h>
35 #include <charmap.h>
36
37 #if _FILE_OFFSET_BITS == 64
38 #define PRINTF_OFF_T "%Ld"
39 #else
40 #define PRINTF_OFF_T "%ld"
41 #endif
42
43 #define USE_SHELLSORT 0
44
45 #if USE_SHELLSORT
46 static void shellsort(void *ar, int r, size_t s,
47                       int (*cmp)(const void *a, const void *b))
48 {
49     char *a = ar;
50     char v[100];
51     int h, i, j, k;
52     static const int incs[16] = { 1391376, 463792, 198768, 86961, 33936,
53                                   13776, 4592, 1968, 861, 336, 
54                                   112, 48, 21, 7, 3, 1 };
55     for ( k = 0; k < 16; k++)
56         for (h = incs[k], i = h; i < r; i++)
57         { 
58             memcpy (v, a+s*i, s);
59             j = i;
60             while (j > h && (*cmp)(a + s*(j-h), v) > 0)
61             {
62                 memcpy (a + s*j, a + s*(j-h), s);
63                 j -= h;
64             }
65             memcpy (a+s*j, v, s);
66         } 
67 }
68 #endif
69
70 static void logRecord (ZebraHandle zh)
71 {
72     ++zh->records_processed;
73     if (!(zh->records_processed % 1000))
74     {
75         logf (LOG_LOG, "Records: "ZINT_FORMAT" i/u/d "
76                         ZINT_FORMAT"/"ZINT_FORMAT"/"ZINT_FORMAT, 
77               zh->records_processed, zh->records_inserted, zh->records_updated,
78               zh->records_deleted);
79     }
80 }
81
82 static void extract_init (struct recExtractCtrl *p, RecWord *w)
83 {
84     w->zebra_maps = p->zebra_maps;
85     w->seqno = 1;
86     w->attrSet = VAL_BIB1;
87     w->attrUse = 1016;
88     w->reg_type = 'w';
89     w->extractCtrl = p;
90 }
91
92 static const char **searchRecordKey (ZebraHandle zh,
93                                      struct recKeys *reckeys,
94                                      int attrSetS, int attrUseS)
95 {
96 #if IT_KEY_NEW
97 /* #error searchRecordKey does not work yet in this mode.. */
98     static const char *ws[32];
99     void *decode_handle = iscz1_start();
100     int off = 0;
101     int startSeq = -1;
102     int seqno = 0;
103     int i;
104
105     for (i = 0; i<32; i++)
106         ws[i] = NULL;
107
108     while (off < reckeys->buf_used)
109     {
110         const char *src = reckeys->buf + off;
111         struct it_key key;
112         char *dst = (char*) &key;
113         int attrSet, attrUse;
114
115         iscz1_decode(decode_handle, &dst, &src);
116         assert(key.len < 4 && key.len > 2);
117
118         attrSet = (int) key.mem[0];
119         attrUse = (int) key.mem[1];
120         seqno = (int) key.mem[2];
121
122         if (attrUseS == attrUse && attrSetS == attrSet)
123         {
124             int woff;
125
126             if (startSeq == -1)
127                 startSeq = seqno;
128             woff = seqno - startSeq;
129             if (woff >= 0 && woff < 31)
130                 ws[woff] = src;
131         }
132
133         while (*src++)
134             ;
135         off = src - reckeys->buf;
136     }
137     iscz1_stop(decode_handle);
138     assert (off == reckeys->buf_used);
139     return ws;
140 #else
141     static const char *ws[32];
142     int off = 0;
143     int startSeq = -1;
144     int i;
145     int seqno = 0;
146 #if SU_SCHEME
147     int chS, ch;
148 #else
149     short attrUse;
150     char attrSet;
151 #endif
152
153     for (i = 0; i<32; i++)
154         ws[i] = NULL;
155
156 #if SU_SCHEME
157     chS = zebraExplain_lookupSU (zh->reg->zei, attrSetS, attrUseS);
158     if (chS < 0)
159         return ws;
160 #endif
161     while (off < reckeys->buf_used)
162     {
163
164         const char *src = reckeys->buf + off;
165         const char *wstart;
166         int lead;
167     
168         lead = *src++;
169 #if SU_SCHEME
170         if ((lead & 3)<3)
171         {
172             memcpy (&ch, src, sizeof(ch));
173             src += sizeof(ch);
174         }
175 #else
176         if (!(lead & 1))
177         {
178             memcpy (&attrSet, src, sizeof(attrSet));
179             src += sizeof(attrSet);
180         }
181         if (!(lead & 2))
182         {
183             memcpy (&attrUse, src, sizeof(attrUse));
184             src += sizeof(attrUse);
185         }
186 #endif
187         wstart = src;
188         while (*src++)
189             ;
190         if (lead & 60)
191             seqno += ((lead>>2) & 15)-1;
192         else
193         {
194             memcpy (&seqno, src, sizeof(seqno));
195             src += sizeof(seqno);
196         }
197         if (
198 #if SU_SCHEME
199             ch == chS
200 #else
201             attrUseS == attrUse && attrSetS == attrSet
202 #endif
203             )
204         {
205             int woff;
206
207
208             if (startSeq == -1)
209                 startSeq = seqno;
210             woff = seqno - startSeq;
211             if (woff >= 0 && woff < 31)
212                 ws[woff] = wstart;
213         }
214
215         off = src - reckeys->buf;
216     }
217     assert (off == reckeys->buf_used);
218     return ws;
219 #endif
220 }
221
222 struct file_read_info {
223     off_t file_max;         /* maximum offset so far */
224     off_t file_offset;      /* current offset */
225     off_t file_moffset;     /* offset of rec/rec boundary */
226     int file_more;
227     int fd;
228     char *sdrbuf;
229     int sdrmax;
230 };
231
232 static struct file_read_info *file_read_start (int fd)
233 {
234     struct file_read_info *fi = (struct file_read_info *)
235         xmalloc (sizeof(*fi));
236
237     fi->fd = fd;
238     fi->file_max = 0;
239     fi->file_moffset = 0;
240     fi->sdrbuf = 0;
241     fi->sdrmax = 0;
242     return fi;
243 }
244
245 static void file_read_stop (struct file_read_info *fi)
246 {
247     xfree (fi);
248 }
249
250 static off_t file_seek (void *handle, off_t offset)
251 {
252     struct file_read_info *p = (struct file_read_info *) handle;
253     p->file_offset = offset;
254     if (p->sdrbuf)
255         return offset;
256     return lseek (p->fd, offset, SEEK_SET);
257 }
258
259 static off_t file_tell (void *handle)
260 {
261     struct file_read_info *p = (struct file_read_info *) handle;
262     return p->file_offset;
263 }
264
265 static int file_read (void *handle, char *buf, size_t count)
266 {
267     struct file_read_info *p = (struct file_read_info *) handle;
268     int fd = p->fd;
269     int r;
270     if (p->sdrbuf)
271     {
272         r = count;
273         if (r > p->sdrmax - p->file_offset)
274             r = p->sdrmax - p->file_offset;
275         if (r)
276             memcpy (buf, p->sdrbuf + p->file_offset, r);
277     }
278     else
279         r = read (fd, buf, count);
280     if (r > 0)
281     {
282         p->file_offset += r;
283         if (p->file_offset > p->file_max)
284             p->file_max = p->file_offset;
285     }
286     return r;
287 }
288
289 static void file_begin (void *handle)
290 {
291     struct file_read_info *p = (struct file_read_info *) handle;
292
293     p->file_offset = p->file_moffset;
294     if (!p->sdrbuf && p->file_moffset)
295         lseek (p->fd, p->file_moffset, SEEK_SET);
296     p->file_more = 0;
297 }
298
299 static void file_end (void *handle, off_t offset)
300 {
301     struct file_read_info *p = (struct file_read_info *) handle;
302
303     assert (p->file_more == 0);
304     p->file_more = 1;
305     p->file_moffset = offset;
306 }
307
308 static char *fileMatchStr (ZebraHandle zh,
309                            struct recKeys *reckeys,
310                            const char *fname, const char *spec)
311 {
312     static char dstBuf[2048];      /* static here ??? */
313     char *dst = dstBuf;
314     const char *s = spec;
315     static const char **w;
316
317     while (1)
318     {
319         while (*s == ' ' || *s == '\t')
320             s++;
321         if (!*s)
322             break;
323         if (*s == '(')
324         {
325             char attset_str[64], attname_str[64];
326             data1_attset *attset;
327             int i;
328             char matchFlag[32];
329             int attSet = 1, attUse = 1;
330             int first = 1;
331
332             s++;
333             for (i = 0; *s && *s != ',' && *s != ')'; s++)
334                 if (i < 63)
335                     attset_str[i++] = *s;
336             attset_str[i] = '\0';
337
338             if (*s == ',')
339             {
340                 s++;
341                 for (i = 0; *s && *s != ')'; s++)
342                     if (i < 63)
343                         attname_str[i++] = *s;
344                 attname_str[i] = '\0';
345             }
346             
347             if ((attset = data1_get_attset (zh->reg->dh, attset_str)))
348             {
349                 data1_att *att;
350                 attSet = attset->reference;
351                 att = data1_getattbyname(zh->reg->dh, attset, attname_str);
352                 if (att)
353                     attUse = att->value;
354                 else
355                     attUse = atoi (attname_str);
356             }
357             w = searchRecordKey (zh, reckeys, attSet, attUse);
358             assert (w);
359
360             if (*s == ')')
361             {
362                 for (i = 0; i<32; i++)
363                     matchFlag[i] = 1;
364             }
365             else
366             {
367                 logf (LOG_WARN, "Missing ) in match criteria %s in group %s",
368                       spec, zh->m_group ? zh->m_group : "none");
369                 return NULL;
370             }
371             s++;
372
373             for (i = 0; i<32; i++)
374                 if (matchFlag[i] && w[i])
375                 {
376                     if (first)
377                     {
378                         *dst++ = ' ';
379                         first = 0;
380                     }
381                     strcpy (dst, w[i]);
382                     dst += strlen(w[i]);
383                 }
384             if (first)
385             {
386                 logf (LOG_WARN, "Record didn't contain match"
387                       " fields in (%s,%s)", attset_str, attname_str);
388                 return NULL;
389             }
390         }
391         else if (*s == '$')
392         {
393             int spec_len;
394             char special[64];
395             const char *spec_src = NULL;
396             const char *s1 = ++s;
397             while (*s1 && *s1 != ' ' && *s1 != '\t')
398                 s1++;
399
400             spec_len = s1 - s;
401             if (spec_len > 63)
402                 spec_len = 63;
403             memcpy (special, s, spec_len);
404             special[spec_len] = '\0';
405             s = s1;
406
407             if (!strcmp (special, "group"))
408                 spec_src = zh->m_group;
409             else if (!strcmp (special, "database"))
410                 spec_src = zh->basenames[0];
411             else if (!strcmp (special, "filename")) {
412                 spec_src = fname;
413             }
414             else if (!strcmp (special, "type"))
415                 spec_src = zh->m_record_type;
416             else 
417                 spec_src = NULL;
418             if (spec_src)
419             {
420                 strcpy (dst, spec_src);
421                 dst += strlen (spec_src);
422             }
423         }
424         else if (*s == '\"' || *s == '\'')
425         {
426             int stopMarker = *s++;
427             char tmpString[64];
428             int i = 0;
429
430             while (*s && *s != stopMarker)
431             {
432                 if (i < 63)
433                     tmpString[i++] = *s++;
434             }
435             if (*s)
436                 s++;
437             tmpString[i] = '\0';
438             strcpy (dst, tmpString);
439             dst += strlen (tmpString);
440         }
441         else
442         {
443             logf (LOG_WARN, "Syntax error in match criteria %s in group %s",
444                   spec, zh->m_group ? zh->m_group : "none");
445             return NULL;
446         }
447         *dst++ = 1;
448     }
449     if (dst == dstBuf)
450     {
451         logf (LOG_WARN, "No match criteria for record %s in group %s",
452               fname, zh->m_group ? zh->m_group : "none");
453         return NULL;
454     }
455     *dst = '\0';
456     return dstBuf;
457 }
458
459 struct recordLogInfo {
460     const char *fname;
461     int recordOffset;
462     struct recordGroup *rGroup;
463 };
464
465 void create_rec_keys_codec(struct recKeys *keys)
466 {
467     keys->buf_used = 0;
468 #if IT_KEY_NEW
469     iscz1_reset(keys->codec_handle);
470 #else
471     keys->prevAttrUse = -1;
472     keys->prevAttrSet = -1;
473     keys->prevSeqNo = 0;
474 #endif
475 }
476      
477 static int file_extract_record(ZebraHandle zh,
478                                SYSNO *sysno, const char *fname,
479                                int deleteFlag,
480                                struct file_read_info *fi,
481                                int force_update)
482 {
483     RecordAttr *recordAttr;
484     int r;
485     const char *matchStr;
486     SYSNO sysnotmp;
487     Record rec;
488     off_t recordOffset = 0;
489     RecType recType;
490     void *clientData;
491     char subType[128];
492     
493     if (!(recType =
494           recType_byName (zh->reg->recTypes, zh->m_record_type, subType,
495                           &clientData)))
496     {
497         logf (LOG_WARN, "No such record type: %s", zh->m_record_type);
498         return 0;
499     }
500
501     /* announce database */
502     if (zebraExplain_curDatabase (zh->reg->zei, zh->basenames[0]))
503     {
504         if (zebraExplain_newDatabase (zh->reg->zei, zh->basenames[0],
505                                       zh->m_explain_database))
506             return 0;
507     }
508
509     if (fi->fd != -1)
510     {
511         struct recExtractCtrl extractCtrl;
512
513         /* we are going to read from a file, so prepare the extraction */
514         int i;
515
516         create_rec_keys_codec(&zh->reg->keys);
517
518         zh->reg->sortKeys.buf_used = 0;
519         
520         recordOffset = fi->file_moffset;
521         extractCtrl.offset = fi->file_moffset;
522         extractCtrl.readf = file_read;
523         extractCtrl.seekf = file_seek;
524         extractCtrl.tellf = file_tell;
525         extractCtrl.endf = file_end;
526         extractCtrl.fh = fi;
527         extractCtrl.subType = subType;
528         extractCtrl.init = extract_init;
529         extractCtrl.tokenAdd = extract_token_add;
530         extractCtrl.schemaAdd = extract_schema_add;
531         extractCtrl.dh = zh->reg->dh;
532         extractCtrl.handle = zh;
533         for (i = 0; i<256; i++)
534         {
535             if (zebra_maps_is_positioned(zh->reg->zebra_maps, i))
536                 extractCtrl.seqno[i] = 1;
537             else
538                 extractCtrl.seqno[i] = 0;
539         }
540         extractCtrl.zebra_maps = zh->reg->zebra_maps;
541         extractCtrl.flagShowRecords = !zh->m_flag_rw;
542
543         if (!zh->m_flag_rw)
544             printf ("File: %s " PRINTF_OFF_T "\n", fname, recordOffset);
545         if (zh->m_flag_rw)
546         {
547             char msg[512];
548             sprintf (msg, "%s:" PRINTF_OFF_T , fname, recordOffset);
549             yaz_log_init_prefix2 (msg);
550         }
551
552         r = (*recType->extract)(clientData, &extractCtrl);
553
554         yaz_log_init_prefix2 (0);
555         if (r == RECCTRL_EXTRACT_EOF)
556             return 0;
557         else if (r == RECCTRL_EXTRACT_ERROR_GENERIC)
558         {
559             /* error occured during extraction ... */
560             if (zh->m_flag_rw &&
561                 zh->records_processed < zh->m_file_verbose_limit)
562             {
563                 logf (LOG_WARN, "fail %s %s " PRINTF_OFF_T, zh->m_record_type,
564                       fname, recordOffset);
565             }
566             return 0;
567         }
568         else if (r == RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER)
569         {
570             /* error occured during extraction ... */
571             if (zh->m_flag_rw &&
572                 zh->records_processed < zh->m_file_verbose_limit)
573             {
574                 logf (LOG_WARN, "no filter for %s %s " 
575                       PRINTF_OFF_T, zh->m_record_type,
576                       fname, recordOffset);
577             }
578             return 0;
579         }
580         if (zh->reg->keys.buf_used == 0)
581         {
582             /* the extraction process returned no information - the record
583                is probably empty - unless flagShowRecords is in use */
584             if (!zh->m_flag_rw)
585                 return 1;
586             
587             logf (LOG_WARN, "empty %s %s " PRINTF_OFF_T, zh->m_record_type,
588                   fname, recordOffset);
589             return 1;
590         }
591     }
592
593     /* perform match if sysno not known and if match criteria is specified */
594        
595     matchStr = NULL;
596     if (!sysno) 
597     {
598         sysnotmp = 0;
599         sysno = &sysnotmp;
600         if (zh->m_record_id && *zh->m_record_id)
601         {
602             char *rinfo;
603         
604             matchStr = fileMatchStr (zh, &zh->reg->keys, fname, 
605                                      zh->m_record_id);
606             if (matchStr)
607             {
608                 rinfo = dict_lookup (zh->reg->matchDict, matchStr);
609                 if (rinfo)
610                 {
611                     assert(*rinfo == sizeof(*sysno));
612                     memcpy (sysno, rinfo+1, sizeof(*sysno));
613                 }
614             }
615             else
616             {
617                 logf (LOG_WARN, "Bad match criteria");
618                 return 0;
619             }
620         }
621     }
622
623     if (! *sysno)
624     {
625         /* new record */
626         if (deleteFlag)
627         {
628             logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T, zh->m_record_type,
629                   fname, recordOffset);
630             logf (LOG_WARN, "cannot delete record above (seems new)");
631             return 1;
632         }
633         if (zh->records_processed < zh->m_file_verbose_limit)
634             logf (LOG_LOG, "add %s %s " PRINTF_OFF_T, zh->m_record_type,
635                   fname, recordOffset);
636         rec = rec_new (zh->reg->records);
637
638         *sysno = rec->sysno;
639
640         recordAttr = rec_init_attr (zh->reg->zei, rec);
641
642         if (matchStr)
643         {
644             dict_insert (zh->reg->matchDict, matchStr, sizeof(*sysno), sysno);
645         }
646         extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
647         extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
648
649         zh->records_inserted++;
650     }
651     else
652     {
653         /* record already exists */
654         struct recKeys delkeys;
655         struct sortKeys sortKeys;
656
657         rec = rec_get (zh->reg->records, *sysno);
658         assert (rec);
659         
660         recordAttr = rec_init_attr (zh->reg->zei, rec);
661
662         if (!force_update && recordAttr->runNumber ==
663             zebraExplain_runNumberIncrement (zh->reg->zei, 0))
664         {
665             yaz_log (LOG_LOG, "run number = %d", recordAttr->runNumber);
666             yaz_log (LOG_LOG, "skipped %s %s " PRINTF_OFF_T,
667                      zh->m_record_type, fname, recordOffset);
668             extract_flushSortKeys (zh, *sysno, -1, &zh->reg->sortKeys);
669             rec_rm (&rec);
670             logRecord (zh);
671             return 1;
672         }
673         delkeys.buf_used = rec->size[recInfo_delKeys];
674         delkeys.buf = rec->info[recInfo_delKeys];
675
676         sortKeys.buf_used = rec->size[recInfo_sortKeys];
677         sortKeys.buf = rec->info[recInfo_sortKeys];
678
679         extract_flushSortKeys (zh, *sysno, 0, &sortKeys);
680         extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
681         if (deleteFlag)
682         {
683             /* record going to be deleted */
684             if (!delkeys.buf_used)
685             {
686                 logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
687                       zh->m_record_type, fname, recordOffset);
688                 logf (LOG_WARN, "cannot delete file above, storeKeys false");
689             }
690             else
691             {
692                 if (zh->records_processed < zh->m_file_verbose_limit)
693                     logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
694                          zh->m_record_type, fname, recordOffset);
695                 zh->records_deleted++;
696                 if (matchStr)
697                     dict_delete (zh->reg->matchDict, matchStr);
698                 rec_del (zh->reg->records, &rec);
699             }
700             rec_rm (&rec);
701             logRecord (zh);
702             return 1;
703         }
704         else
705         {
706             /* record going to be updated */
707             if (!delkeys.buf_used)
708             {
709                 logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
710                       zh->m_record_type, fname, recordOffset);
711                 logf (LOG_WARN, "cannot update file above, storeKeys false");
712             }
713             else
714             {
715                 if (zh->records_processed < zh->m_file_verbose_limit)
716                     logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
717                         zh->m_record_type, fname, recordOffset);
718                 extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
719                 extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
720                 zh->records_updated++;
721             }
722         }
723     }
724     /* update file type */
725     xfree (rec->info[recInfo_fileType]);
726     rec->info[recInfo_fileType] =
727         rec_strdup (zh->m_record_type, &rec->size[recInfo_fileType]);
728
729     /* update filename */
730     xfree (rec->info[recInfo_filename]);
731     rec->info[recInfo_filename] =
732         rec_strdup (fname, &rec->size[recInfo_filename]);
733
734     /* update delete keys */
735     xfree (rec->info[recInfo_delKeys]);
736     if (zh->reg->keys.buf_used > 0 && zh->m_store_keys == 1)
737     {
738         rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
739         rec->info[recInfo_delKeys] = zh->reg->keys.buf;
740         zh->reg->keys.buf = NULL;
741         zh->reg->keys.buf_max = 0;
742     }
743     else
744     {
745         rec->info[recInfo_delKeys] = NULL;
746         rec->size[recInfo_delKeys] = 0;
747     }
748
749     /* update sort keys */
750     xfree (rec->info[recInfo_sortKeys]);
751
752     rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
753     rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
754     zh->reg->sortKeys.buf = NULL;
755     zh->reg->sortKeys.buf_max = 0;
756
757     /* save file size of original record */
758     zebraExplain_recordBytesIncrement (zh->reg->zei,
759                                        - recordAttr->recordSize);
760     recordAttr->recordSize = fi->file_moffset - recordOffset;
761     if (!recordAttr->recordSize)
762         recordAttr->recordSize = fi->file_max - recordOffset;
763     zebraExplain_recordBytesIncrement (zh->reg->zei,
764                                        recordAttr->recordSize);
765
766     /* set run-number for this record */
767     recordAttr->runNumber = zebraExplain_runNumberIncrement (zh->reg->zei,
768                                                              0);
769
770     /* update store data */
771     xfree (rec->info[recInfo_storeData]);
772     if (zh->m_store_data)
773     {
774         rec->size[recInfo_storeData] = recordAttr->recordSize;
775         rec->info[recInfo_storeData] = (char *)
776             xmalloc (recordAttr->recordSize);
777         if (lseek (fi->fd, recordOffset, SEEK_SET) < 0)
778         {
779             logf (LOG_ERRNO|LOG_FATAL, "seek to " PRINTF_OFF_T " in %s",
780                   recordOffset, fname);
781             exit (1);
782         }
783         if (read (fi->fd, rec->info[recInfo_storeData], recordAttr->recordSize)
784             < recordAttr->recordSize)
785         {
786             logf (LOG_ERRNO|LOG_FATAL, "read %d bytes of %s",
787                   recordAttr->recordSize, fname);
788             exit (1);
789         }
790     }
791     else
792     {
793         rec->info[recInfo_storeData] = NULL;
794         rec->size[recInfo_storeData] = 0;
795     }
796     /* update database name */
797     xfree (rec->info[recInfo_databaseName]);
798     rec->info[recInfo_databaseName] =
799         rec_strdup (zh->basenames[0], &rec->size[recInfo_databaseName]); 
800
801     /* update offset */
802     recordAttr->recordOffset = recordOffset;
803     
804     /* commit this record */
805     rec_put (zh->reg->records, &rec);
806     logRecord (zh);
807     return 1;
808 }
809
810 int fileExtract (ZebraHandle zh, SYSNO *sysno, const char *fname, 
811                  int deleteFlag)
812 {
813     int r, i, fd;
814     char gprefix[128];
815     char ext[128];
816     char ext_res[128];
817     struct file_read_info *fi;
818     const char *original_record_type = 0;
819
820     if (!zh->m_group || !*zh->m_group)
821         *gprefix = '\0';
822     else
823         sprintf (gprefix, "%s.", zh->m_group);
824     
825     logf (LOG_DEBUG, "fileExtract %s", fname);
826
827     /* determine file extension */
828     *ext = '\0';
829     for (i = strlen(fname); --i >= 0; )
830         if (fname[i] == '/')
831             break;
832         else if (fname[i] == '.')
833         {
834             strcpy (ext, fname+i+1);
835             break;
836         }
837     /* determine file type - depending on extension */
838     original_record_type = zh->m_record_type;
839     if (!zh->m_record_type)
840     {
841         sprintf (ext_res, "%srecordType.%s", gprefix, ext);
842         zh->m_record_type = res_get (zh->res, ext_res);
843     }
844     if (!zh->m_record_type)
845     {
846         if (zh->records_processed < zh->m_file_verbose_limit)
847             logf (LOG_LOG, "? %s", fname);
848         return 0;
849     }
850     /* determine match criteria */
851     if (!zh->m_record_id)
852     {
853         sprintf (ext_res, "%srecordId.%s", gprefix, ext);
854         zh->m_record_id = res_get (zh->res, ext_res);
855     }
856
857     if (sysno && deleteFlag)
858         fd = -1;
859     else
860     {
861         char full_rep[1024];
862
863         if (zh->path_reg && !yaz_is_abspath (fname))
864         {
865             strcpy (full_rep, zh->path_reg);
866             strcat (full_rep, "/");
867             strcat (full_rep, fname);
868         }
869         else
870             strcpy (full_rep, fname);
871         
872
873         if ((fd = open (full_rep, O_BINARY|O_RDONLY)) == -1)
874         {
875             logf (LOG_WARN|LOG_ERRNO, "open %s", full_rep);
876             zh->m_record_type = original_record_type;
877             return 0;
878         }
879     }
880     fi = file_read_start (fd);
881     do
882     {
883         file_begin (fi);
884         r = file_extract_record (zh, sysno, fname, deleteFlag, fi, 1);
885     } while (r && !sysno && fi->file_more);
886     file_read_stop (fi);
887     if (fd != -1)
888         close (fd);
889     zh->m_record_type = original_record_type;
890     return r;
891 }
892
893 /*
894   If sysno is provided, then it's used to identify the reocord.
895   If not, and match_criteria is provided, then sysno is guessed
896   If not, and a record is provided, then sysno is got from there
897   
898  */
899 int buffer_extract_record (ZebraHandle zh, 
900                            const char *buf, size_t buf_size,
901                            int delete_flag,
902                            int test_mode, 
903                            const char *recordType,
904                            SYSNO *sysno,
905                            const char *match_criteria,
906                            const char *fname,
907                            int force_update,
908                            int allow_update)
909 {
910     RecordAttr *recordAttr;
911     struct recExtractCtrl extractCtrl;
912     int i, r;
913     const char *matchStr = 0;
914     RecType recType = NULL;
915     char subType[1024];
916     void *clientData;
917     Record rec;
918     long recordOffset = 0;
919     struct zebra_fetch_control fc;
920     const char *pr_fname = fname;  /* filename to print .. */
921
922     if (!pr_fname)
923         pr_fname = "<no file>";  /* make it printable if file is omitted */
924
925     fc.fd = -1;
926     fc.record_int_buf = buf;
927     fc.record_int_len = buf_size;
928     fc.record_int_pos = 0;
929     fc.offset_end = 0;
930     fc.record_offset = 0;
931
932     extractCtrl.offset = 0;
933     extractCtrl.readf = zebra_record_int_read;
934     extractCtrl.seekf = zebra_record_int_seek;
935     extractCtrl.tellf = zebra_record_int_tell;
936     extractCtrl.endf = zebra_record_int_end;
937     extractCtrl.fh = &fc;
938
939     create_rec_keys_codec(&zh->reg->keys);
940
941     zh->reg->sortKeys.buf_used = 0;
942
943     if (zebraExplain_curDatabase (zh->reg->zei, zh->basenames[0]))
944     {
945         if (zebraExplain_newDatabase (zh->reg->zei, zh->basenames[0], 
946                                       zh->m_explain_database))
947             return 0;
948     }
949     
950     if (recordType && *recordType) {
951         logf (LOG_DEBUG, "Record type explicitly specified: %s", recordType);
952         recType = recType_byName (zh->reg->recTypes, recordType, subType,
953                                   &clientData);
954     } else {
955         if (!(zh->m_record_type)) {
956             logf (LOG_WARN, "No such record type defined");
957             return 0;
958         }
959         logf (LOG_DEBUG, "Get record type from rgroup: %s",zh->m_record_type);
960         recType = recType_byName (zh->reg->recTypes, zh->m_record_type, subType,
961                                   &clientData);
962         recordType = zh->m_record_type;
963     }
964     
965     if (!recType) {
966         logf (LOG_WARN, "No such record type: %s", zh->m_record_type);
967         return 0;
968     }
969     
970     extractCtrl.subType = subType;
971     extractCtrl.init = extract_init;
972     extractCtrl.tokenAdd = extract_token_add;
973     extractCtrl.schemaAdd = extract_schema_add;
974     extractCtrl.dh = zh->reg->dh;
975     extractCtrl.handle = zh;
976     extractCtrl.zebra_maps = zh->reg->zebra_maps;
977     extractCtrl.flagShowRecords = 0;
978     for (i = 0; i<256; i++)
979     {
980         if (zebra_maps_is_positioned(zh->reg->zebra_maps, i))
981             extractCtrl.seqno[i] = 1;
982         else
983             extractCtrl.seqno[i] = 0;
984     }
985
986     r = (*recType->extract)(clientData, &extractCtrl);
987
988     if (r == RECCTRL_EXTRACT_EOF)
989         return 0;
990     else if (r == RECCTRL_EXTRACT_ERROR_GENERIC)
991     {
992         /* error occured during extraction ... */
993         yaz_log (LOG_WARN, "extract error: generic");
994         return 0;
995     }
996     else if (r == RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER)
997     {
998         /* error occured during extraction ... */
999         yaz_log (LOG_WARN, "extract error: no such filter");
1000         return 0;
1001     }
1002     if (zh->reg->keys.buf_used == 0)
1003     {
1004         /* the extraction process returned no information - the record
1005            is probably empty - unless flagShowRecords is in use */
1006         if (test_mode)
1007             return 1;
1008         logf (LOG_WARN, "No keys generated for record");
1009         logf (LOG_WARN, " The file is probably empty");
1010         return 1;
1011     }
1012     /* match criteria */
1013     matchStr = NULL;
1014
1015     if (! *sysno) {
1016         char *rinfo;
1017         if (match_criteria && *match_criteria) {
1018             matchStr = match_criteria;
1019         } else {
1020             if (zh->m_record_id && *zh->m_record_id) {
1021                 matchStr = fileMatchStr (zh, &zh->reg->keys, pr_fname, 
1022                                          zh->m_record_id);
1023                 if (!matchStr)
1024                 {
1025                     logf (LOG_WARN, "Bad match criteria (recordID)");
1026                     return 1;
1027                 }
1028             }
1029         }
1030         if (matchStr) {
1031             rinfo = dict_lookup (zh->reg->matchDict, matchStr);
1032             if (rinfo)
1033             {
1034                 assert(*rinfo == sizeof(*sysno));
1035                 memcpy (sysno, rinfo+1, sizeof(*sysno));
1036             }
1037         }
1038     }
1039
1040     if (! *sysno)
1041     {
1042         /* new record */
1043         if (delete_flag)
1044         {
1045             logf (LOG_LOG, "delete %s %s %ld", recordType,
1046                   pr_fname, (long) recordOffset);
1047             logf (LOG_WARN, "cannot delete record above (seems new)");
1048             return 1;
1049         }
1050         logf (LOG_LOG, "add %s %s %ld", recordType, pr_fname,
1051               (long) recordOffset);
1052         rec = rec_new (zh->reg->records);
1053
1054         *sysno = rec->sysno;
1055
1056         recordAttr = rec_init_attr (zh->reg->zei, rec);
1057
1058         if (matchStr)
1059         {
1060             dict_insert (zh->reg->matchDict, matchStr,
1061                          sizeof(*sysno), sysno);
1062         }
1063         extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
1064         extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
1065
1066         zh->records_inserted++;
1067     } 
1068     else
1069     {
1070         /* record already exists */
1071         struct recKeys delkeys;
1072         struct sortKeys sortKeys;
1073
1074         if (!allow_update) {
1075               logf (LOG_LOG, "skipped %s %s %ld", 
1076                     recordType, pr_fname, (long) recordOffset);
1077               logRecord(zh);
1078               return -1;
1079         }
1080
1081         rec = rec_get (zh->reg->records, *sysno);
1082         assert (rec);
1083         
1084         recordAttr = rec_init_attr (zh->reg->zei, rec);
1085         
1086         if (!force_update) {
1087             if (recordAttr->runNumber ==
1088                 zebraExplain_runNumberIncrement (zh->reg->zei, 0))
1089             {
1090                 logf (LOG_LOG, "skipped %s %s %ld", recordType,
1091                       pr_fname, (long) recordOffset);
1092                 extract_flushSortKeys (zh, *sysno, -1, &zh->reg->sortKeys);
1093                 rec_rm (&rec);
1094                 logRecord(zh);
1095                 return -1;
1096             }
1097         }
1098
1099         delkeys.buf_used = rec->size[recInfo_delKeys];
1100         delkeys.buf = rec->info[recInfo_delKeys];
1101
1102         sortKeys.buf_used = rec->size[recInfo_sortKeys];
1103         sortKeys.buf = rec->info[recInfo_sortKeys];
1104
1105         extract_flushSortKeys (zh, *sysno, 0, &sortKeys);
1106         extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
1107         if (delete_flag)
1108         {
1109             /* record going to be deleted */
1110             if (!delkeys.buf_used)
1111             {
1112                 logf (LOG_LOG, "delete %s %s %ld", recordType,
1113                       pr_fname, (long) recordOffset);
1114                 logf (LOG_WARN, "cannot delete file above, storeKeys false");
1115             }
1116             else
1117             {
1118                 logf (LOG_LOG, "delete %s %s %ld", recordType,
1119                       pr_fname, (long) recordOffset);
1120                 zh->records_deleted++;
1121                 if (matchStr)
1122                     dict_delete (zh->reg->matchDict, matchStr);
1123                 rec_del (zh->reg->records, &rec);
1124             }
1125             rec_rm (&rec);
1126             logRecord(zh);
1127             return 0;
1128         }
1129         else
1130         {
1131             /* record going to be updated */
1132             if (!delkeys.buf_used)
1133             {
1134                 logf (LOG_LOG, "update %s %s %ld", recordType,
1135                       pr_fname, (long) recordOffset);
1136                 logf (LOG_WARN, "cannot update file above, storeKeys false");
1137             }
1138             else
1139             {
1140                 logf (LOG_LOG, "update %s %s %ld", recordType,
1141                       pr_fname, (long) recordOffset);
1142                 extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
1143                 extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
1144                 zh->records_updated++;
1145             }
1146         }
1147     }
1148     /* update file type */
1149     xfree (rec->info[recInfo_fileType]);
1150     rec->info[recInfo_fileType] =
1151         rec_strdup (recordType, &rec->size[recInfo_fileType]);
1152
1153     /* update filename */
1154     xfree (rec->info[recInfo_filename]);
1155     rec->info[recInfo_filename] =
1156         rec_strdup (fname, &rec->size[recInfo_filename]);
1157
1158     /* update delete keys */
1159     xfree (rec->info[recInfo_delKeys]);
1160     if (zh->reg->keys.buf_used > 0 && zh->m_store_keys == 1)
1161     {
1162         rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
1163         rec->info[recInfo_delKeys] = zh->reg->keys.buf;
1164         zh->reg->keys.buf = NULL;
1165         zh->reg->keys.buf_max = 0;
1166     }
1167     else
1168     {
1169         rec->info[recInfo_delKeys] = NULL;
1170         rec->size[recInfo_delKeys] = 0;
1171     }
1172
1173     /* update sort keys */
1174     xfree (rec->info[recInfo_sortKeys]);
1175
1176     rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
1177     rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
1178     zh->reg->sortKeys.buf = NULL;
1179     zh->reg->sortKeys.buf_max = 0;
1180
1181     /* save file size of original record */
1182     zebraExplain_recordBytesIncrement (zh->reg->zei,
1183                                        - recordAttr->recordSize);
1184 #if 0
1185     recordAttr->recordSize = fi->file_moffset - recordOffset;
1186     if (!recordAttr->recordSize)
1187         recordAttr->recordSize = fi->file_max - recordOffset;
1188 #else
1189     recordAttr->recordSize = buf_size;
1190 #endif
1191     zebraExplain_recordBytesIncrement (zh->reg->zei,
1192                                        recordAttr->recordSize);
1193
1194     /* set run-number for this record */
1195     recordAttr->runNumber =
1196         zebraExplain_runNumberIncrement (zh->reg->zei, 0);
1197
1198     /* update store data */
1199     xfree (rec->info[recInfo_storeData]);
1200     if (zh->m_store_data)
1201     {
1202         rec->size[recInfo_storeData] = recordAttr->recordSize;
1203         rec->info[recInfo_storeData] = (char *)
1204             xmalloc (recordAttr->recordSize);
1205         memcpy (rec->info[recInfo_storeData], buf, recordAttr->recordSize);
1206     }
1207     else
1208     {
1209         rec->info[recInfo_storeData] = NULL;
1210         rec->size[recInfo_storeData] = 0;
1211     }
1212     /* update database name */
1213     xfree (rec->info[recInfo_databaseName]);
1214     rec->info[recInfo_databaseName] =
1215         rec_strdup (zh->basenames[0], &rec->size[recInfo_databaseName]); 
1216
1217     /* update offset */
1218     recordAttr->recordOffset = recordOffset;
1219     
1220     /* commit this record */
1221     rec_put (zh->reg->records, &rec);
1222     logRecord(zh);
1223     return 0;
1224 }
1225
1226 int explain_extract (void *handle, Record rec, data1_node *n)
1227 {
1228     ZebraHandle zh = (ZebraHandle) handle;
1229     struct recExtractCtrl extractCtrl;
1230     int i;
1231
1232     if (zebraExplain_curDatabase (zh->reg->zei,
1233                                   rec->info[recInfo_databaseName]))
1234     {
1235         abort();
1236         if (zebraExplain_newDatabase (zh->reg->zei,
1237                                       rec->info[recInfo_databaseName], 0))
1238             abort ();
1239     }
1240
1241     create_rec_keys_codec(&zh->reg->keys);
1242
1243     zh->reg->sortKeys.buf_used = 0;
1244     
1245     extractCtrl.init = extract_init;
1246     extractCtrl.tokenAdd = extract_token_add;
1247     extractCtrl.schemaAdd = extract_schema_add;
1248     extractCtrl.dh = zh->reg->dh;
1249     for (i = 0; i<256; i++)
1250         extractCtrl.seqno[i] = 0;
1251     extractCtrl.zebra_maps = zh->reg->zebra_maps;
1252     extractCtrl.flagShowRecords = 0;
1253     extractCtrl.handle = handle;
1254
1255     if (n)
1256         grs_extract_tree(&extractCtrl, n);
1257
1258     if (rec->size[recInfo_delKeys])
1259     {
1260         struct recKeys delkeys;
1261         struct sortKeys sortkeys;
1262
1263         delkeys.buf_used = rec->size[recInfo_delKeys];
1264         delkeys.buf = rec->info[recInfo_delKeys];
1265
1266         sortkeys.buf_used = rec->size[recInfo_sortKeys];
1267         sortkeys.buf = rec->info[recInfo_sortKeys];
1268
1269         extract_flushSortKeys (zh, rec->sysno, 0, &sortkeys);
1270         extract_flushRecordKeys (zh, rec->sysno, 0, &delkeys);
1271     }
1272     extract_flushRecordKeys (zh, rec->sysno, 1, &zh->reg->keys);
1273     extract_flushSortKeys (zh, rec->sysno, 1, &zh->reg->sortKeys);
1274
1275     xfree (rec->info[recInfo_delKeys]);
1276     rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
1277     rec->info[recInfo_delKeys] = zh->reg->keys.buf;
1278     zh->reg->keys.buf = NULL;
1279     zh->reg->keys.buf_max = 0;
1280
1281     xfree (rec->info[recInfo_sortKeys]);
1282     rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
1283     rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
1284     zh->reg->sortKeys.buf = NULL;
1285     zh->reg->sortKeys.buf_max = 0;
1286
1287     return 0;
1288 }
1289
1290 void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
1291                               int cmd, struct recKeys *reckeys)
1292 {
1293 #if IT_KEY_NEW
1294     void *decode_handle = iscz1_start();
1295 #else
1296     int seqno = 0;
1297 #if SU_SCHEME
1298 #else
1299     unsigned char attrSet = (unsigned char) -1;
1300     unsigned short attrUse = (unsigned short) -1;
1301 #endif
1302 #endif
1303     int off = 0;
1304     int ch = 0;
1305     ZebraExplainInfo zei = zh->reg->zei;
1306
1307     if (!zh->reg->key_buf)
1308     {
1309         int mem= 1024*1024* atoi( res_get_def( zh->res, "memmax", "8"));
1310         if (mem <= 0)
1311         {
1312             logf(LOG_WARN, "Invalid memory setting, using default 8 MB");
1313             mem= 1024*1024*8;
1314         }
1315         /* FIXME: That "8" should be in a default settings include */
1316         /* not hard-coded here! -H */
1317         zh->reg->key_buf = (char**) xmalloc (mem);
1318         zh->reg->ptr_top = mem/sizeof(char*);
1319         zh->reg->ptr_i = 0;
1320         zh->reg->key_buf_used = 0;
1321         zh->reg->key_file_no = 0;
1322     }
1323     zebraExplain_recordCountIncrement (zei, cmd ? 1 : -1);
1324 #if IT_KEY_NEW
1325     while (off < reckeys->buf_used)
1326     {
1327         const char *src = reckeys->buf + off;
1328         struct it_key key;
1329         char *dst = (char*) &key;
1330         int attrSet, attrUse;
1331
1332         iscz1_decode(decode_handle, &dst, &src);
1333         assert(key.len < 4 && key.len > 2);
1334
1335         attrSet = (int) key.mem[0];
1336         attrUse = (int) key.mem[1]; /* sequence in mem[2] */
1337
1338         if (zh->reg->key_buf_used + 1024 > 
1339             (zh->reg->ptr_top -zh->reg->ptr_i)*sizeof(char*))
1340             extract_flushWriteKeys (zh,0);
1341         ++(zh->reg->ptr_i);
1342         assert(zh->reg->ptr_i > 0);
1343         (zh->reg->key_buf)[zh->reg->ptr_top - zh->reg->ptr_i] =
1344             (char*)zh->reg->key_buf + zh->reg->key_buf_used;
1345
1346         ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
1347         if (ch < 0)
1348             ch = zebraExplain_addSU (zei, attrSet, attrUse);
1349
1350         assert (ch > 0);
1351         zh->reg->key_buf_used +=
1352             key_SU_encode (ch,((char*)zh->reg->key_buf) +
1353                            zh->reg->key_buf_used);
1354         while (*src)
1355             ((char*)zh->reg->key_buf) [(zh->reg->key_buf_used)++] = *src++;
1356         src++;
1357         ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = '\0';
1358         ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = cmd;
1359
1360         key.len = 2;
1361         key.mem[0] = sysno;
1362         key.mem[1] = key.mem[2];  /* sequence .. */
1363         
1364         memcpy ((char*)zh->reg->key_buf + zh->reg->key_buf_used,
1365                 &key, sizeof(key));
1366         (zh->reg->key_buf_used) += sizeof(key);
1367         off = src - reckeys->buf;
1368     }
1369 #else
1370     while (off < reckeys->buf_used)
1371     {
1372         const char *src = reckeys->buf + off;
1373         struct it_key key;
1374         int lead;
1375     
1376         lead = *src++;
1377
1378 #if SU_SCHEME
1379         if ((lead & 3) < 3)
1380         {
1381             memcpy (&ch, src, sizeof(ch));
1382             src += sizeof(ch);
1383         }
1384 #else
1385         if (!(lead & 1))
1386         {
1387             memcpy (&attrSet, src, sizeof(attrSet));
1388             src += sizeof(attrSet);
1389         }
1390         if (!(lead & 2))
1391         {
1392             memcpy (&attrUse, src, sizeof(attrUse));
1393             src += sizeof(attrUse);
1394         }
1395 #endif
1396         if (zh->reg->key_buf_used + 1024 > 
1397             (zh->reg->ptr_top -zh->reg->ptr_i)*sizeof(char*))
1398             extract_flushWriteKeys (zh,0);
1399         assert(zh->reg->ptr_i >= 0);
1400         ++(zh->reg->ptr_i);
1401         assert(zh->reg->ptr_i > 0);
1402         (zh->reg->key_buf)[zh->reg->ptr_top - zh->reg->ptr_i] =
1403             (char*)zh->reg->key_buf + zh->reg->key_buf_used;
1404 #if SU_SCHEME
1405 #else
1406         ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
1407         if (ch < 0)
1408             ch = zebraExplain_addSU (zei, attrSet, attrUse);
1409 #endif
1410         assert (ch > 0);
1411         zh->reg->key_buf_used +=
1412             key_SU_encode (ch,((char*)zh->reg->key_buf) +
1413                            zh->reg->key_buf_used);
1414
1415         while (*src)
1416             ((char*)zh->reg->key_buf) [(zh->reg->key_buf_used)++] = *src++;
1417         src++;
1418         ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = '\0';
1419         ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = cmd;
1420
1421         if (lead & 60)
1422             seqno += ((lead>>2) & 15)-1;
1423         else
1424         {
1425             memcpy (&seqno, src, sizeof(seqno));
1426             src += sizeof(seqno);
1427         }
1428         key.seqno = seqno;
1429         key.sysno = sysno;
1430         memcpy ((char*)zh->reg->key_buf + zh->reg->key_buf_used, &key, sizeof(key));
1431         (zh->reg->key_buf_used) += sizeof(key);
1432         off = src - reckeys->buf;
1433     }
1434 #endif
1435     assert (off == reckeys->buf_used);
1436 #if IT_KEY_NEW
1437     iscz1_stop(decode_handle);
1438 #endif
1439 }
1440
1441 void extract_flushWriteKeys (ZebraHandle zh, int final)
1442         /* optimizing: if final=1, and no files written yet */
1443         /* push the keys directly to merge, sidestepping the */
1444         /* temp file altogether. Speeds small updates */
1445 {
1446     FILE *outf;
1447     char out_fname[200];
1448     char *prevcp, *cp;
1449     struct encode_info encode_info;
1450     int ptr_i = zh->reg->ptr_i;
1451     int temp_policy;
1452 #if SORT_EXTRA
1453     int i;
1454 #endif
1455     if (!zh->reg->key_buf || ptr_i <= 0)
1456     {
1457         logf (LOG_DEBUG, "  nothing to flush section=%d buf=%p i=%d",
1458                zh->reg->key_file_no, zh->reg->key_buf, ptr_i);
1459         logf (LOG_DEBUG, "  buf=%p ",
1460                zh->reg->key_buf);
1461         logf (LOG_DEBUG, "  ptr=%d ",zh->reg->ptr_i);
1462         logf (LOG_DEBUG, "  reg=%p ",zh->reg);
1463                
1464         return;
1465     }
1466
1467     (zh->reg->key_file_no)++;
1468     logf (LOG_LOG, "sorting section %d", (zh->reg->key_file_no));
1469     logf (LOG_DEBUG, "  sort_buff at %p n=%d",
1470                     zh->reg->key_buf + zh->reg->ptr_top - ptr_i,ptr_i);
1471 #if !SORT_EXTRA
1472     qsort (zh->reg->key_buf + zh->reg->ptr_top - ptr_i, ptr_i,
1473                sizeof(char*), key_qsort_compare);
1474
1475     /* zebra.cfg: tempfiles:  
1476        Y: always use temp files (old way) 
1477        A: use temp files, if more than one (auto) 
1478           = if this is both the last and the first 
1479        N: never bother with temp files (new) */
1480
1481     temp_policy=toupper(res_get_def(zh->res,"tempfiles","auto")[0]);
1482     if (temp_policy != 'Y' && temp_policy != 'N' && temp_policy != 'A') {
1483         logf (LOG_WARN, "Illegal tempfiles setting '%c'. using 'Auto' ", 
1484                         temp_policy);
1485         temp_policy='A';
1486     }
1487
1488     if (   ( temp_policy =='N' )   ||     /* always from memory */
1489          ( ( temp_policy =='A' ) &&       /* automatic */
1490              (zh->reg->key_file_no == 1) &&  /* this is first time */
1491              (final) ) )                     /* and last (=only) time */
1492     { /* go directly from memory */
1493         zh->reg->key_file_no =0; /* signal not to read files */
1494         zebra_index_merge(zh); 
1495         zh->reg->ptr_i = 0;
1496         zh->reg->key_buf_used = 0; 
1497         return; 
1498     }
1499
1500     /* Not doing directly from memory, write into a temp file */
1501     extract_get_fname_tmp (zh, out_fname, zh->reg->key_file_no);
1502
1503     if (!(outf = fopen (out_fname, "wb")))
1504     {
1505         logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
1506         exit (1);
1507     }
1508     logf (LOG_LOG, "writing section %d", zh->reg->key_file_no);
1509     prevcp = cp = (zh->reg->key_buf)[zh->reg->ptr_top - ptr_i];
1510     
1511     encode_key_init (&encode_info);
1512     encode_key_write (cp, &encode_info, outf);
1513     
1514     while (--ptr_i > 0)
1515     {
1516         cp = (zh->reg->key_buf)[zh->reg->ptr_top - ptr_i];
1517         if (strcmp (cp, prevcp))
1518         {
1519             encode_key_flush ( &encode_info, outf);
1520             encode_key_init (&encode_info);
1521             encode_key_write (cp, &encode_info, outf);
1522             prevcp = cp;
1523         }
1524         else
1525             encode_key_write (cp + strlen(cp), &encode_info, outf);
1526     }
1527     encode_key_flush ( &encode_info, outf);
1528 #else
1529     qsort (key_buf + ptr_top-ptr_i, ptr_i, sizeof(char*), key_x_compare);
1530     extract_get_fname_tmp (out_fname, key_file_no);
1531
1532     if (!(outf = fopen (out_fname, "wb")))
1533     {
1534         logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
1535         exit (1);
1536     }
1537     logf (LOG_LOG, "writing section %d", key_file_no);
1538     i = ptr_i;
1539     prevcp =  key_buf[ptr_top-i];
1540     while (1)
1541         if (!--i || strcmp (prevcp, key_buf[ptr_top-i]))
1542         {
1543             key_y_len = strlen(prevcp)+1;
1544 #if 0
1545             logf (LOG_LOG, "key_y_len: %2d %02x %02x %s",
1546                       key_y_len, prevcp[0], prevcp[1], 2+prevcp);
1547 #endif
1548             qsort (key_buf + ptr_top-ptr_i, ptr_i - i,
1549                                    sizeof(char*), key_y_compare);
1550             cp = key_buf[ptr_top-ptr_i];
1551             --key_y_len;
1552             encode_key_init (&encode_info);
1553             encode_key_write (cp, &encode_info, outf);
1554             while (--ptr_i > i)
1555             {
1556                 cp = key_buf[ptr_top-ptr_i];
1557                 encode_key_write (cp+key_y_len, &encode_info, outf);
1558             }
1559             encode_key_flush ( &encode_info, outf);
1560             if (!i)
1561                 break;
1562             prevcp = key_buf[ptr_top-ptr_i];
1563         }
1564 #endif
1565     if (fclose (outf))
1566     {
1567         logf (LOG_FATAL|LOG_ERRNO, "fclose %s", out_fname);
1568         exit (1);
1569     }
1570     logf (LOG_LOG, "finished section %d", zh->reg->key_file_no);
1571     zh->reg->ptr_i = 0;
1572     zh->reg->key_buf_used = 0;
1573 }
1574
1575 void extract_add_index_string (RecWord *p, const char *str, int length)
1576 {
1577     char *dst;
1578     ZebraHandle zh = p->extractCtrl->handle;
1579     struct recKeys *keys = &zh->reg->keys;
1580 #if IT_KEY_NEW
1581     struct it_key key;
1582     const char *src = (char*) &key;
1583 #else
1584     unsigned char attrSet;
1585     unsigned short attrUse;
1586     int lead = 0;
1587     int diff = 0;
1588     int *pseqno = &p->seqno;
1589     ZebraExplainInfo zei = zh->reg->zei;
1590 #endif
1591     
1592     if (keys->buf_used+1024 > keys->buf_max)
1593     {
1594         char *b;
1595
1596         b = (char *) xmalloc (keys->buf_max += 128000);
1597         if (keys->buf_used > 0)
1598             memcpy (b, keys->buf, keys->buf_used);
1599         xfree (keys->buf);
1600         keys->buf = b;
1601     }
1602     dst = keys->buf + keys->buf_used;
1603
1604 #if IT_KEY_NEW
1605     key.len = 3;
1606     key.mem[0] = p->attrSet;
1607     key.mem[1] = p->attrUse;
1608     key.mem[2] = p->seqno;
1609
1610 #if 0
1611     /* just for debugging .. */
1612     yaz_log(LOG_LOG, "set=%d use=%d seqno=%d", p->attrSet, p->attrUse,
1613             p->seqno);
1614 #endif
1615
1616     iscz1_encode(keys->codec_handle, &dst, &src);
1617
1618     *dst++ = p->reg_type;
1619     memcpy (dst, str, length);
1620     dst += length;
1621     *dst++ = '\0';
1622 #else
1623     /* leader byte is encoded as follows:
1624        bit 0 : 1 if attrset is unchanged; 0 if attrset is changed
1625        bit 1 : 1 if attruse is unchanged; 0 if attruse is changed
1626     */
1627     attrSet = p->attrSet;
1628     if (keys->buf_used > 0 && keys->prevAttrSet == attrSet)
1629         lead |= 1;
1630     else
1631         keys->prevAttrSet = attrSet;
1632     attrUse = p->attrUse;
1633     if (keys->buf_used > 0 && keys->prevAttrUse == attrUse)
1634         lead |= 2;
1635     else
1636         keys->prevAttrUse = attrUse;
1637
1638     diff = 1 + *pseqno - keys->prevSeqNo;
1639     if (diff >= 1 && diff <= 15)
1640         lead |= (diff << 2);
1641     else
1642         diff = 0;
1643
1644     keys->prevSeqNo = *pseqno;
1645     
1646     *dst++ = lead;
1647
1648 #if SU_SCHEME
1649     if ((lead & 3) < 3)
1650     {
1651         int ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
1652         if (ch < 0)
1653         {
1654             ch = zebraExplain_addSU (zei, attrSet, attrUse);
1655             yaz_log (LOG_DEBUG, "addSU set=%d use=%d SU=%d",
1656                      attrSet, attrUse, ch);
1657         }
1658         assert (ch > 0);
1659         memcpy (dst, &ch, sizeof(ch));
1660         dst += sizeof(ch);
1661     }
1662 #else
1663     if (!(lead & 1))
1664     {
1665         memcpy (dst, &attrSet, sizeof(attrSet));
1666         dst += sizeof(attrSet);
1667     }
1668     if (!(lead & 2))
1669     {
1670         memcpy (dst, &attrUse, sizeof(attrUse));
1671         dst += sizeof(attrUse);
1672     }
1673 #endif
1674     *dst++ = p->reg_type;
1675     memcpy (dst, str, length);
1676     dst += length;
1677     *dst++ = '\0';
1678
1679     if (!diff)
1680     {
1681         memcpy (dst, pseqno, sizeof(*pseqno));
1682         dst += sizeof(*pseqno);
1683     }
1684 #endif
1685     keys->buf_used = dst - keys->buf;
1686 }
1687
1688 static void extract_add_sort_string (RecWord *p, const char *str,
1689                                      int length)
1690 {
1691     ZebraHandle zh = p->extractCtrl->handle;
1692     struct sortKeys *sk = &zh->reg->sortKeys;
1693     int off = 0;
1694
1695     while (off < sk->buf_used)
1696     {
1697         int set, use, slen;
1698
1699         off += key_SU_decode(&set, sk->buf + off);
1700         off += key_SU_decode(&use, sk->buf + off);
1701         off += key_SU_decode(&slen, sk->buf + off);
1702         off += slen;
1703         if (p->attrSet == set && p->attrUse == use)
1704             return;
1705     }
1706     assert (off == sk->buf_used);
1707     
1708     if (sk->buf_used + IT_MAX_WORD > sk->buf_max)
1709     {
1710         char *b;
1711         
1712         b = (char *) xmalloc (sk->buf_max += 128000);
1713         if (sk->buf_used > 0)
1714             memcpy (b, sk->buf, sk->buf_used);
1715         xfree (sk->buf);
1716         sk->buf = b;
1717     }
1718     off += key_SU_encode(p->attrSet, sk->buf + off);
1719     off += key_SU_encode(p->attrUse, sk->buf + off);
1720     off += key_SU_encode(length, sk->buf + off);
1721     memcpy (sk->buf + off, str, length);
1722     sk->buf_used = off + length;
1723 }
1724
1725 void extract_add_string (RecWord *p, const char *string, int length)
1726 {
1727     assert (length > 0);
1728     if (zebra_maps_is_sort (p->zebra_maps, p->reg_type))
1729         extract_add_sort_string (p, string, length);
1730     else
1731         extract_add_index_string (p, string, length);
1732 }
1733
1734 static void extract_add_incomplete_field (RecWord *p)
1735 {
1736     const char *b = p->string;
1737     int remain = p->length;
1738     const char **map = 0;
1739
1740     if (remain > 0)
1741         map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
1742
1743     while (map)
1744     {
1745         char buf[IT_MAX_WORD+1];
1746         int i, remain;
1747
1748         /* Skip spaces */
1749         while (map && *map && **map == *CHR_SPACE)
1750         {
1751             remain = p->length - (b - p->string);
1752             if (remain > 0)
1753                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
1754             else
1755                 map = 0;
1756         }
1757         if (!map)
1758             break;
1759         i = 0;
1760         while (map && *map && **map != *CHR_SPACE)
1761         {
1762             const char *cp = *map;
1763
1764             while (i < IT_MAX_WORD && *cp)
1765                 buf[i++] = *(cp++);
1766             remain = p->length - (b - p->string);
1767             if (remain > 0)
1768                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
1769             else
1770                 map = 0;
1771         }
1772         if (!i)
1773             return;
1774         extract_add_string (p, buf, i);
1775         p->seqno++;
1776     }
1777 }
1778
1779 static void extract_add_complete_field (RecWord *p)
1780 {
1781     const char *b = p->string;
1782     char buf[IT_MAX_WORD+1];
1783     const char **map = 0;
1784     int i = 0, remain = p->length;
1785
1786     if (remain > 0)
1787         map = zebra_maps_input (p->zebra_maps, p->reg_type, &b, remain);
1788
1789     while (remain > 0 && i < IT_MAX_WORD)
1790     {
1791         while (map && *map && **map == *CHR_SPACE)
1792         {
1793             remain = p->length - (b - p->string);
1794
1795             if (remain > 0)
1796                 map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
1797             else
1798                 map = 0;
1799         }
1800         if (!map)
1801             break;
1802
1803         if (i && i < IT_MAX_WORD)
1804             buf[i++] = *CHR_SPACE;
1805         while (map && *map && **map != *CHR_SPACE)
1806         {
1807             const char *cp = *map;
1808
1809             if (**map == *CHR_CUT)
1810             {
1811                 i = 0;
1812             }
1813             else
1814             {
1815                 if (i >= IT_MAX_WORD)
1816                     break;
1817                 while (i < IT_MAX_WORD && *cp)
1818                     buf[i++] = *(cp++);
1819             }
1820             remain = p->length  - (b - p->string);
1821             if (remain > 0)
1822                 map = zebra_maps_input (p->zebra_maps, p->reg_type, &b,
1823                                         remain);
1824             else
1825                 map = 0;
1826         }
1827     }
1828     if (!i)
1829         return;
1830     extract_add_string (p, buf, i);
1831 }
1832
1833 void extract_token_add (RecWord *p)
1834 {
1835     WRBUF wrbuf;
1836 #if 0
1837     yaz_log (LOG_LOG, "token_add "
1838              "reg_type=%c attrSet=%d attrUse=%d seqno=%d s=%.*s",
1839              p->reg_type, p->attrSet, p->attrUse, p->seqno, p->length,
1840              p->string);
1841 #endif
1842     if ((wrbuf = zebra_replace(p->zebra_maps, p->reg_type, 0,
1843                                p->string, p->length)))
1844     {
1845         p->string = wrbuf_buf(wrbuf);
1846         p->length = wrbuf_len(wrbuf);
1847     }
1848     if (zebra_maps_is_complete (p->zebra_maps, p->reg_type))
1849         extract_add_complete_field (p);
1850     else
1851         extract_add_incomplete_field(p);
1852 }
1853
1854 void extract_schema_add (struct recExtractCtrl *p, Odr_oid *oid)
1855 {
1856     ZebraHandle zh = (ZebraHandle) (p->handle);
1857     zebraExplain_addSchema (zh->reg->zei, oid);
1858 }
1859
1860 void extract_flushSortKeys (ZebraHandle zh, SYSNO sysno,
1861                             int cmd, struct sortKeys *sk)
1862 {
1863     SortIdx sortIdx = zh->reg->sortIdx;
1864     int off = 0;
1865
1866     sortIdx_sysno (sortIdx, sysno);
1867
1868     while (off < sk->buf_used)
1869     {
1870         int set, use, slen;
1871         
1872         off += key_SU_decode(&set, sk->buf + off);
1873         off += key_SU_decode(&use, sk->buf + off);
1874         off += key_SU_decode(&slen, sk->buf + off);
1875         
1876         sortIdx_type(sortIdx, use);
1877         if (cmd == 1)
1878             sortIdx_add(sortIdx, sk->buf + off, slen);
1879         else
1880             sortIdx_add(sortIdx, "", 1);
1881         off += slen;
1882     }
1883 }
1884
1885 void encode_key_init (struct encode_info *i)
1886 {
1887     i->sysno = 0;
1888     i->seqno = 0;
1889     i->cmd = -1;
1890     i->prevsys=0;
1891     i->prevseq=0;
1892     i->prevcmd=-1;
1893     i->keylen=0;
1894 #if IT_KEY_NEW
1895     i->encode_handle = iscz1_start();
1896 #endif
1897 }
1898
1899 #if IT_KEY_NEW
1900 #else
1901 char *encode_key_int (int d, char *bp)
1902 {
1903     if (d <= 63)
1904         *bp++ = d;
1905     else if (d <= 16383)
1906     {
1907         *bp++ = 64 + (d>>8);
1908         *bp++ = d  & 255;
1909     }
1910     else if (d <= 4194303)
1911     {
1912         *bp++ = 128 + (d>>16);
1913         *bp++ = (d>>8) & 255;
1914         *bp++ = d & 255;
1915     }
1916     else
1917     {
1918         *bp++ = 192 + (d>>24);
1919         *bp++ = (d>>16) & 255;
1920         *bp++ = (d>>8) & 255;
1921         *bp++ = d & 255;
1922     }
1923     return bp;
1924 }
1925 #endif
1926
1927 #define OLDENCODE 1
1928
1929 #ifdef OLDENCODE
1930 /* this is the old encode_key_write 
1931  * may be deleted once we are confident that the new works
1932  * HL 15-oct-2002
1933  */
1934 void encode_key_write (char *k, struct encode_info *i, FILE *outf)
1935 {
1936     struct it_key key;
1937     char *bp = i->buf, *bp0;
1938     const char *src = (char *) &key;
1939
1940     /* copy term to output buf */
1941     while ((*bp++ = *k++))
1942         ;
1943     /* and copy & align key so we can mangle */
1944     memcpy (&key, k+1, sizeof(struct it_key));  /* *k is insert/delete */
1945 #if IT_KEY_NEW
1946     bp0 = bp++;
1947     iscz1_encode(i->encode_handle, &bp, &src);
1948     *bp0 = (*k * 128) + bp - bp0 - 1; /* length and insert/delete combined */
1949 #else
1950     bp = encode_key_int ( (key.sysno - i->sysno) * 2 + *k, bp);
1951     if (i->sysno != key.sysno)
1952     {
1953         i->sysno = key.sysno;
1954         i->seqno = 0;
1955     }
1956     else if (!i->seqno && !key.seqno && i->cmd == *k)
1957         return;
1958     bp = encode_key_int (key.seqno - i->seqno, bp);
1959     i->seqno = key.seqno;
1960     i->cmd = *k;
1961 #endif
1962     if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
1963     {
1964         logf (LOG_FATAL|LOG_ERRNO, "fwrite");
1965         exit (1);
1966     }
1967 }
1968
1969 void encode_key_flush (struct encode_info *i, FILE *outf)
1970 { /* dummy routine */
1971 #if IT_KEY_NEW
1972     iscz1_stop(i->encode_handle);
1973 #endif
1974 }
1975
1976 #else
1977
1978 /* new encode_key_write
1979  * The idea is to buffer one more key, and compare them
1980  * If we are going to delete and insert the same key, 
1981  * we may as well not bother. Should make a difference in 
1982  * updates with small modifications (appending to a mbox)
1983  */
1984 void encode_key_write (char *k, struct encode_info *i, FILE *outf)
1985 {
1986     struct it_key key;
1987     char *bp; 
1988
1989     if (*k)  /* first time for new key */
1990     {
1991         bp = i->buf;
1992         while ((*bp++ = *k++))
1993             ;
1994         i->keylen= bp - i->buf -1;    
1995         assert(i->keylen+1+sizeof(struct it_key) < ENCODE_BUFLEN);
1996     }
1997     else
1998     {
1999         bp=i->buf + i->keylen;
2000         *bp++=0;
2001         k++;
2002     }
2003
2004     memcpy (&key, k+1, sizeof(struct it_key));
2005     if (0==i->prevsys) /* no previous filter, fill up */
2006     {
2007         i->prevsys=key.sysno;
2008         i->prevseq=key.seqno;
2009         i->prevcmd=*k;
2010     }
2011     else if ( (i->prevsys==key.sysno) &&
2012               (i->prevseq==key.seqno) &&
2013               (i->prevcmd!=*k) )
2014     { /* same numbers, diff cmd, they cancel out */
2015         i->prevsys=0;
2016     }
2017     else 
2018     { /* different stuff, write previous, move buf */
2019         bp = encode_key_int ( (i->prevsys - i->sysno) * 2 + i->prevcmd, bp);
2020         if (i->sysno != i->prevsys)
2021         {
2022             i->sysno = i->prevsys;
2023             i->seqno = 0;
2024         }
2025         else if (!i->seqno && !i->prevseq && i->cmd == i->prevcmd)
2026         {
2027             return; /* ??? Filters some sort of duplicates away */
2028                     /* ??? Can this ever happen   -H 15oct02 */
2029         }
2030         bp = encode_key_int (i->prevseq - i->seqno, bp);
2031         i->seqno = i->prevseq;
2032         i->cmd = i->prevcmd;
2033         if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
2034         {
2035             logf (LOG_FATAL|LOG_ERRNO, "fwrite");
2036             exit (1);
2037         }
2038         i->keylen=0; /* ok, it's written, forget it */
2039         i->prevsys=key.sysno;
2040         i->prevseq=key.seqno;
2041         i->prevcmd=*k;
2042     }
2043 }
2044
2045 void encode_key_flush (struct encode_info *i, FILE *outf)
2046 { /* flush the last key from i */
2047     char *bp =i->buf + i->keylen;
2048     if (0==i->prevsys)
2049     {
2050         return; /* nothing to flush */
2051     }
2052     *bp++=0;
2053     bp = encode_key_int ( (i->prevsys - i->sysno) * 2 + i->prevcmd, bp);
2054     if (i->sysno != i->prevsys)
2055     {
2056         i->sysno = i->prevsys;
2057         i->seqno = 0;
2058     }
2059     else if (!i->seqno && !i->prevseq && i->cmd == i->prevcmd)
2060     {
2061         return; /* ??? Filters some sort of duplicates away */
2062                 /* ??? Can this ever happen   -H 15oct02 */
2063     }
2064     bp = encode_key_int (i->prevseq - i->seqno, bp);
2065     i->seqno = i->prevseq;
2066     i->cmd = i->prevcmd;
2067     if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
2068     {
2069         logf (LOG_FATAL|LOG_ERRNO, "fwrite");
2070         exit (1);
2071     }
2072     i->keylen=0; /* ok, it's written, forget it */
2073     i->prevsys=0; /* forget the values too */
2074     i->prevseq=0;
2075 }
2076 #endif