More type casts due to zint.
[idzebra-moved-to-github.git] / index / extract.c
1 /* $Id: extract.c,v 1.159 2004-08-06 13:36:22 adam 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: %7d i/u/d %d/%d/%d", 
76               zh->records_processed, zh->records_inserted, zh->records_updated,
77               zh->records_deleted);
78     }
79 }
80
81 static void extract_init (struct recExtractCtrl *p, RecWord *w)
82 {
83     w->zebra_maps = p->zebra_maps;
84     w->seqno = 1;
85     w->attrSet = VAL_BIB1;
86     w->attrUse = 1016;
87     w->reg_type = 'w';
88     w->extractCtrl = p;
89 }
90
91 static const char **searchRecordKey (ZebraHandle zh,
92                                      struct recKeys *reckeys,
93                                      int attrSetS, int attrUseS)
94 {
95 #if IT_KEY_NEW
96 /* #error searchRecordKey does not work yet in this mode.. */
97     static const char *ws[32];
98     void *decode_handle = iscz1_start();
99     int off = 0;
100     int startSeq = -1;
101     int seqno = 0;
102     int i;
103
104     for (i = 0; i<32; i++)
105         ws[i] = NULL;
106
107     while (off < reckeys->buf_used)
108     {
109         const char *src = reckeys->buf + off;
110         struct it_key key;
111         char *dst = (char*) &key;
112         int attrSet, attrUse;
113
114         iscz1_decode(decode_handle, &dst, &src);
115         assert(key.len < 4 && key.len > 2);
116
117         attrSet = (int) key.mem[0];
118         attrUse = (int) key.mem[1];
119         seqno = (int) key.mem[2];
120
121         if (attrUseS == attrUse && attrSetS == attrSet)
122         {
123             int woff;
124
125             if (startSeq == -1)
126                 startSeq = seqno;
127             woff = seqno - startSeq;
128             if (woff >= 0 && woff < 31)
129                 ws[woff] = src;
130         }
131
132         while (*src++)
133             ;
134         off = src - reckeys->buf;
135     }
136     iscz1_stop(decode_handle);
137     assert (off == reckeys->buf_used);
138     return ws;
139 #else
140     static const char *ws[32];
141     int off = 0;
142     int startSeq = -1;
143     int i;
144     int seqno = 0;
145 #if SU_SCHEME
146     int chS, ch;
147 #else
148     short attrUse;
149     char attrSet;
150 #endif
151
152     for (i = 0; i<32; i++)
153         ws[i] = NULL;
154
155 #if SU_SCHEME
156     chS = zebraExplain_lookupSU (zh->reg->zei, attrSetS, attrUseS);
157     if (chS < 0)
158         return ws;
159 #endif
160     while (off < reckeys->buf_used)
161     {
162
163         const char *src = reckeys->buf + off;
164         const char *wstart;
165         int lead;
166     
167         lead = *src++;
168 #if SU_SCHEME
169         if ((lead & 3)<3)
170         {
171             memcpy (&ch, src, sizeof(ch));
172             src += sizeof(ch);
173         }
174 #else
175         if (!(lead & 1))
176         {
177             memcpy (&attrSet, src, sizeof(attrSet));
178             src += sizeof(attrSet);
179         }
180         if (!(lead & 2))
181         {
182             memcpy (&attrUse, src, sizeof(attrUse));
183             src += sizeof(attrUse);
184         }
185 #endif
186         wstart = src;
187         while (*src++)
188             ;
189         if (lead & 60)
190             seqno += ((lead>>2) & 15)-1;
191         else
192         {
193             memcpy (&seqno, src, sizeof(seqno));
194             src += sizeof(seqno);
195         }
196         if (
197 #if SU_SCHEME
198             ch == chS
199 #else
200             attrUseS == attrUse && attrSetS == attrSet
201 #endif
202             )
203         {
204             int woff;
205
206
207             if (startSeq == -1)
208                 startSeq = seqno;
209             woff = seqno - startSeq;
210             if (woff >= 0 && woff < 31)
211                 ws[woff] = wstart;
212         }
213
214         off = src - reckeys->buf;
215     }
216     assert (off == reckeys->buf_used);
217     return ws;
218 #endif
219 }
220
221 struct file_read_info {
222     off_t file_max;         /* maximum offset so far */
223     off_t file_offset;      /* current offset */
224     off_t file_moffset;     /* offset of rec/rec boundary */
225     int file_more;
226     int fd;
227     char *sdrbuf;
228     int sdrmax;
229 };
230
231 static struct file_read_info *file_read_start (int fd)
232 {
233     struct file_read_info *fi = (struct file_read_info *)
234         xmalloc (sizeof(*fi));
235
236     fi->fd = fd;
237     fi->file_max = 0;
238     fi->file_moffset = 0;
239     fi->sdrbuf = 0;
240     fi->sdrmax = 0;
241     return fi;
242 }
243
244 static void file_read_stop (struct file_read_info *fi)
245 {
246     xfree (fi);
247 }
248
249 static off_t file_seek (void *handle, off_t offset)
250 {
251     struct file_read_info *p = (struct file_read_info *) handle;
252     p->file_offset = offset;
253     if (p->sdrbuf)
254         return offset;
255     return lseek (p->fd, offset, SEEK_SET);
256 }
257
258 static off_t file_tell (void *handle)
259 {
260     struct file_read_info *p = (struct file_read_info *) handle;
261     return p->file_offset;
262 }
263
264 static int file_read (void *handle, char *buf, size_t count)
265 {
266     struct file_read_info *p = (struct file_read_info *) handle;
267     int fd = p->fd;
268     int r;
269     if (p->sdrbuf)
270     {
271         r = count;
272         if (r > p->sdrmax - p->file_offset)
273             r = p->sdrmax - p->file_offset;
274         if (r)
275             memcpy (buf, p->sdrbuf + p->file_offset, r);
276     }
277     else
278         r = read (fd, buf, count);
279     if (r > 0)
280     {
281         p->file_offset += r;
282         if (p->file_offset > p->file_max)
283             p->file_max = p->file_offset;
284     }
285     return r;
286 }
287
288 static void file_begin (void *handle)
289 {
290     struct file_read_info *p = (struct file_read_info *) handle;
291
292     p->file_offset = p->file_moffset;
293     if (!p->sdrbuf && p->file_moffset)
294         lseek (p->fd, p->file_moffset, SEEK_SET);
295     p->file_more = 0;
296 }
297
298 static void file_end (void *handle, off_t offset)
299 {
300     struct file_read_info *p = (struct file_read_info *) handle;
301
302     assert (p->file_more == 0);
303     p->file_more = 1;
304     p->file_moffset = offset;
305 }
306
307 static char *fileMatchStr (ZebraHandle zh,
308                            struct recKeys *reckeys,
309                            const char *fname, const char *spec)
310 {
311     static char dstBuf[2048];      /* static here ??? */
312     char *dst = dstBuf;
313     const char *s = spec;
314     static const char **w;
315
316     while (1)
317     {
318         while (*s == ' ' || *s == '\t')
319             s++;
320         if (!*s)
321             break;
322         if (*s == '(')
323         {
324             char attset_str[64], attname_str[64];
325             data1_attset *attset;
326             int i;
327             char matchFlag[32];
328             int attSet = 1, attUse = 1;
329             int first = 1;
330
331             s++;
332             for (i = 0; *s && *s != ',' && *s != ')'; s++)
333                 if (i < 63)
334                     attset_str[i++] = *s;
335             attset_str[i] = '\0';
336
337             if (*s == ',')
338             {
339                 s++;
340                 for (i = 0; *s && *s != ')'; s++)
341                     if (i < 63)
342                         attname_str[i++] = *s;
343                 attname_str[i] = '\0';
344             }
345             
346             if ((attset = data1_get_attset (zh->reg->dh, attset_str)))
347             {
348                 data1_att *att;
349                 attSet = attset->reference;
350                 att = data1_getattbyname(zh->reg->dh, attset, attname_str);
351                 if (att)
352                     attUse = att->value;
353                 else
354                     attUse = atoi (attname_str);
355             }
356             w = searchRecordKey (zh, reckeys, attSet, attUse);
357             assert (w);
358
359             if (*s == ')')
360             {
361                 for (i = 0; i<32; i++)
362                     matchFlag[i] = 1;
363             }
364             else
365             {
366                 logf (LOG_WARN, "Missing ) in match criteria %s in group %s",
367                       spec, zh->m_group ? zh->m_group : "none");
368                 return NULL;
369             }
370             s++;
371
372             for (i = 0; i<32; i++)
373                 if (matchFlag[i] && w[i])
374                 {
375                     if (first)
376                     {
377                         *dst++ = ' ';
378                         first = 0;
379                     }
380                     strcpy (dst, w[i]);
381                     dst += strlen(w[i]);
382                 }
383             if (first)
384             {
385                 logf (LOG_WARN, "Record didn't contain match"
386                       " fields in (%s,%s)", attset_str, attname_str);
387                 return NULL;
388             }
389         }
390         else if (*s == '$')
391         {
392             int spec_len;
393             char special[64];
394             const char *spec_src = NULL;
395             const char *s1 = ++s;
396             while (*s1 && *s1 != ' ' && *s1 != '\t')
397                 s1++;
398
399             spec_len = s1 - s;
400             if (spec_len > 63)
401                 spec_len = 63;
402             memcpy (special, s, spec_len);
403             special[spec_len] = '\0';
404             s = s1;
405
406             if (!strcmp (special, "group"))
407                 spec_src = zh->m_group;
408             else if (!strcmp (special, "database"))
409                 spec_src = zh->basenames[0];
410             else if (!strcmp (special, "filename")) {
411                 spec_src = fname;
412             }
413             else if (!strcmp (special, "type"))
414                 spec_src = zh->m_record_type;
415             else 
416                 spec_src = NULL;
417             if (spec_src)
418             {
419                 strcpy (dst, spec_src);
420                 dst += strlen (spec_src);
421             }
422         }
423         else if (*s == '\"' || *s == '\'')
424         {
425             int stopMarker = *s++;
426             char tmpString[64];
427             int i = 0;
428
429             while (*s && *s != stopMarker)
430             {
431                 if (i < 63)
432                     tmpString[i++] = *s++;
433             }
434             if (*s)
435                 s++;
436             tmpString[i] = '\0';
437             strcpy (dst, tmpString);
438             dst += strlen (tmpString);
439         }
440         else
441         {
442             logf (LOG_WARN, "Syntax error in match criteria %s in group %s",
443                   spec, zh->m_group ? zh->m_group : "none");
444             return NULL;
445         }
446         *dst++ = 1;
447     }
448     if (dst == dstBuf)
449     {
450         logf (LOG_WARN, "No match criteria for record %s in group %s",
451               fname, zh->m_group ? zh->m_group : "none");
452         return NULL;
453     }
454     *dst = '\0';
455     return dstBuf;
456 }
457
458 struct recordLogInfo {
459     const char *fname;
460     int recordOffset;
461     struct recordGroup *rGroup;
462 };
463
464 void create_rec_keys_codec(struct recKeys *keys)
465 {
466     keys->buf_used = 0;
467 #if IT_KEY_NEW
468     iscz1_reset(keys->codec_handle);
469 #else
470     keys->prevAttrUse = -1;
471     keys->prevAttrSet = -1;
472     keys->prevSeqNo = 0;
473 #endif
474 }
475      
476 static int file_extract_record(ZebraHandle zh,
477                                SYSNO *sysno, const char *fname,
478                                int deleteFlag,
479                                struct file_read_info *fi,
480                                int force_update)
481 {
482     RecordAttr *recordAttr;
483     int r;
484     const char *matchStr;
485     SYSNO sysnotmp;
486     Record rec;
487     off_t recordOffset = 0;
488     RecType recType;
489     void *clientData;
490     char subType[128];
491     
492     if (!(recType =
493           recType_byName (zh->reg->recTypes, zh->m_record_type, subType,
494                           &clientData)))
495     {
496         logf (LOG_WARN, "No such record type: %s", zh->m_record_type);
497         return 0;
498     }
499
500     /* announce database */
501     if (zebraExplain_curDatabase (zh->reg->zei, zh->basenames[0]))
502     {
503         if (zebraExplain_newDatabase (zh->reg->zei, zh->basenames[0],
504                                       zh->m_explain_database))
505             return 0;
506     }
507
508     if (fi->fd != -1)
509     {
510         struct recExtractCtrl extractCtrl;
511
512         /* we are going to read from a file, so prepare the extraction */
513         int i;
514
515         create_rec_keys_codec(&zh->reg->keys);
516
517         zh->reg->sortKeys.buf_used = 0;
518         
519         recordOffset = fi->file_moffset;
520         extractCtrl.offset = fi->file_moffset;
521         extractCtrl.readf = file_read;
522         extractCtrl.seekf = file_seek;
523         extractCtrl.tellf = file_tell;
524         extractCtrl.endf = file_end;
525         extractCtrl.fh = fi;
526         extractCtrl.subType = subType;
527         extractCtrl.init = extract_init;
528         extractCtrl.tokenAdd = extract_token_add;
529         extractCtrl.schemaAdd = extract_schema_add;
530         extractCtrl.dh = zh->reg->dh;
531         extractCtrl.handle = zh;
532         for (i = 0; i<256; i++)
533         {
534             if (zebra_maps_is_positioned(zh->reg->zebra_maps, i))
535                 extractCtrl.seqno[i] = 1;
536             else
537                 extractCtrl.seqno[i] = 0;
538         }
539         extractCtrl.zebra_maps = zh->reg->zebra_maps;
540         extractCtrl.flagShowRecords = !zh->m_flag_rw;
541
542         if (!zh->m_flag_rw)
543             printf ("File: %s " PRINTF_OFF_T "\n", fname, recordOffset);
544         if (zh->m_flag_rw)
545         {
546             char msg[512];
547             sprintf (msg, "%s:" PRINTF_OFF_T , fname, recordOffset);
548             yaz_log_init_prefix2 (msg);
549         }
550
551         r = (*recType->extract)(clientData, &extractCtrl);
552
553         yaz_log_init_prefix2 (0);
554         if (r == RECCTRL_EXTRACT_EOF)
555             return 0;
556         else if (r == RECCTRL_EXTRACT_ERROR_GENERIC)
557         {
558             /* error occured during extraction ... */
559             if (zh->m_flag_rw &&
560                 zh->records_processed < zh->m_file_verbose_limit)
561             {
562                 logf (LOG_WARN, "fail %s %s " PRINTF_OFF_T, zh->m_record_type,
563                       fname, recordOffset);
564             }
565             return 0;
566         }
567         else if (r == RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER)
568         {
569             /* error occured during extraction ... */
570             if (zh->m_flag_rw &&
571                 zh->records_processed < zh->m_file_verbose_limit)
572             {
573                 logf (LOG_WARN, "no filter for %s %s " 
574                       PRINTF_OFF_T, zh->m_record_type,
575                       fname, recordOffset);
576             }
577             return 0;
578         }
579         if (zh->reg->keys.buf_used == 0)
580         {
581             /* the extraction process returned no information - the record
582                is probably empty - unless flagShowRecords is in use */
583             if (!zh->m_flag_rw)
584                 return 1;
585             
586             logf (LOG_WARN, "empty %s %s " PRINTF_OFF_T, zh->m_record_type,
587                   fname, recordOffset);
588             return 1;
589         }
590     }
591
592     /* perform match if sysno not known and if match criteria is specified */
593        
594     matchStr = NULL;
595     if (!sysno) 
596     {
597         sysnotmp = 0;
598         sysno = &sysnotmp;
599         if (zh->m_record_id && *zh->m_record_id)
600         {
601             char *rinfo;
602         
603             matchStr = fileMatchStr (zh, &zh->reg->keys, fname, 
604                                      zh->m_record_id);
605             if (matchStr)
606             {
607                 rinfo = dict_lookup (zh->reg->matchDict, matchStr);
608                 if (rinfo)
609                 {
610                     assert(*rinfo == sizeof(*sysno));
611                     memcpy (sysno, rinfo+1, sizeof(*sysno));
612                 }
613             }
614             else
615             {
616                 logf (LOG_WARN, "Bad match criteria");
617                 return 0;
618             }
619         }
620     }
621
622     if (! *sysno)
623     {
624         /* new record */
625         if (deleteFlag)
626         {
627             logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T, zh->m_record_type,
628                   fname, recordOffset);
629             logf (LOG_WARN, "cannot delete record above (seems new)");
630             return 1;
631         }
632         if (zh->records_processed < zh->m_file_verbose_limit)
633             logf (LOG_LOG, "add %s %s " PRINTF_OFF_T, zh->m_record_type,
634                   fname, recordOffset);
635         rec = rec_new (zh->reg->records);
636
637         *sysno = rec->sysno;
638
639         recordAttr = rec_init_attr (zh->reg->zei, rec);
640
641         if (matchStr)
642         {
643             dict_insert (zh->reg->matchDict, matchStr, sizeof(*sysno), sysno);
644         }
645         extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
646         extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
647
648         zh->records_inserted++;
649     }
650     else
651     {
652         /* record already exists */
653         struct recKeys delkeys;
654         struct sortKeys sortKeys;
655
656         rec = rec_get (zh->reg->records, *sysno);
657         assert (rec);
658         
659         recordAttr = rec_init_attr (zh->reg->zei, rec);
660
661         if (!force_update && recordAttr->runNumber ==
662             zebraExplain_runNumberIncrement (zh->reg->zei, 0))
663         {
664             yaz_log (LOG_LOG, "run number = %d", recordAttr->runNumber);
665             yaz_log (LOG_LOG, "skipped %s %s " PRINTF_OFF_T,
666                      zh->m_record_type, fname, recordOffset);
667             extract_flushSortKeys (zh, *sysno, -1, &zh->reg->sortKeys);
668             rec_rm (&rec);
669             logRecord (zh);
670             return 1;
671         }
672         delkeys.buf_used = rec->size[recInfo_delKeys];
673         delkeys.buf = rec->info[recInfo_delKeys];
674
675         sortKeys.buf_used = rec->size[recInfo_sortKeys];
676         sortKeys.buf = rec->info[recInfo_sortKeys];
677
678         extract_flushSortKeys (zh, *sysno, 0, &sortKeys);
679         extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
680         if (deleteFlag)
681         {
682             /* record going to be deleted */
683             if (!delkeys.buf_used)
684             {
685                 logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
686                       zh->m_record_type, fname, recordOffset);
687                 logf (LOG_WARN, "cannot delete file above, storeKeys false");
688             }
689             else
690             {
691                 if (zh->records_processed < zh->m_file_verbose_limit)
692                     logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
693                          zh->m_record_type, fname, recordOffset);
694                 zh->records_deleted++;
695                 if (matchStr)
696                     dict_delete (zh->reg->matchDict, matchStr);
697                 rec_del (zh->reg->records, &rec);
698             }
699             rec_rm (&rec);
700             logRecord (zh);
701             return 1;
702         }
703         else
704         {
705             /* record going to be updated */
706             if (!delkeys.buf_used)
707             {
708                 logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
709                       zh->m_record_type, fname, recordOffset);
710                 logf (LOG_WARN, "cannot update file above, storeKeys false");
711             }
712             else
713             {
714                 if (zh->records_processed < zh->m_file_verbose_limit)
715                     logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
716                         zh->m_record_type, fname, recordOffset);
717                 extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
718                 extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
719                 zh->records_updated++;
720             }
721         }
722     }
723     /* update file type */
724     xfree (rec->info[recInfo_fileType]);
725     rec->info[recInfo_fileType] =
726         rec_strdup (zh->m_record_type, &rec->size[recInfo_fileType]);
727
728     /* update filename */
729     xfree (rec->info[recInfo_filename]);
730     rec->info[recInfo_filename] =
731         rec_strdup (fname, &rec->size[recInfo_filename]);
732
733     /* update delete keys */
734     xfree (rec->info[recInfo_delKeys]);
735     if (zh->reg->keys.buf_used > 0 && zh->m_store_keys == 1)
736     {
737         rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
738         rec->info[recInfo_delKeys] = zh->reg->keys.buf;
739         zh->reg->keys.buf = NULL;
740         zh->reg->keys.buf_max = 0;
741     }
742     else
743     {
744         rec->info[recInfo_delKeys] = NULL;
745         rec->size[recInfo_delKeys] = 0;
746     }
747
748     /* update sort keys */
749     xfree (rec->info[recInfo_sortKeys]);
750
751     rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
752     rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
753     zh->reg->sortKeys.buf = NULL;
754     zh->reg->sortKeys.buf_max = 0;
755
756     /* save file size of original record */
757     zebraExplain_recordBytesIncrement (zh->reg->zei,
758                                        - recordAttr->recordSize);
759     recordAttr->recordSize = fi->file_moffset - recordOffset;
760     if (!recordAttr->recordSize)
761         recordAttr->recordSize = fi->file_max - recordOffset;
762     zebraExplain_recordBytesIncrement (zh->reg->zei,
763                                        recordAttr->recordSize);
764
765     /* set run-number for this record */
766     recordAttr->runNumber = zebraExplain_runNumberIncrement (zh->reg->zei,
767                                                              0);
768
769     /* update store data */
770     xfree (rec->info[recInfo_storeData]);
771     if (zh->m_store_data)
772     {
773         rec->size[recInfo_storeData] = recordAttr->recordSize;
774         rec->info[recInfo_storeData] = (char *)
775             xmalloc (recordAttr->recordSize);
776         if (lseek (fi->fd, recordOffset, SEEK_SET) < 0)
777         {
778             logf (LOG_ERRNO|LOG_FATAL, "seek to " PRINTF_OFF_T " in %s",
779                   recordOffset, fname);
780             exit (1);
781         }
782         if (read (fi->fd, rec->info[recInfo_storeData], recordAttr->recordSize)
783             < recordAttr->recordSize)
784         {
785             logf (LOG_ERRNO|LOG_FATAL, "read %d bytes of %s",
786                   recordAttr->recordSize, fname);
787             exit (1);
788         }
789     }
790     else
791     {
792         rec->info[recInfo_storeData] = NULL;
793         rec->size[recInfo_storeData] = 0;
794     }
795     /* update database name */
796     xfree (rec->info[recInfo_databaseName]);
797     rec->info[recInfo_databaseName] =
798         rec_strdup (zh->basenames[0], &rec->size[recInfo_databaseName]); 
799
800     /* update offset */
801     recordAttr->recordOffset = recordOffset;
802     
803     /* commit this record */
804     rec_put (zh->reg->records, &rec);
805     logRecord (zh);
806     return 1;
807 }
808
809 int fileExtract (ZebraHandle zh, SYSNO *sysno, const char *fname, 
810                  int deleteFlag)
811 {
812     int r, i, fd;
813     char gprefix[128];
814     char ext[128];
815     char ext_res[128];
816     struct file_read_info *fi;
817     const char *original_record_type = 0;
818
819     if (!zh->m_group || !*zh->m_group)
820         *gprefix = '\0';
821     else
822         sprintf (gprefix, "%s.", zh->m_group);
823     
824     logf (LOG_DEBUG, "fileExtract %s", fname);
825
826     /* determine file extension */
827     *ext = '\0';
828     for (i = strlen(fname); --i >= 0; )
829         if (fname[i] == '/')
830             break;
831         else if (fname[i] == '.')
832         {
833             strcpy (ext, fname+i+1);
834             break;
835         }
836     /* determine file type - depending on extension */
837     original_record_type = zh->m_record_type;
838     if (!zh->m_record_type)
839     {
840         sprintf (ext_res, "%srecordType.%s", gprefix, ext);
841         zh->m_record_type = res_get (zh->res, ext_res);
842     }
843     if (!zh->m_record_type)
844     {
845         if (zh->records_processed < zh->m_file_verbose_limit)
846             logf (LOG_LOG, "? %s", fname);
847         return 0;
848     }
849     /* determine match criteria */
850     if (!zh->m_record_id)
851     {
852         sprintf (ext_res, "%srecordId.%s", gprefix, ext);
853         zh->m_record_id = res_get (zh->res, ext_res);
854     }
855
856     if (sysno && deleteFlag)
857         fd = -1;
858     else
859     {
860         char full_rep[1024];
861
862         if (zh->path_reg && !yaz_is_abspath (fname))
863         {
864             strcpy (full_rep, zh->path_reg);
865             strcat (full_rep, "/");
866             strcat (full_rep, fname);
867         }
868         else
869             strcpy (full_rep, fname);
870         
871
872         if ((fd = open (full_rep, O_BINARY|O_RDONLY)) == -1)
873         {
874             logf (LOG_WARN|LOG_ERRNO, "open %s", full_rep);
875             zh->m_record_type = original_record_type;
876             return 0;
877         }
878     }
879     fi = file_read_start (fd);
880     do
881     {
882         file_begin (fi);
883         r = file_extract_record (zh, sysno, fname, deleteFlag, fi, 1);
884     } while (r && !sysno && fi->file_more);
885     file_read_stop (fi);
886     if (fd != -1)
887         close (fd);
888     zh->m_record_type = original_record_type;
889     return r;
890 }
891
892 /*
893   If sysno is provided, then it's used to identify the reocord.
894   If not, and match_criteria is provided, then sysno is guessed
895   If not, and a record is provided, then sysno is got from there
896   
897  */
898 int buffer_extract_record (ZebraHandle zh, 
899                            const char *buf, size_t buf_size,
900                            int delete_flag,
901                            int test_mode, 
902                            const char *recordType,
903                            SYSNO *sysno,
904                            const char *match_criteria,
905                            const char *fname,
906                            int force_update,
907                            int allow_update)
908 {
909     RecordAttr *recordAttr;
910     struct recExtractCtrl extractCtrl;
911     int i, r;
912     const char *matchStr = 0;
913     RecType recType = NULL;
914     char subType[1024];
915     void *clientData;
916     Record rec;
917     long recordOffset = 0;
918     struct zebra_fetch_control fc;
919     const char *pr_fname = fname;  /* filename to print .. */
920
921     if (!pr_fname)
922         pr_fname = "<no file>";  /* make it printable if file is omitted */
923
924     fc.fd = -1;
925     fc.record_int_buf = buf;
926     fc.record_int_len = buf_size;
927     fc.record_int_pos = 0;
928     fc.offset_end = 0;
929     fc.record_offset = 0;
930
931     extractCtrl.offset = 0;
932     extractCtrl.readf = zebra_record_int_read;
933     extractCtrl.seekf = zebra_record_int_seek;
934     extractCtrl.tellf = zebra_record_int_tell;
935     extractCtrl.endf = zebra_record_int_end;
936     extractCtrl.fh = &fc;
937
938     create_rec_keys_codec(&zh->reg->keys);
939
940     zh->reg->sortKeys.buf_used = 0;
941
942     if (zebraExplain_curDatabase (zh->reg->zei, zh->basenames[0]))
943     {
944         if (zebraExplain_newDatabase (zh->reg->zei, zh->basenames[0], 
945                                       zh->m_explain_database))
946             return 0;
947     }
948     
949     if (recordType && *recordType) {
950         logf (LOG_DEBUG, "Record type explicitly specified: %s", recordType);
951         recType = recType_byName (zh->reg->recTypes, recordType, subType,
952                                   &clientData);
953     } else {
954         if (!(zh->m_record_type)) {
955             logf (LOG_WARN, "No such record type defined");
956             return 0;
957         }
958         logf (LOG_DEBUG, "Get record type from rgroup: %s",zh->m_record_type);
959         recType = recType_byName (zh->reg->recTypes, zh->m_record_type, subType,
960                                   &clientData);
961         recordType = zh->m_record_type;
962     }
963     
964     if (!recType) {
965         logf (LOG_WARN, "No such record type: %s", zh->m_record_type);
966         return 0;
967     }
968     
969     extractCtrl.subType = subType;
970     extractCtrl.init = extract_init;
971     extractCtrl.tokenAdd = extract_token_add;
972     extractCtrl.schemaAdd = extract_schema_add;
973     extractCtrl.dh = zh->reg->dh;
974     extractCtrl.handle = zh;
975     extractCtrl.zebra_maps = zh->reg->zebra_maps;
976     extractCtrl.flagShowRecords = 0;
977     for (i = 0; i<256; i++)
978     {
979         if (zebra_maps_is_positioned(zh->reg->zebra_maps, i))
980             extractCtrl.seqno[i] = 1;
981         else
982             extractCtrl.seqno[i] = 0;
983     }
984
985     r = (*recType->extract)(clientData, &extractCtrl);
986
987     if (r == RECCTRL_EXTRACT_EOF)
988         return 0;
989     else if (r == RECCTRL_EXTRACT_ERROR_GENERIC)
990     {
991         /* error occured during extraction ... */
992         yaz_log (LOG_WARN, "extract error: generic");
993         return 0;
994     }
995     else if (r == RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER)
996     {
997         /* error occured during extraction ... */
998         yaz_log (LOG_WARN, "extract error: no such filter");
999         return 0;
1000     }
1001     if (zh->reg->keys.buf_used == 0)
1002     {
1003         /* the extraction process returned no information - the record
1004            is probably empty - unless flagShowRecords is in use */
1005         if (test_mode)
1006             return 1;
1007         logf (LOG_WARN, "No keys generated for record");
1008         logf (LOG_WARN, " The file is probably empty");
1009         return 1;
1010     }
1011     /* match criteria */
1012     matchStr = NULL;
1013
1014     if (! *sysno) {
1015         char *rinfo;
1016         if (match_criteria && *match_criteria) {
1017             matchStr = match_criteria;
1018         } else {
1019             if (zh->m_record_id && *zh->m_record_id) {
1020                 matchStr = fileMatchStr (zh, &zh->reg->keys, pr_fname, 
1021                                          zh->m_record_id);
1022                 if (!matchStr)
1023                 {
1024                     logf (LOG_WARN, "Bad match criteria (recordID)");
1025                     return 1;
1026                 }
1027             }
1028         }
1029         if (matchStr) {
1030             rinfo = dict_lookup (zh->reg->matchDict, matchStr);
1031             if (rinfo)
1032             {
1033                 assert(*rinfo == sizeof(*sysno));
1034                 memcpy (sysno, rinfo+1, sizeof(*sysno));
1035             }
1036         }
1037     }
1038
1039     if (! *sysno)
1040     {
1041         /* new record */
1042         if (delete_flag)
1043         {
1044             logf (LOG_LOG, "delete %s %s %ld", recordType,
1045                   pr_fname, (long) recordOffset);
1046             logf (LOG_WARN, "cannot delete record above (seems new)");
1047             return 1;
1048         }
1049         logf (LOG_LOG, "add %s %s %ld", recordType, pr_fname,
1050               (long) recordOffset);
1051         rec = rec_new (zh->reg->records);
1052
1053         *sysno = rec->sysno;
1054
1055         recordAttr = rec_init_attr (zh->reg->zei, rec);
1056
1057         if (matchStr)
1058         {
1059             dict_insert (zh->reg->matchDict, matchStr,
1060                          sizeof(*sysno), sysno);
1061         }
1062         extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
1063         extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
1064
1065         zh->records_inserted++;
1066     } 
1067     else
1068     {
1069         /* record already exists */
1070         struct recKeys delkeys;
1071         struct sortKeys sortKeys;
1072
1073         if (!allow_update) {
1074               logf (LOG_LOG, "skipped %s %s %ld", 
1075                     recordType, pr_fname, (long) recordOffset);
1076               logRecord(zh);
1077               return -1;
1078         }
1079
1080         rec = rec_get (zh->reg->records, *sysno);
1081         assert (rec);
1082         
1083         recordAttr = rec_init_attr (zh->reg->zei, rec);
1084         
1085         if (!force_update) {
1086             if (recordAttr->runNumber ==
1087                 zebraExplain_runNumberIncrement (zh->reg->zei, 0))
1088             {
1089                 logf (LOG_LOG, "skipped %s %s %ld", recordType,
1090                       pr_fname, (long) recordOffset);
1091                 extract_flushSortKeys (zh, *sysno, -1, &zh->reg->sortKeys);
1092                 rec_rm (&rec);
1093                 logRecord(zh);
1094                 return -1;
1095             }
1096         }
1097
1098         delkeys.buf_used = rec->size[recInfo_delKeys];
1099         delkeys.buf = rec->info[recInfo_delKeys];
1100
1101         sortKeys.buf_used = rec->size[recInfo_sortKeys];
1102         sortKeys.buf = rec->info[recInfo_sortKeys];
1103
1104         extract_flushSortKeys (zh, *sysno, 0, &sortKeys);
1105         extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
1106         if (delete_flag)
1107         {
1108             /* record going to be deleted */
1109             if (!delkeys.buf_used)
1110             {
1111                 logf (LOG_LOG, "delete %s %s %ld", recordType,
1112                       pr_fname, (long) recordOffset);
1113                 logf (LOG_WARN, "cannot delete file above, storeKeys false");
1114             }
1115             else
1116             {
1117                 logf (LOG_LOG, "delete %s %s %ld", recordType,
1118                       pr_fname, (long) recordOffset);
1119                 zh->records_deleted++;
1120                 if (matchStr)
1121                     dict_delete (zh->reg->matchDict, matchStr);
1122                 rec_del (zh->reg->records, &rec);
1123             }
1124             rec_rm (&rec);
1125             logRecord(zh);
1126             return 0;
1127         }
1128         else
1129         {
1130             /* record going to be updated */
1131             if (!delkeys.buf_used)
1132             {
1133                 logf (LOG_LOG, "update %s %s %ld", recordType,
1134                       pr_fname, (long) recordOffset);
1135                 logf (LOG_WARN, "cannot update file above, storeKeys false");
1136             }
1137             else
1138             {
1139                 logf (LOG_LOG, "update %s %s %ld", recordType,
1140                       pr_fname, (long) recordOffset);
1141                 extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
1142                 extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
1143                 zh->records_updated++;
1144             }
1145         }
1146     }
1147     /* update file type */
1148     xfree (rec->info[recInfo_fileType]);
1149     rec->info[recInfo_fileType] =
1150         rec_strdup (recordType, &rec->size[recInfo_fileType]);
1151
1152     /* update filename */
1153     xfree (rec->info[recInfo_filename]);
1154     rec->info[recInfo_filename] =
1155         rec_strdup (fname, &rec->size[recInfo_filename]);
1156
1157     /* update delete keys */
1158     xfree (rec->info[recInfo_delKeys]);
1159     if (zh->reg->keys.buf_used > 0 && zh->m_store_keys == 1)
1160     {
1161         rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
1162         rec->info[recInfo_delKeys] = zh->reg->keys.buf;
1163         zh->reg->keys.buf = NULL;
1164         zh->reg->keys.buf_max = 0;
1165     }
1166     else
1167     {
1168         rec->info[recInfo_delKeys] = NULL;
1169         rec->size[recInfo_delKeys] = 0;
1170     }
1171
1172     /* update sort keys */
1173     xfree (rec->info[recInfo_sortKeys]);
1174
1175     rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
1176     rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
1177     zh->reg->sortKeys.buf = NULL;
1178     zh->reg->sortKeys.buf_max = 0;
1179
1180     /* save file size of original record */
1181     zebraExplain_recordBytesIncrement (zh->reg->zei,
1182                                        - recordAttr->recordSize);
1183 #if 0
1184     recordAttr->recordSize = fi->file_moffset - recordOffset;
1185     if (!recordAttr->recordSize)
1186         recordAttr->recordSize = fi->file_max - recordOffset;
1187 #else
1188     recordAttr->recordSize = buf_size;
1189 #endif
1190     zebraExplain_recordBytesIncrement (zh->reg->zei,
1191                                        recordAttr->recordSize);
1192
1193     /* set run-number for this record */
1194     recordAttr->runNumber =
1195         zebraExplain_runNumberIncrement (zh->reg->zei, 0);
1196
1197     /* update store data */
1198     xfree (rec->info[recInfo_storeData]);
1199     if (zh->m_store_data)
1200     {
1201         rec->size[recInfo_storeData] = recordAttr->recordSize;
1202         rec->info[recInfo_storeData] = (char *)
1203             xmalloc (recordAttr->recordSize);
1204         memcpy (rec->info[recInfo_storeData], buf, recordAttr->recordSize);
1205     }
1206     else
1207     {
1208         rec->info[recInfo_storeData] = NULL;
1209         rec->size[recInfo_storeData] = 0;
1210     }
1211     /* update database name */
1212     xfree (rec->info[recInfo_databaseName]);
1213     rec->info[recInfo_databaseName] =
1214         rec_strdup (zh->basenames[0], &rec->size[recInfo_databaseName]); 
1215
1216     /* update offset */
1217     recordAttr->recordOffset = recordOffset;
1218     
1219     /* commit this record */
1220     rec_put (zh->reg->records, &rec);
1221     logRecord(zh);
1222     return 0;
1223 }
1224
1225 int explain_extract (void *handle, Record rec, data1_node *n)
1226 {
1227     ZebraHandle zh = (ZebraHandle) handle;
1228     struct recExtractCtrl extractCtrl;
1229     int i;
1230
1231     if (zebraExplain_curDatabase (zh->reg->zei,
1232                                   rec->info[recInfo_databaseName]))
1233     {
1234         abort();
1235         if (zebraExplain_newDatabase (zh->reg->zei,
1236                                       rec->info[recInfo_databaseName], 0))
1237             abort ();
1238     }
1239
1240     create_rec_keys_codec(&zh->reg->keys);
1241
1242     zh->reg->sortKeys.buf_used = 0;
1243     
1244     extractCtrl.init = extract_init;
1245     extractCtrl.tokenAdd = extract_token_add;
1246     extractCtrl.schemaAdd = extract_schema_add;
1247     extractCtrl.dh = zh->reg->dh;
1248     for (i = 0; i<256; i++)
1249         extractCtrl.seqno[i] = 0;
1250     extractCtrl.zebra_maps = zh->reg->zebra_maps;
1251     extractCtrl.flagShowRecords = 0;
1252     extractCtrl.handle = handle;
1253
1254     if (n)
1255         grs_extract_tree(&extractCtrl, n);
1256
1257     if (rec->size[recInfo_delKeys])
1258     {
1259         struct recKeys delkeys;
1260         struct sortKeys sortkeys;
1261
1262         delkeys.buf_used = rec->size[recInfo_delKeys];
1263         delkeys.buf = rec->info[recInfo_delKeys];
1264
1265         sortkeys.buf_used = rec->size[recInfo_sortKeys];
1266         sortkeys.buf = rec->info[recInfo_sortKeys];
1267
1268         extract_flushSortKeys (zh, rec->sysno, 0, &sortkeys);
1269         extract_flushRecordKeys (zh, rec->sysno, 0, &delkeys);
1270     }
1271     extract_flushRecordKeys (zh, rec->sysno, 1, &zh->reg->keys);
1272     extract_flushSortKeys (zh, rec->sysno, 1, &zh->reg->sortKeys);
1273
1274     xfree (rec->info[recInfo_delKeys]);
1275     rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
1276     rec->info[recInfo_delKeys] = zh->reg->keys.buf;
1277     zh->reg->keys.buf = NULL;
1278     zh->reg->keys.buf_max = 0;
1279
1280     xfree (rec->info[recInfo_sortKeys]);
1281     rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
1282     rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
1283     zh->reg->sortKeys.buf = NULL;
1284     zh->reg->sortKeys.buf_max = 0;
1285
1286     return 0;
1287 }
1288
1289 void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
1290                               int cmd, struct recKeys *reckeys)
1291 {
1292 #if IT_KEY_NEW
1293     void *decode_handle = iscz1_start();
1294 #else
1295     int seqno = 0;
1296 #if SU_SCHEME
1297 #else
1298     unsigned char attrSet = (unsigned char) -1;
1299     unsigned short attrUse = (unsigned short) -1;
1300 #endif
1301 #endif
1302     int off = 0;
1303     int ch = 0;
1304     ZebraExplainInfo zei = zh->reg->zei;
1305
1306     if (!zh->reg->key_buf)
1307     {
1308         int mem= 1024*1024* atoi( res_get_def( zh->res, "memmax", "8"));
1309         if (mem <= 0)
1310         {
1311             logf(LOG_WARN, "Invalid memory setting, using default 8 MB");
1312             mem= 1024*1024*8;
1313         }
1314         /* FIXME: That "8" should be in a default settings include */
1315         /* not hard-coded here! -H */
1316         zh->reg->key_buf = (char**) xmalloc (mem);
1317         zh->reg->ptr_top = mem/sizeof(char*);
1318         zh->reg->ptr_i = 0;
1319         zh->reg->key_buf_used = 0;
1320         zh->reg->key_file_no = 0;
1321     }
1322     zebraExplain_recordCountIncrement (zei, cmd ? 1 : -1);
1323 #if IT_KEY_NEW
1324     while (off < reckeys->buf_used)
1325     {
1326         const char *src = reckeys->buf + off;
1327         struct it_key key;
1328         char *dst = (char*) &key;
1329         int attrSet, attrUse;
1330
1331         iscz1_decode(decode_handle, &dst, &src);
1332         assert(key.len < 4 && key.len > 2);
1333
1334         attrSet = (int) key.mem[0];
1335         attrUse = (int) key.mem[1]; /* sequence in mem[2] */
1336
1337         if (zh->reg->key_buf_used + 1024 > 
1338             (zh->reg->ptr_top -zh->reg->ptr_i)*sizeof(char*))
1339             extract_flushWriteKeys (zh,0);
1340         assert(zh->reg->ptr_i >= 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