Improved installation. Updated for inclusion of YAZ header files.
[idzebra-moved-to-github.git] / index / kinput.c
1 /*
2  * Copyright (C) 1994-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss, Heikki Levanto
5  *
6  * (log at the end)
7  *
8  * Bugs
9  *  - Allocates a lot of memory for the merge process, but never releases it.
10  *    Doesn't matter, as the program terminates soon after.  
11  
12  */
13  
14 #include <fcntl.h>
15 #ifdef WIN32
16 #include <io.h>
17 #else
18 #include <unistd.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <assert.h>
24
25 #include "index.h"
26
27 #define KEY_SIZE (1+sizeof(struct it_key))
28 #define INP_NAME_MAX 768
29 #define INP_BUF_START 60000
30 #define INP_BUF_ADD  400000
31
32 static int no_diffs   = 0;
33 static int no_updates = 0;
34 static int no_deletions = 0;
35 static int no_insertions = 0;
36 static int no_iterations = 0;
37
38 struct key_file {
39     int   no;            /* file no */
40     off_t offset;        /* file offset */
41     unsigned char *buf;  /* buffer block */
42     size_t buf_size;     /* number of read bytes in block */
43     size_t chunk;        /* number of bytes allocated */
44     size_t buf_ptr;      /* current position in buffer */
45     char *prev_name;     /* last word read */
46     int   sysno;         /* last sysno */
47     int   seqno;         /* last seqno */
48     off_t length;        /* length of file */
49                          /* handler invoked in each read */
50     void (*readHandler)(struct key_file *keyp, void *rinfo);
51     void *readInfo;
52 };
53
54 void getFnameTmp (char *fname, int no)
55 {
56     const char *pre;
57     
58     pre = res_get_def (common_resource, "keyTmpDir", ".");
59     sprintf (fname, "%s/key%d.tmp", pre, no);
60 }
61
62 void key_file_chunk_read (struct key_file *f)
63 {
64     int nr = 0, r = 0, fd;
65     char fname[1024];
66     getFnameTmp (fname, f->no);
67     fd = open (fname, O_BINARY|O_RDONLY);
68     if (fd == -1)
69     {
70         logf (LOG_FATAL|LOG_ERRNO, "cannot open %s", fname);
71         exit (1);
72     }
73     if (!f->length)
74     {
75         if ((f->length = lseek (fd, 0L, SEEK_END)) == (off_t) -1)
76         {
77             logf (LOG_FATAL|LOG_ERRNO, "cannot seek %s", fname);
78             exit (1);
79         }
80     }
81     if (lseek (fd, f->offset, SEEK_SET) == -1)
82     {
83         logf (LOG_FATAL|LOG_ERRNO, "cannot seek %s", fname);
84         exit (1);
85     }
86     while (f->chunk - nr > 0)
87     {
88         r = read (fd, f->buf + nr, f->chunk - nr);
89         if (r <= 0)
90             break;
91         nr += r;
92     }
93     if (r == -1)
94     {
95         logf (LOG_FATAL|LOG_ERRNO, "read of %s", fname);
96         exit (1);
97     }
98     f->buf_size = nr;
99     f->buf_ptr = 0;
100     if (f->readHandler)
101         (*f->readHandler)(f, f->readInfo);
102     close (fd);
103 }
104
105 struct key_file *key_file_init (int no, int chunk)
106 {
107     struct key_file *f;
108
109     f = (struct key_file *) xmalloc (sizeof(*f));
110     f->sysno = 0;
111     f->seqno = 0;
112     f->no = no;
113     f->chunk = chunk;
114     f->offset = 0;
115     f->length = 0;
116     f->readHandler = NULL;
117     f->buf = (unsigned char *) xmalloc (f->chunk);
118     f->prev_name = (char *) xmalloc (INP_NAME_MAX);
119     *f->prev_name = '\0';
120     key_file_chunk_read (f);
121     return f;
122 }
123
124 int key_file_getc (struct key_file *f)
125 {
126     if (f->buf_ptr < f->buf_size)
127         return f->buf[(f->buf_ptr)++];
128     if (f->buf_size < f->chunk)
129         return EOF;
130     f->offset += f->buf_size;
131     key_file_chunk_read (f);
132     if (f->buf_ptr < f->buf_size)
133         return f->buf[(f->buf_ptr)++];
134     else
135         return EOF;
136 }
137
138 int key_file_decode (struct key_file *f)
139 {
140     int c, d;
141
142     c = key_file_getc (f);
143     switch (c & 192) 
144     {
145     case 0:
146         d = c;
147         break;
148     case 64:
149         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
150         break;
151     case 128:
152         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
153         d = (d << 8) + (key_file_getc (f) & 0xff);
154         break;
155     case 192:
156         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
157         d = (d << 8) + (key_file_getc (f) & 0xff);
158         d = (d << 8) + (key_file_getc (f) & 0xff);
159         break;
160     }
161     return d;
162 }
163
164 int key_file_read (struct key_file *f, char *key)
165 {
166     int i, d, c;
167     struct it_key itkey;
168
169     c = key_file_getc (f);
170     if (c == 0)
171     {
172         strcpy (key, f->prev_name);
173         i = 1+strlen (key);
174     }
175     else if (c == EOF)
176         return 0;
177     else
178     {
179         i = 0;
180         key[i++] = c;
181         while ((key[i++] = key_file_getc (f)))
182             ;
183         strcpy (f->prev_name, key);
184         f->sysno = 0;
185     }
186     d = key_file_decode (f);
187     key[i++] = d & 1;
188     d = d >> 1;
189     itkey.sysno = d + f->sysno;
190     if (d) 
191     {
192         f->sysno = itkey.sysno;
193         f->seqno = 0;
194     }
195     d = key_file_decode (f);
196     itkey.seqno = d + f->seqno;
197     f->seqno = itkey.seqno;
198     memcpy (key + i, &itkey, sizeof(struct it_key));
199     return i + sizeof (struct it_key);
200 }
201
202 struct heap_info {
203     struct {
204         struct key_file **file;
205         char   **buf;
206     } info;
207     int    heapnum;
208     int    *ptr;
209     int    (*cmp)(const void *p1, const void *p2);
210     Dict dict;
211     ISAMS isams;
212 #if ZMBOL
213     ISAM isam;
214     ISAMC isamc;
215     ISAMD isamd;
216 #endif
217 };
218
219 struct heap_info *key_heap_init (int nkeys,
220                                  int (*cmp)(const void *p1, const void *p2))
221 {
222     struct heap_info *hi;
223     int i;
224
225     hi = (struct heap_info *) xmalloc (sizeof(*hi));
226     hi->info.file = (struct key_file **)
227         xmalloc (sizeof(*hi->info.file) * (1+nkeys));
228     hi->info.buf = (char **) xmalloc (sizeof(*hi->info.buf) * (1+nkeys));
229     hi->heapnum = 0;
230     hi->ptr = (int *) xmalloc (sizeof(*hi->ptr) * (1+nkeys));
231     hi->cmp = cmp;
232     for (i = 0; i<= nkeys; i++)
233     {
234         hi->ptr[i] = i;
235         hi->info.buf[i] = (char *) xmalloc (INP_NAME_MAX);
236     }
237     return hi;
238 }
239
240 static void key_heap_swap (struct heap_info *hi, int i1, int i2)
241 {
242     int swap;
243
244     swap = hi->ptr[i1];
245     hi->ptr[i1] = hi->ptr[i2];
246     hi->ptr[i2] = swap;
247 }
248
249
250 static void key_heap_delete (struct heap_info *hi)
251 {
252     int cur = 1, child = 2;
253
254     assert (hi->heapnum > 0);
255
256     key_heap_swap (hi, 1, hi->heapnum);
257     hi->heapnum--;
258     while (child <= hi->heapnum) {
259         if (child < hi->heapnum &&
260             (*hi->cmp)(&hi->info.buf[hi->ptr[child]],
261                        &hi->info.buf[hi->ptr[child+1]]) > 0)
262             child++;
263         if ((*hi->cmp)(&hi->info.buf[hi->ptr[cur]],
264                        &hi->info.buf[hi->ptr[child]]) > 0)
265         {            
266             key_heap_swap (hi, cur, child);
267             cur = child;
268             child = 2*cur;
269         }
270         else
271             break;
272     }
273 }
274
275 static void key_heap_insert (struct heap_info *hi, const char *buf, int nbytes,
276                              struct key_file *kf)
277 {
278     int cur, parent;
279
280     cur = ++(hi->heapnum);
281     memcpy (hi->info.buf[hi->ptr[cur]], buf, nbytes);
282     hi->info.file[hi->ptr[cur]] = kf;
283
284     parent = cur/2;
285     while (parent && (*hi->cmp)(&hi->info.buf[hi->ptr[parent]],
286                                 &hi->info.buf[hi->ptr[cur]]) > 0)
287     {
288         key_heap_swap (hi, cur, parent);
289         cur = parent;
290         parent = cur/2;
291     }
292 }
293
294 static int heap_read_one (struct heap_info *hi, char *name, char *key)
295 {
296     int n, r;
297     char rbuf[INP_NAME_MAX];
298     struct key_file *kf;
299
300     if (!hi->heapnum)
301         return 0;
302     n = hi->ptr[1];
303     strcpy (name, hi->info.buf[n]);
304     kf = hi->info.file[n];
305     r = strlen(name);
306     memcpy (key, hi->info.buf[n] + r+1, KEY_SIZE);
307     key_heap_delete (hi);
308     if ((r = key_file_read (kf, rbuf)))
309         key_heap_insert (hi, rbuf, r, kf);
310     no_iterations++;
311     return 1;
312 }
313
314 struct heap_cread_info {
315     char prev_name[INP_NAME_MAX];
316     char cur_name[INP_NAME_MAX];
317     char *key;
318     struct heap_info *hi;
319     int mode;
320     int more;
321 };
322       
323 int heap_cread_item (void *vp, char **dst, int *insertMode)
324 {
325     struct heap_cread_info *p = (struct heap_cread_info *) vp;
326     struct heap_info *hi = p->hi;
327
328     if (p->mode == 1)
329     {
330         *insertMode = p->key[0];
331         memcpy (*dst, p->key+1, sizeof(struct it_key));
332         (*dst) += sizeof(struct it_key);
333         p->mode = 2;
334         return 1;
335     }
336     strcpy (p->prev_name, p->cur_name);
337     if (!(p->more = heap_read_one (hi, p->cur_name, p->key)))
338         return 0;
339     if (*p->cur_name && strcmp (p->cur_name, p->prev_name))
340     {
341         p->mode = 1;
342         return 0;
343     }
344     *insertMode = p->key[0];
345     memcpy (*dst, p->key+1, sizeof(struct it_key));
346     (*dst) += sizeof(struct it_key);
347     return 1;
348 }
349
350 #if ZMBOL
351 int heap_inpc (struct heap_info *hi)
352 {
353     struct heap_cread_info hci;
354     ISAMC_I isamc_i = (ISAMC_I) xmalloc (sizeof(*isamc_i));
355
356     hci.key = (char *) xmalloc (KEY_SIZE);
357     hci.mode = 1;
358     hci.hi = hi;
359     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
360
361     isamc_i->clientData = &hci;
362     isamc_i->read_item = heap_cread_item;
363
364     while (hci.more)
365     {
366         char this_name[INP_NAME_MAX];
367         ISAMC_P isamc_p, isamc_p2;
368         char *dict_info;
369
370         strcpy (this_name, hci.cur_name);
371         assert (hci.cur_name[1]);
372         no_diffs++;
373         if ((dict_info = dict_lookup (hi->dict, hci.cur_name)))
374         {
375             memcpy (&isamc_p, dict_info+1, sizeof(ISAMC_P));
376             isamc_p2 = isc_merge (hi->isamc, isamc_p, isamc_i);
377             if (!isamc_p2)
378             {
379                 no_deletions++;
380                 if (!dict_delete (hi->dict, this_name))
381                     abort();
382             }
383             else 
384             {
385                 no_updates++;
386                 if (isamc_p2 != isamc_p)
387                     dict_insert (hi->dict, this_name,
388                                  sizeof(ISAMC_P), &isamc_p2);
389             }
390         } 
391         else
392         {
393             isamc_p = isc_merge (hi->isamc, 0, isamc_i);
394             no_insertions++;
395             dict_insert (hi->dict, this_name, sizeof(ISAMC_P), &isamc_p);
396         }
397     }
398     xfree (isamc_i);
399     return 0;
400
401
402 int heap_inpd (struct heap_info *hi)
403 {
404     struct heap_cread_info hci;
405     ISAMD_I isamd_i = (ISAMD_I) xmalloc (sizeof(*isamd_i));
406
407     hci.key = (char *) xmalloc (KEY_SIZE);
408     hci.mode = 1;
409     hci.hi = hi;
410     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
411
412     isamd_i->clientData = &hci;
413     isamd_i->read_item = heap_cread_item;
414
415     while (hci.more)
416     {
417         char this_name[INP_NAME_MAX];
418         ISAMD_P isamd_p, isamd_p2;
419         char *dict_info;
420
421         strcpy (this_name, hci.cur_name);
422         assert (hci.cur_name[1]);
423         no_diffs++;
424         if ((dict_info = dict_lookup (hi->dict, hci.cur_name)))
425         {
426             memcpy (&isamd_p, dict_info+1, sizeof(ISAMD_P));
427             isamd_p2 = isamd_append (hi->isamd, isamd_p, isamd_i);
428             if (!isamd_p2)
429             {
430                 no_deletions++;
431                 if (!dict_delete (hi->dict, this_name))
432                     abort();
433             }
434             else 
435             {
436                 no_updates++;
437                 if (isamd_p2 != isamd_p)
438                     dict_insert (hi->dict, this_name,
439                                  sizeof(ISAMD_P), &isamd_p2);
440             }
441         } 
442         else
443         {
444             isamd_p = isamd_append (hi->isamd, 0, isamd_i);
445             no_insertions++;
446             dict_insert (hi->dict, this_name, sizeof(ISAMD_P), &isamd_p);
447         }
448     }
449     xfree (isamd_i);
450     return 0;
451
452
453 int heap_inp (struct heap_info *hi)
454 {
455     char *info;
456     char next_name[INP_NAME_MAX];
457     char cur_name[INP_NAME_MAX];
458     int key_buf_size = INP_BUF_START;
459     int key_buf_ptr;
460     char *next_key;
461     char *key_buf;
462     int more;
463     
464     next_key = (char *) xmalloc (KEY_SIZE);
465     key_buf = (char *) xmalloc (key_buf_size);
466     more = heap_read_one (hi, cur_name, key_buf);
467     while (more)                   /* EOF ? */
468     {
469         int nmemb;
470         key_buf_ptr = KEY_SIZE;
471         while (1)
472         {
473             if (!(more = heap_read_one (hi, next_name, next_key)))
474                 break;
475             if (*next_name && strcmp (next_name, cur_name))
476                 break;
477             memcpy (key_buf + key_buf_ptr, next_key, KEY_SIZE);
478             key_buf_ptr += KEY_SIZE;
479             if (key_buf_ptr+(int) KEY_SIZE >= key_buf_size)
480             {
481                 char *new_key_buf;
482                 new_key_buf = (char *) xmalloc (key_buf_size + INP_BUF_ADD);
483                 memcpy (new_key_buf, key_buf, key_buf_size);
484                 key_buf_size += INP_BUF_ADD;
485                 xfree (key_buf);
486                 key_buf = new_key_buf;
487             }
488         }
489         no_diffs++;
490         nmemb = key_buf_ptr / KEY_SIZE;
491         assert (nmemb * (int) KEY_SIZE == key_buf_ptr);
492         if ((info = dict_lookup (hi->dict, cur_name)))
493         {
494             ISAM_P isam_p, isam_p2;
495             memcpy (&isam_p, info+1, sizeof(ISAM_P));
496             isam_p2 = is_merge (hi->isam, isam_p, nmemb, key_buf);
497             if (!isam_p2)
498             {
499                 no_deletions++;
500                 if (!dict_delete (hi->dict, cur_name))
501                     abort ();
502             }
503             else 
504             {
505                 no_updates++;
506                 if (isam_p2 != isam_p)
507                     dict_insert (hi->dict, cur_name, sizeof(ISAM_P), &isam_p2);
508             }
509         }
510         else
511         {
512             ISAM_P isam_p;
513             no_insertions++;
514             isam_p = is_merge (hi->isam, 0, nmemb, key_buf);
515             dict_insert (hi->dict, cur_name, sizeof(ISAM_P), &isam_p);
516         }
517         memcpy (key_buf, next_key, KEY_SIZE);
518         strcpy (cur_name, next_name);
519     }
520     return 0;
521 }
522
523 #endif
524
525 int heap_inps (struct heap_info *hi)
526 {
527     struct heap_cread_info hci;
528     ISAMS_I isams_i = (ISAMS_I) xmalloc (sizeof(*isams_i));
529
530     hci.key = (char *) xmalloc (KEY_SIZE);
531     hci.mode = 1;
532     hci.hi = hi;
533     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
534
535     isams_i->clientData = &hci;
536     isams_i->read_item = heap_cread_item;
537
538     while (hci.more)
539     {
540         char this_name[INP_NAME_MAX];
541         ISAMS_P isams_p;
542         char *dict_info;
543
544         strcpy (this_name, hci.cur_name);
545         assert (hci.cur_name[1]);
546         no_diffs++;
547         if (!(dict_info = dict_lookup (hi->dict, hci.cur_name)))
548         {
549             isams_p = isams_merge (hi->isams, isams_i);
550             no_insertions++;
551             dict_insert (hi->dict, this_name, sizeof(ISAMS_P), &isams_p);
552         }
553         else
554             abort();
555     }
556     xfree (isams_i);
557     return 0;
558
559
560 struct progressInfo {
561     time_t   startTime;
562     time_t   lastTime;
563     off_t    totalBytes;
564     off_t    totalOffset;
565 };
566
567 void progressFunc (struct key_file *keyp, void *info)
568 {
569     struct progressInfo *p = (struct progressInfo *) info;
570     time_t now, remaining;
571
572     if (keyp->buf_size <= 0 || p->totalBytes <= 0)
573         return ;
574     time (&now);
575
576     if (now >= p->lastTime+10)
577     {
578         p->lastTime = now;
579         remaining = (time_t) ((now - p->startTime)*
580             ((double) p->totalBytes/p->totalOffset - 1.0));
581         if (remaining <= 130)
582             logf (LOG_LOG, "Merge %2.1f%% completed; %ld seconds remaining",
583                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining);
584         else
585             logf (LOG_LOG, "Merge %2.1f%% completed; %ld minutes remaining",
586                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining/60);
587     }
588     p->totalOffset += keyp->buf_size;
589 }
590
591 #ifndef R_OK
592 #define R_OK 4
593 #endif
594
595 void key_input (BFiles bfs, int nkeys, int cache)
596                 
597 {
598     Dict dict;
599     ISAMS isams = NULL;
600 #if ZMBOL
601     ISAM isam = NULL;
602     ISAMC isamc = NULL;
603     ISAMD isamd = NULL;
604 #endif
605     struct key_file **kf;
606     char rbuf[1024];
607     int i, r;
608     struct heap_info *hi;
609     struct progressInfo progressInfo;
610
611     if (nkeys < 0)
612     {
613         char fname[1024];
614         nkeys = 0;
615         while (1)
616         {
617             getFnameTmp (fname, nkeys+1);
618             if (access (fname, R_OK) == -1)
619                 break;
620             nkeys++;
621         }
622         if (!nkeys)
623             return ;
624     }
625     dict = dict_open (bfs, FNAME_DICT, cache, 1, 0);
626     if (!dict)
627     {
628         logf (LOG_FATAL, "dict_open fail");
629         exit (1);
630     }
631     if (res_get_match (common_resource, "isam", "s", ISAM_DEFAULT))
632     {
633         struct ISAMS_M_s isams_m;
634         isams = isams_open (bfs, FNAME_ISAMS, 1,
635                             key_isams_m (common_resource, &isams_m));
636         if (!isams)
637         {
638             logf (LOG_FATAL, "isams_open fail");
639             exit (1);
640         }
641         logf (LOG_LOG, "isams opened");
642     }
643 #if ZMBOL
644     else if (res_get_match (common_resource, "isam", "i", ISAM_DEFAULT))
645     {
646         isam = is_open (bfs, FNAME_ISAM, key_compare, 1,
647                         sizeof(struct it_key), common_resource);
648         if (!isam)
649         {
650             logf (LOG_FATAL, "is_open fail");
651             exit (1);
652         }
653     }
654     else if (res_get_match (common_resource, "isam", "d", ISAM_DEFAULT))
655     {
656         struct ISAMD_M_s isamd_m;
657         isamd = isamd_open (bfs, FNAME_ISAMD, 1,
658                           key_isamd_m (common_resource,&isamd_m));
659         if (!isamd)
660         {
661             logf (LOG_FATAL, "isamd_open fail");
662             exit (1);
663         }
664     }
665     else if (res_get_match (common_resource, "isam", "c", ISAM_DEFAULT))
666     {
667         struct ISAMC_M_s isamc_m;
668         isamc = isc_open (bfs, FNAME_ISAMC, 1,
669                           key_isamc_m (common_resource, &isamc_m));
670         if (!isamc)
671         {
672             logf (LOG_FATAL, "isc_open fail");
673             exit (1);
674         }
675     }
676 #endif
677     kf = (struct key_file **) xmalloc ((1+nkeys) * sizeof(*kf));
678     progressInfo.totalBytes = 0;
679     progressInfo.totalOffset = 0;
680     time (&progressInfo.startTime);
681     time (&progressInfo.lastTime);
682     for (i = 1; i<=nkeys; i++)
683     {
684         kf[i] = key_file_init (i, 32768);
685         kf[i]->readHandler = progressFunc;
686         kf[i]->readInfo = &progressInfo;
687         progressInfo.totalBytes += kf[i]->length;
688         progressInfo.totalOffset += kf[i]->buf_size;
689     }
690     hi = key_heap_init (nkeys, key_qsort_compare);
691     hi->dict = dict;
692     hi->isams = isams;
693 #if ZMBOL
694     hi->isam = isam;
695     hi->isamc = isamc;
696     hi->isamd = isamd;
697 #endif
698     
699     for (i = 1; i<=nkeys; i++)
700         if ((r = key_file_read (kf[i], rbuf)))
701             key_heap_insert (hi, rbuf, r, kf[i]);
702     if (isams)
703         heap_inps (hi);
704 #if ZMBOL
705     else if (isamc)
706         heap_inpc (hi);
707     else if (isam)
708         heap_inp (hi);
709     else if (isamd)
710         heap_inpd (hi);
711 #endif
712         
713     dict_close (dict);
714     if (isams)
715         isams_close (isams);
716 #if ZMBOL
717     if (isam)
718         is_close (isam);
719     if (isamc)
720         isc_close (isamc);
721     if (isamd)
722         isamd_close (isamd);
723 #endif
724    
725     for (i = 1; i<=nkeys; i++)
726     {
727         getFnameTmp (rbuf, i);
728         unlink (rbuf);
729     }
730     logf (LOG_LOG, "Iterations . . .%7d", no_iterations);
731     logf (LOG_LOG, "Distinct words .%7d", no_diffs);
732     logf (LOG_LOG, "Updates. . . . .%7d", no_updates);
733     logf (LOG_LOG, "Deletions. . . .%7d", no_deletions);
734     logf (LOG_LOG, "Insertions . . .%7d", no_insertions);
735
736     /* xmalloc_trav("unfreed"); while hunting leaks */     
737 }
738
739
740
741 /*
742  * $Log: kinput.c,v $
743  * Revision 1.41  1999-11-30 13:48:03  adam
744  * Improved installation. Updated for inclusion of YAZ header files.
745  *
746  * Revision 1.40  1999/09/08 12:12:39  adam
747  * Removed log message.
748  *
749  * Revision 1.39  1999/08/18 10:39:20  heikki
750  * Added a comment on memory leaks
751  *
752  * Revision 1.38  1999/08/18 08:38:04  heikki
753  * Memory leak hunting
754  *
755  * Revision 1.37  1999/07/14 13:21:34  heikki
756  * Added isam-d files. Compiles (almost) clean. Doesn't work at all
757  *
758  * Revision 1.36  1999/07/14 10:59:26  adam
759  * Changed functions isc_getmethod, isams_getmethod.
760  * Improved fatal error handling (such as missing EXPLAIN schema).
761  *
762  * Revision 1.35  1999/06/30 15:07:23  heikki
763  * Adding isamh stuff
764  *
765  * Revision 1.34  1999/05/26 07:49:13  adam
766  * C++ compilation.
767  *
768  * Revision 1.33  1999/05/15 14:36:38  adam
769  * Updated dictionary. Implemented "compression" of dictionary.
770  *
771  * Revision 1.32  1999/05/12 13:08:06  adam
772  * First version of ISAMS.
773  *
774  * Revision 1.31  1999/02/02 14:50:56  adam
775  * Updated WIN32 code specific sections. Changed header.
776  *
777  * Revision 1.30  1998/10/28 10:53:57  adam
778  * Added type cast to prevent warning.
779  *
780  * Revision 1.29  1998/06/11 15:41:39  adam
781  * Minor changes.
782  *
783  * Revision 1.28  1998/03/05 08:45:12  adam
784  * New result set model and modular ranking system. Moved towards
785  * descent server API. System information stored as "SGML" records.
786  *
787  * Revision 1.27  1998/02/17 10:32:52  adam
788  * Fixed bug: binary files weren't opened with flag b on NT.
789  *
790  * Revision 1.26  1998/01/29 13:39:13  adam
791  * Compress ISAM is default.
792  *
793  * Revision 1.25  1997/09/17 12:19:14  adam
794  * Zebra version corresponds to YAZ version 1.4.
795  * Changed Zebra server so that it doesn't depend on global common_resource.
796  *
797  * Revision 1.24  1997/09/09 13:38:07  adam
798  * Partial port to WIN95/NT.
799  *
800  * Revision 1.23  1997/09/04 13:57:39  adam
801  * Added O_BINARY for open calls.
802  *
803  * Revision 1.22  1997/02/12 20:39:45  adam
804  * Implemented options -f <n> that limits the log to the first <n>
805  * records.
806  * Changed some log messages also.
807  *
808  * Revision 1.21  1996/11/08 11:10:23  adam
809  * Buffers used during file match got bigger.
810  * Compressed ISAM support everywhere.
811  * Bug fixes regarding masking characters in queries.
812  * Redesigned Regexp-2 queries.
813  *
814  * Revision 1.20  1996/11/01 08:58:41  adam
815  * Interface to isamc system now includes update and delete.
816  *
817  * Revision 1.19  1996/10/29 14:09:46  adam
818  * Use of cisam system - enabled if setting isamc is 1.
819  *
820  * Revision 1.18  1996/06/04 10:18:59  adam
821  * Minor changes - removed include of ctype.h.
822  *
823  * Revision 1.17  1996/05/14  15:47:07  adam
824  * Cleanup of various buffer size entities.
825  *
826  * Revision 1.16  1996/04/09  10:05:20  adam
827  * Bug fix: prev_name buffer possibly too small; allocated in key_file_init.
828  *
829  * Revision 1.15  1996/03/21  14:50:09  adam
830  * File update uses modify-time instead of change-time.
831  *
832  * Revision 1.14  1996/02/07  14:06:37  adam
833  * Better progress report during register merge.
834  * New command: clean - removes temporary shadow files.
835  *
836  * Revision 1.13  1996/02/05  12:30:00  adam
837  * Logging reduced a bit.
838  * The remaining running time is estimated during register merge.
839  *
840  * Revision 1.12  1995/12/06  17:49:19  adam
841  * Uses dict_delete now.
842  *
843  * Revision 1.11  1995/12/06  16:06:43  adam
844  * Better diagnostics. Work on 'real' dictionary deletion.
845  *
846  * Revision 1.10  1995/12/06  12:41:22  adam
847  * New command 'stat' for the index program.
848  * Filenames can be read from stdin by specifying '-'.
849  * Bug fix/enhancement of the transformation from terms to regular
850  * expressons in the search engine.
851  *
852  * Revision 1.9  1995/10/10  12:24:39  adam
853  * Temporary sort files are compressed.
854  *
855  * Revision 1.8  1995/10/04  16:57:19  adam
856  * Key input and merge sort in one pass.
857  *
858  * Revision 1.7  1995/10/02  15:18:52  adam
859  * New member in recRetrieveCtrl: diagnostic.
860  *
861  * Revision 1.6  1995/09/29  15:51:56  adam
862  * First work on multi-way read.
863  *
864  * Revision 1.5  1995/09/29  14:01:43  adam
865  * Bug fixes.
866  *
867  * Revision 1.4  1995/09/28  14:22:57  adam
868  * Sort uses smaller temporary files.
869  *
870  * Revision 1.3  1995/09/06  16:11:17  adam
871  * Option: only one word key per file.
872  *
873  * Revision 1.2  1995/09/04  12:33:42  adam
874  * Various cleanup. YAZ util used instead.
875  *
876  * Revision 1.1  1995/09/04  09:10:37  adam
877  * More work on index add/del/update.
878  * Merge sort implemented.
879  * Initial work on z39 server.
880  *
881  */
882