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