Partial port to WIN95/NT.
[idzebra-moved-to-github.git] / rset / rstemp.c
1 /*
2  * Copyright (C) 1994-1995, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: rstemp.c,v $
7  * Revision 1.20  1997-09-09 13:38:17  adam
8  * Partial port to WIN95/NT.
9  *
10  * Revision 1.19  1997/09/04 13:58:57  adam
11  * Added O_BINARY for open calls.
12  *
13  * Revision 1.18  1996/10/29 13:54:52  adam
14  * Changed name of setting tempSetDir to setTmpDir.
15  *
16  * Revision 1.17  1995/12/11 09:15:28  adam
17  * New set types: sand/sor/snot - ranked versions of and/or/not in
18  * ranked/semi-ranked result sets.
19  * Note: the snot not finished yet.
20  * New rset member: flag.
21  * Bug fix: r_delete in rsrel.c did free bad memory block.
22  *
23  * Revision 1.16  1995/11/28  14:47:02  adam
24  * New setting: tempSetPath. Location of temporary result sets.
25  *
26  * Revision 1.15  1995/10/12  12:41:58  adam
27  * Private info (buf) moved from struct rset_control to struct rset.
28  * Bug fixes in relevance.
29  *
30  * Revision 1.14  1995/10/10  14:00:04  adam
31  * Function rset_open changed its wflag parameter to general flags.
32  *
33  * Revision 1.13  1995/10/06  14:38:06  adam
34  * New result set method: r_score.
35  * Local no (sysno) and score is transferred to retrieveCtrl.
36  *
37  * Revision 1.12  1995/09/28  09:52:11  adam
38  * xfree/xmalloc used everywhere.
39  *
40  * Revision 1.11  1995/09/18  14:17:56  adam
41  * Bug fixes.
42  *
43  * Revision 1.10  1995/09/15  14:45:39  adam
44  * Bug fixes.
45  *
46  * Revision 1.9  1995/09/15  09:20:42  adam
47  * Bug fixes.
48  *
49  * Revision 1.8  1995/09/08  14:52:42  adam
50  * Work on relevance feedback.
51  *
52  * Revision 1.7  1995/09/07  13:58:44  adam
53  * New parameter: result-set file descriptor (RSFD) to support multiple
54  * positions within the same result-set.
55  * Boolean operators: and, or, not implemented.
56  *
57  * Revision 1.6  1995/09/06  16:11:56  adam
58  * More work on boolean sets.
59  *
60  * Revision 1.5  1995/09/05  16:36:59  adam
61  * Minor changes.
62  *
63  * Revision 1.4  1995/09/05  11:43:24  adam
64  * Complete version of temporary sets. Not tested yet though.
65  *
66  * Revision 1.3  1995/09/04  15:20:40  adam
67  * More work on temp sets. is_open member removed.
68  *
69  * Revision 1.2  1995/09/04  09:10:56  adam
70  * Minor changes.
71  *
72  * Revision 1.1  1994/11/04  13:21:30  quinn
73  * Working.
74  *
75  */
76
77 #include <fcntl.h>
78 #include <assert.h>
79 #ifdef WINDOWS
80 #include <io.h>
81 #else
82 #include <unistd.h>
83 #endif
84 #include <string.h>
85 #include <sys/types.h>
86 #include <stdio.h>
87
88 #include <zebrautl.h>
89 #include <rstemp.h>
90
91 static void *r_create(const struct rset_control *sel, void *parms,
92                       int *flags);
93 static RSFD r_open (RSET ct, int flag);
94 static void r_close (RSFD rfd);
95 static void r_delete (RSET ct);
96 static void r_rewind (RSFD rfd);
97 static int r_count (RSET ct);
98 static int r_read (RSFD rfd, void *buf);
99 static int r_write (RSFD rfd, const void *buf);
100 static int r_score (RSFD rfd, int *score);
101
102 static int temppath_init = 0;
103 static char *temppath_root = NULL;
104
105 static const rset_control control = 
106 {
107     "temp",
108     r_create,
109     r_open,
110     r_close,
111     r_delete,
112     r_rewind,
113     r_count,
114     r_read,
115     r_write,
116     r_score
117 };
118
119 const rset_control *rset_kind_temp = &control;
120
121 struct rset_temp_info {
122     int     fd;
123     char   *fname;
124     size_t  key_size;      /* key size */
125     char   *buf_mem;       /* window buffer */
126     size_t  buf_size;      /* size of window */
127     size_t  pos_end;       /* last position in set */
128     size_t  pos_cur;       /* current position in set */
129     size_t  pos_buf;       /* position of first byte in window */
130     size_t  pos_border;    /* position of last byte+1 in window */
131     int     dirty;         /* window is dirty */
132 };
133
134 struct rset_temp_rfd {
135     struct rset_temp_info *info;
136     struct rset_temp_rfd *next;
137 };
138
139 static void *r_create(const struct rset_control *sel, void *parms, int *flags)
140 {
141     rset_temp_parms *temp_parms = parms;
142     struct rset_temp_info *info;
143    
144     info = xmalloc (sizeof(struct rset_temp_info));
145     info->fd = -1;
146     info->fname = NULL;
147     info->key_size = temp_parms->key_size;
148     info->buf_size = 4096;
149     info->buf_mem = xmalloc (info->buf_size);
150     info->pos_cur = 0;
151     info->pos_end = 0;
152     info->pos_buf = 0;
153     info->dirty = 0;
154
155     if (!temppath_init)
156     {
157         temppath_init = 1;
158         temppath_root = res_get (common_resource, "setTmpDir");
159     }
160     return info;
161 }
162
163 static RSFD r_open (RSET ct, int flag)
164 {
165     struct rset_temp_info *info = ct->buf;
166     struct rset_temp_rfd *rfd;
167
168     assert (info->fd == -1);
169     if (info->fname)
170     {
171         if (flag & RSETF_WRITE)
172             info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
173         else
174             info->fd = open (info->fname, O_BINARY|O_RDONLY);
175         if (info->fd == -1)
176         {
177             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
178             exit (1);
179         }
180     }
181     rfd = xmalloc (sizeof(*rfd));
182     rfd->info = info;
183     r_rewind (rfd);
184     return rfd;
185 }
186
187 /* r_flush:
188       flush current window to file if file is assocated with set
189  */
190 static void r_flush (RSFD rfd, int mk)
191 {
192     struct rset_temp_info *info = ((struct rset_temp_rfd*) rfd)->info;
193
194     if (!info->fname && mk)
195     {
196         char *s = (char*) tempnam (temppath_root, "zrs");
197
198         info->fname = xmalloc (strlen(s)+1);
199         strcpy (info->fname, s);
200
201         logf (LOG_DEBUG, "creating tempfile %s", info->fname);
202         info->fd = open (info->fname, O_BINARY|O_RDWR|O_CREAT, 0666);
203         if (info->fd == -1)
204         {
205             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
206             exit (1);
207         }
208     }
209     if (info->fname && info->fd != -1 && info->dirty)
210     {
211         size_t r, count;
212         
213         if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
214         {
215             logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
216             exit (1);
217         }
218         count = info->buf_size;
219         if (count > info->pos_end - info->pos_buf)
220             count = info->pos_end - info->pos_buf;
221         if ((r = write (info->fd, info->buf_mem, count)) < count)
222         {
223             if (r == -1)
224                 logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
225             else
226                 logf (LOG_FATAL, "write of %ld but got %ld",
227                       (long) count, (long) r);
228             exit (1);
229         }
230         info->dirty = 0;
231     }
232 }
233
234 static void r_close (RSFD rfd)
235 {
236     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
237
238     r_flush (rfd, 0);
239     if (info->fname && info->fd != -1)
240     {
241         close (info->fd);
242         info->fd = -1;
243     }
244 }
245
246 static void r_delete (RSET ct)
247 {
248     struct rset_temp_info *info = ct->buf;
249
250     if (info->fname)
251         unlink (info->fname);        
252     free (info->buf_mem);
253     logf (LOG_DEBUG, "r_delete: set size %ld", (long) info->pos_end);
254     if (info->fname)
255     {
256         logf (LOG_DEBUG, "r_delete: unlink %s", info->fname);
257         unlink (info->fname);
258         free (info->fname);
259     }
260     free (info);
261 }
262
263 /* r_reread:
264       read from file to window if file is assocated with set -
265       indicated by fname
266  */
267 static void r_reread (RSFD rfd)
268 {
269     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
270
271     if (info->fname)
272     {
273         size_t r, count;
274
275         info->pos_border = info->pos_cur + info->buf_size;
276         if (info->pos_border > info->pos_end)
277             info->pos_border = info->pos_end;
278         count = info->pos_border - info->pos_buf;
279         if (count > 0)
280         {
281             if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
282             {
283                 logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
284                 exit (1);
285             }
286             if ((r = read (info->fd, info->buf_mem, count)) < count)
287             {
288                 if (r == -1)
289                     logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
290                 else
291                     logf (LOG_FATAL, "read of %ld but got %ld",
292                           (long) count, (long) r);
293                 exit (1);
294             }
295         }
296     }
297     else
298         info->pos_border = info->pos_end;
299 }
300
301 static void r_rewind (RSFD rfd)
302 {
303     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
304
305     r_flush (rfd, 0);
306     info->pos_cur = 0;
307     info->pos_buf = 0;
308     r_reread (rfd);
309 }
310
311 static int r_count (RSET ct)
312 {
313     struct rset_temp_info *info = ct->buf;
314
315     return info->pos_end / info->key_size;
316 }
317
318 static int r_read (RSFD rfd, void *buf)
319 {
320     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
321
322     size_t nc = info->pos_cur + info->key_size;
323
324     if (nc > info->pos_border)
325     {
326         if (nc > info->pos_end)
327             return 0;
328         r_flush (rfd, 0);
329         info->pos_buf = info->pos_cur;
330         r_reread (rfd);
331     }
332     memcpy (buf, info->buf_mem + (info->pos_cur - info->pos_buf),
333             info->key_size);
334     info->pos_cur = nc;
335     return 1;
336 }
337
338 static int r_write (RSFD rfd, const void *buf)
339 {
340     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
341
342     size_t nc = info->pos_cur + info->key_size;
343
344     if (nc > info->pos_buf + info->buf_size)
345     {
346         r_flush (rfd, 1);
347         info->pos_buf = info->pos_cur;
348         if (info->pos_buf < info->pos_end)
349             r_reread (rfd);
350     }
351     info->dirty = 1;
352     memcpy (info->buf_mem + (info->pos_cur - info->pos_buf), buf,
353             info->key_size);
354     info->pos_cur = nc;
355     if (nc > info->pos_end)
356         info->pos_border = info->pos_end = nc;
357     return 1;
358 }
359
360 static int r_score (RSFD rfd, int *score)
361 {
362     *score = -1;
363     return -1;
364 }