Fixed bug.
[idzebra-moved-to-github.git] / index / extract.c
1 /*
2  * Copyright (C) 1994-1995, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: extract.c,v $
7  * Revision 1.18  1995-10-04 09:37:08  quinn
8  * Fixed bug.
9  *
10  * Revision 1.17  1995/10/03  14:28:57  adam
11  * Buffered read in extract works.
12  *
13  * Revision 1.16  1995/10/03  14:28:45  adam
14  * Work on more effecient read handler in extract.
15  *
16  * Revision 1.15  1995/10/02  15:42:53  adam
17  * Extract uses file descriptors instead of FILE pointers.
18  *
19  * Revision 1.14  1995/10/02  15:29:13  adam
20  * More logging in file_extract.
21  *
22  * Revision 1.13  1995/09/29  14:01:39  adam
23  * Bug fixes.
24  *
25  * Revision 1.12  1995/09/28  14:22:56  adam
26  * Sort uses smaller temporary files.
27  *
28  * Revision 1.11  1995/09/28  12:10:31  adam
29  * Bug fixes. Field prefix used in queries.
30  *
31  * Revision 1.10  1995/09/28  09:19:41  adam
32  * xfree/xmalloc used everywhere.
33  * Extract/retrieve method seems to work for text records.
34  *
35  * Revision 1.9  1995/09/27  12:22:28  adam
36  * More work on extract in record control.
37  * Field name is not in isam keys but in prefix in dictionary words.
38  *
39  * Revision 1.8  1995/09/14  07:48:22  adam
40  * Record control management.
41  *
42  * Revision 1.7  1995/09/11  13:09:32  adam
43  * More work on relevance feedback.
44  *
45  * Revision 1.6  1995/09/08  14:52:27  adam
46  * Minor changes. Dictionary is lower case now.
47  *
48  * Revision 1.5  1995/09/06  16:11:16  adam
49  * Option: only one word key per file.
50  *
51  * Revision 1.4  1995/09/05  15:28:39  adam
52  * More work on search engine.
53  *
54  * Revision 1.3  1995/09/04  12:33:41  adam
55  * Various cleanup. YAZ util used instead.
56  *
57  * Revision 1.2  1995/09/04  09:10:34  adam
58  * More work on index add/del/update.
59  * Merge sort implemented.
60  * Initial work on z39 server.
61  *
62  * Revision 1.1  1995/09/01  14:06:35  adam
63  * Split of work into more files.
64  *
65  */
66 #include <stdio.h>
67 #include <assert.h>
68 #include <unistd.h>
69 #include <fcntl.h>
70 #include <ctype.h>
71
72 #include <alexutil.h>
73 #include <recctrl.h>
74 #include "index.h"
75
76 static Dict file_idx;
77 static SYSNO sysno_next;
78 static int sys_idx_fd = -1;
79
80 static int key_cmd;
81 static int key_sysno;
82 static char **key_buf;
83 static size_t ptr_top;
84 static size_t ptr_i;
85 static size_t kused;
86 static int key_file_no;
87
88 void key_open (int mem)
89 {
90     void *file_key;
91
92     if (mem < 50000)
93         mem = 50000;
94     key_buf = xmalloc (mem);
95     ptr_top = mem/sizeof(char*);
96     ptr_i = 0;
97     kused = 0;
98     key_file_no = 0;
99
100     if (!(file_idx = dict_open (FNAME_FILE_DICT, 40, 1)))
101     {
102         logf (LOG_FATAL, "dict_open fail of %s", "fileidx");
103         exit (1);
104     }
105     file_key = dict_lookup (file_idx, ".");
106     if (file_key)
107         memcpy (&sysno_next, (char*)file_key+1, sizeof(sysno_next));
108     else
109         sysno_next = 1;
110     if ((sys_idx_fd = open (FNAME_SYS_IDX, O_RDWR|O_CREAT, 0666)) == -1)
111     {
112         logf (LOG_FATAL|LOG_ERRNO, "open %s", FNAME_SYS_IDX);
113         exit (1);
114     }
115 }
116     
117 void key_flush (void)
118 {
119     FILE *outf;
120     char out_fname[200];
121     char *prevcp, *cp;
122     
123     if (ptr_i <= 0)
124         return;
125
126     key_file_no++;
127     logf (LOG_LOG, "sorting section %d", key_file_no);
128     qsort (key_buf + ptr_top-ptr_i, ptr_i, sizeof(char*), key_qsort_compare);
129     sprintf (out_fname, TEMP_FNAME, key_file_no);
130
131     if (!(outf = fopen (out_fname, "w")))
132     {
133         logf (LOG_FATAL|LOG_ERRNO, "fopen (4) %s", out_fname);
134         exit (1);
135     }
136     logf (LOG_LOG, "writing section %d", key_file_no);
137     prevcp = cp = key_buf[ptr_top-ptr_i];
138     
139     if (fwrite (cp, strlen (cp)+2+sizeof(struct it_key), 1, outf) != 1)
140     {
141         logf (LOG_FATAL|LOG_ERRNO, "fwrite %s", out_fname);
142         exit (1);
143     }
144     while (--ptr_i > 0)
145     {
146         cp = key_buf[ptr_top-ptr_i];
147         if (strcmp (cp, prevcp))
148         {
149             if (fwrite (cp, strlen (cp)+2+sizeof(struct it_key), 1,
150                         outf) != 1)
151             {
152                 logf (LOG_FATAL|LOG_ERRNO, "fwrite %s", out_fname);
153                 exit (1);
154             }
155             prevcp = cp;
156         }
157         else
158         {
159             cp = strlen (cp) + cp;
160             if (fwrite (cp, 2+sizeof(struct it_key), 1, outf) != 1)
161             {
162                 logf (LOG_FATAL|LOG_ERRNO, "fwrite %s", out_fname);
163                 exit (1);
164             }
165         }
166     }
167     if (fclose (outf))
168     {
169         logf (LOG_FATAL|LOG_ERRNO, "fclose %s", out_fname);
170         exit (1);
171     }
172     logf (LOG_LOG, "finished section %d", key_file_no);
173     ptr_i = 0;
174     kused = 0;
175 }
176
177 int key_close (void)
178 {
179     key_flush ();
180     xfree (key_buf);
181     close (sys_idx_fd);
182     dict_insert (file_idx, ".", sizeof(sysno_next), &sysno_next);
183     dict_close (file_idx);
184     return key_file_no;
185 }
186
187 static void wordInit (RecWord *p)
188 {
189     p->attrSet = 1;
190     p->attrUse = 1016;
191     p->which = Word_String;
192 }
193
194 static void wordAdd (const RecWord *p)
195 {
196     struct it_key key;
197     size_t i;
198
199     if (kused + 1024 > (ptr_top-ptr_i)*sizeof(char*))
200         key_flush ();
201     ++ptr_i;
202     key_buf[ptr_top-ptr_i] = (char*)key_buf + kused;
203     kused += index_word_prefix ((char*)key_buf + kused,
204                                 p->attrSet, p->attrUse);
205     switch (p->which)
206     {
207     case Word_String:
208         for (i = 0; p->u.string[i]; i++)
209             ((char*)key_buf) [kused++] = index_char_cvt (p->u.string[i]);
210         ((char*)key_buf) [kused++] = '\0';
211         break;
212     default:
213         return ;
214     }
215     ((char*) key_buf)[kused++] = ((key_cmd == 'a') ? 1 : 0);
216     key.sysno = key_sysno;
217     key.seqno = p->seqno;
218     memcpy ((char*)key_buf + kused, &key, sizeof(key));
219     kused += sizeof(key);
220 }
221
222 #define FILE_READ_BUF 1
223 #if FILE_READ_BUF
224 static char *file_buf;
225 static int file_offset;
226 static int file_bufsize;
227
228 static void file_read_start (int fd)
229 {
230     file_offset = 0;
231     file_buf = xmalloc (4096);
232     file_bufsize = read (fd, file_buf, 4096);
233 }
234
235 static void file_read_stop (int fd)
236 {
237     xfree (file_buf);
238 }
239
240 static int file_read (int fd, char *buf, size_t count)
241 {
242     int l = file_bufsize - file_offset;
243
244     if (count > l)
245     {
246         int r;
247         if (l > 0)
248             memcpy (buf, file_buf + file_offset, l);
249         count = count-l;
250         if (count > file_bufsize)
251         {
252             if ((r = read (fd, buf + l, count)) == -1)
253             {
254                 logf (LOG_FATAL|LOG_ERRNO, "read");
255                 exit (1);
256             }
257             file_bufsize = 0;
258             file_offset = 0;
259             return r;
260         }
261         file_bufsize = r = read (fd, file_buf, 4096);
262         if (r == -1)
263         {
264             logf (LOG_FATAL|LOG_ERRNO, "read");
265             exit (1);
266         }
267         else if (r <= count)
268         {
269             file_offset = r;
270             memcpy (buf + l, file_buf, r);
271             return l + r;
272         }
273         else
274         {
275             file_offset = count;
276             memcpy (buf + l, file_buf, count - l);
277             return count;
278         }
279     }
280     memcpy (buf, file_buf + file_offset, count);
281     file_offset += count;
282     return count;
283 }
284 #else
285 static int file_read (int fd, char *buf, size_t count)
286 {
287     return read (fd, buf, count);
288 }
289 #endif
290 void file_extract (int cmd, const char *fname, const char *kname)
291 {
292     int i, r;
293     char ext[128];
294     SYSNO sysno;
295     char ext_res[128];
296     const char *file_type;
297     void *file_info;
298     struct recExtractCtrl extractCtrl;
299     RecType rt;
300
301     for (i = strlen(fname); --i >= 0; )
302         if (fname[i] == '/')
303         {
304             strcpy (ext, "");
305             break;
306         }
307         else if (fname[i] == '.')
308         {
309             strcpy (ext, fname+i+1);
310             break;
311         }
312     sprintf (ext_res, "fileExtension.%s", ext);
313     if (!(file_type = res_get (common_resource, ext_res)))
314         return;
315     if (!(rt = recType_byName (file_type)))
316         return;
317     logf (LOG_DEBUG, "%c %s k=%s", cmd, fname, kname);
318     file_info = dict_lookup (file_idx, kname);
319     if (!file_info)
320     {
321         sysno = sysno_next++;
322         dict_insert (file_idx, kname, sizeof(sysno), &sysno);
323         lseek (sys_idx_fd, sysno * SYS_IDX_ENTRY_LEN, SEEK_SET);
324         write (sys_idx_fd, file_type, strlen (file_type)+1);
325         write (sys_idx_fd, kname, strlen(kname)+1);
326     }
327     else
328         memcpy (&sysno, (char*) file_info+1, sizeof(sysno));
329
330     if ((extractCtrl.fd = open (fname, O_RDONLY)) == -1)
331     {
332         logf (LOG_WARN|LOG_ERRNO, "open %s", fname);
333         return;
334     }
335     extractCtrl.subType = "";
336     extractCtrl.init = wordInit;
337     extractCtrl.add = wordAdd;
338 #if FILE_READ_BUF
339     file_read_start (extractCtrl.fd);
340 #endif
341     extractCtrl.readf = file_read;
342     key_sysno = sysno;
343     key_cmd = cmd;
344     r = (*rt->extract)(&extractCtrl);
345 #if FILE_READ_BUF
346     file_read_stop (extractCtrl.fd);
347 #endif
348     close (extractCtrl.fd);
349     if (r)
350         logf (LOG_WARN, "Couldn't extract file %s, code %d", fname, r);
351 }