Bug fixes.
[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.10  1995-09-15 14:45:39  adam
8  * Bug fixes.
9  *
10  * Revision 1.9  1995/09/15  09:20:42  adam
11  * Bug fixes.
12  *
13  * Revision 1.8  1995/09/08  14:52:42  adam
14  * Work on relevance feedback.
15  *
16  * Revision 1.7  1995/09/07  13:58:44  adam
17  * New parameter: result-set file descriptor (RSFD) to support multiple
18  * positions within the same result-set.
19  * Boolean operators: and, or, not implemented.
20  *
21  * Revision 1.6  1995/09/06  16:11:56  adam
22  * More work on boolean sets.
23  *
24  * Revision 1.5  1995/09/05  16:36:59  adam
25  * Minor changes.
26  *
27  * Revision 1.4  1995/09/05  11:43:24  adam
28  * Complete version of temporary sets. Not tested yet though.
29  *
30  * Revision 1.3  1995/09/04  15:20:40  adam
31  * More work on temp sets. is_open member removed.
32  *
33  * Revision 1.2  1995/09/04  09:10:56  adam
34  * Minor changes.
35  *
36  * Revision 1.1  1994/11/04  13:21:30  quinn
37  * Working.
38  *
39  */
40
41 #include <fcntl.h>
42 #include <assert.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <stdio.h>
46
47 #include <alexutil.h>
48 #include <rstemp.h>
49
50 static rset_control *r_create(const struct rset_control *sel, void *parms);
51 static RSFD r_open (rset_control *ct, int wflag);
52 static void r_close (RSFD rfd);
53 static void r_delete (rset_control *ct);
54 static void r_rewind (RSFD rfd);
55 static int r_count (rset_control *ct);
56 static int r_read (RSFD rfd, void *buf);
57 static int r_write (RSFD rfd, const void *buf);
58
59 static const rset_control control = 
60 {
61     "Temporary set",
62     0,
63     r_create,
64     r_open,
65     r_close,
66     r_delete,
67     r_rewind,
68     r_count,
69     r_read,
70     r_write
71 };
72
73 const rset_control *rset_kind_temp = &control;
74
75 struct rset_temp_info {
76     int     fd;
77     char   *fname;
78     size_t  key_size;      /* key size */
79     char   *buf_mem;       /* window buffer */
80     size_t  buf_size;      /* size of window */
81     size_t  pos_end;       /* last position in set */
82     size_t  pos_cur;       /* current position in set */
83     size_t  pos_buf;       /* position of first byte in window */
84     size_t  pos_border;    /* position of last byte+1 in window */
85     int     dirty;         /* window is dirty */
86 };
87
88 struct rset_temp_rfd {
89     struct rset_temp_info *info;
90     struct rset_temp_rfd *next;
91 };
92
93 static struct rset_control *r_create(const struct rset_control *sel,
94                                      void *parms)
95 {
96     rset_control *newct;
97     rset_temp_parms *temp_parms = parms;
98     struct rset_temp_info *info;
99     
100     newct = xmalloc(sizeof(*newct));
101     memcpy(newct, sel, sizeof(*sel));
102     newct->buf = xmalloc (sizeof(struct rset_temp_info));
103     info = newct->buf;
104
105     info->fd = -1;
106     info->fname = NULL;
107     info->key_size = temp_parms->key_size;
108     info->buf_size = 2048;
109     info->buf_mem = xmalloc (info->buf_size);
110     info->pos_cur = 0;
111     info->pos_end = 0;
112     info->pos_buf = 0;
113     info->dirty = 0;
114
115     return newct;
116 }
117
118 static RSFD r_open (struct rset_control *ct, int wflag)
119 {
120     struct rset_temp_info *info = ct->buf;
121     struct rset_temp_rfd *rfd;
122
123     assert (info->fd == -1);
124     if (info->fname)
125     {
126         if (wflag)
127             info->fd = open (info->fname, O_RDWR|O_CREAT, 0666);
128         else
129             info->fd = open (info->fname, O_RDONLY);
130         if (info->fd == -1)
131         {
132             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
133             exit (1);
134         }
135     }
136     rfd = xmalloc (sizeof(*rfd));
137     rfd->info = info;
138     r_rewind (rfd);
139     return rfd;
140 }
141
142 /* r_flush:
143       flush current window to file if file is assocated with set
144  */
145 static void r_flush (RSFD rfd, int mk)
146 {
147     struct rset_temp_info *info = ((struct rset_temp_rfd*) rfd)->info;
148
149     if (!info->fname && mk)
150     {
151         char *s = (char*) tempnam (NULL, "zrs");
152
153         info->fname = xmalloc (strlen(s)+1);
154         strcpy (info->fname, s);
155
156         logf (LOG_DEBUG, "creating tempfile %s", info->fname);
157         info->fd = open (info->fname, O_RDWR|O_CREAT, 0666);
158         if (info->fd == -1)
159         {
160             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
161             exit (1);
162         }
163     }
164     if (info->fname && info->fd != -1 && info->dirty)
165     {
166         size_t r, count;
167         
168         if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
169         {
170             logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
171             exit (1);
172         }
173         count = info->buf_size;
174         if (count > info->pos_end - info->pos_buf)
175             count = info->pos_end - info->pos_buf;
176         if ((r = write (info->fd, info->buf_mem, count)) < count)
177         {
178             if (r == -1)
179                 logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
180             else
181                 logf (LOG_FATAL, "write of %ld but got %ld",
182                       (long) count, (long) r);
183             exit (1);
184         }
185         info->dirty = 0;
186     }
187 }
188
189 static void r_close (RSFD rfd)
190 {
191     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
192
193     r_flush (rfd, 0);
194     if (info->fname && info->fd != -1)
195     {
196         close (info->fd);
197         info->fd = -1;
198     }
199 }
200
201 static void r_delete (struct rset_control *ct)
202 {
203     struct rset_temp_info *info = ct->buf;
204
205     if (info->fname)
206         unlink (info->fname);        
207     free (info->buf_mem);
208     free (info->fname);
209     free (info);
210 }
211
212 /* r_reread:
213       read from file to window if file is assocated with set -
214       indicated by fname
215  */
216 static void r_reread (RSFD rfd)
217 {
218     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
219
220     if (info->fname)
221     {
222         size_t r, count;
223
224         info->pos_border = info->pos_cur + info->buf_size;
225         if (info->pos_border > info->pos_end)
226             info->pos_border = info->pos_end;
227         count = info->pos_border - info->pos_buf;
228         if (count > 0)
229         {
230             if (lseek (info->fd, info->pos_buf, SEEK_SET) == -1)
231             {
232                 logf (LOG_FATAL|LOG_ERRNO, "lseek %s", info->fname);
233                 exit (1);
234             }
235             if ((r = read (info->fd, info->buf_mem, count)) < count)
236             {
237                 if (r == -1)
238                     logf (LOG_FATAL|LOG_ERRNO, "read %s", info->fname);
239                 else
240                     logf (LOG_FATAL, "read of %ld but got %ld",
241                           (long) count, (long) r);
242                 exit (1);
243             }
244         }
245     }
246     else
247         info->pos_border = info->pos_end;
248 }
249
250 static void r_rewind (RSFD rfd)
251 {
252     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
253
254     r_flush (rfd, 0);
255     info->pos_cur = 0;
256     info->pos_buf = 0;
257     r_reread (rfd);
258 }
259
260 static int r_count (struct rset_control *ct)
261 {
262     struct rset_temp_info *info = ct->buf;
263
264     return info->pos_end / info->key_size;
265 }
266
267 static int r_read (RSFD rfd, void *buf)
268 {
269     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
270
271     size_t nc = info->pos_cur + info->key_size;
272
273     if (nc > info->pos_border)
274     {
275         if (nc > info->pos_end)
276             return 0;
277         r_flush (rfd, 0);
278         info->pos_buf = info->pos_cur;
279         r_reread (rfd);
280     }
281     memcpy (buf, info->buf_mem + (info->pos_cur - info->pos_buf),
282             info->key_size);
283     info->pos_cur = nc;
284     return 1;
285 }
286
287 static int r_write (RSFD rfd, const void *buf)
288 {
289     struct rset_temp_info *info = ((struct rset_temp_rfd*)rfd)->info;
290
291     size_t nc = info->pos_cur + info->key_size;
292
293     if (nc > info->pos_buf + info->buf_size)
294     {
295         r_flush (rfd, 1);
296         info->pos_buf = info->pos_cur;
297         r_reread (rfd);
298         info->dirty = 1;
299     }
300     memcpy (info->buf_mem + (info->pos_cur - info->pos_buf), buf,
301             info->key_size);
302     info->pos_cur = nc;
303     if (nc > info->pos_end)
304         info->pos_border = info->pos_end = nc;
305     return 1;
306 }
307