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