rsbetween.[ch] - new result set type
[idzebra-moved-to-github.git] / rset / rsbetween.c
1 /*
2  * Copyright (C) 1994-2002, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss, Heikki Levanto
5  *
6  * $Id: rsbetween.c,v 1.1 2002-04-09 15:24:13 heikki Exp $
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <assert.h>
13
14 #include <rsbetween.h>
15 #include <zebrautl.h>
16
17 static void *r_create(RSET ct, const struct rset_control *sel, void *parms);
18 static RSFD r_open (RSET ct, int flag);
19 static void r_close (RSFD rfd);
20 static void r_delete (RSET ct);
21 static void r_rewind (RSFD rfd);
22 static int r_count (RSET ct);
23 static int r_read (RSFD rfd, void *buf, int *term_index);
24 static int r_write (RSFD rfd, const void *buf);
25
26 static const struct rset_control control_between = 
27 {
28     "between",
29     r_create,
30     r_open,
31     r_close,
32     r_delete,
33     r_rewind,
34     r_count,
35     r_read,
36     r_write,
37 };
38
39
40 const struct rset_control *rset_kind_between = &control_between;
41
42 struct rset_between_info {
43     int key_size;
44     RSET rset_l;
45     RSET rset_m;
46     RSET rset_r;
47     int term_index_s;
48     int (*cmp)(const void *p1, const void *p2);
49     struct rset_between_rfd *rfd_list;
50 };
51
52 struct rset_between_rfd {
53     RSFD rfd_l;
54     RSFD rfd_m;
55     RSFD rfd_r;
56     int  more_l;
57     int  more_m;
58     int  more_r;
59     int term_index_l;
60     int term_index_m;
61     int term_index_r;
62     void *buf_l;
63     void *buf_m;
64     void *buf_r;
65     int level;
66     struct rset_between_rfd *next;
67     struct rset_between_info *info;
68 };    
69
70 static void *r_create (RSET ct, const struct rset_control *sel, void *parms)
71 {
72     rset_between_parms *between_parms = (rset_between_parms *) parms;
73     struct rset_between_info *info;
74
75     info = (struct rset_between_info *) xmalloc (sizeof(*info));
76     info->key_size = between_parms->key_size;
77     info->rset_l = between_parms->rset_l;
78     info->rset_m = between_parms->rset_m;
79     info->rset_r = between_parms->rset_r;
80     if (rset_is_volatile(info->rset_l) || 
81         rset_is_volatile(info->rset_m) ||
82         rset_is_volatile(info->rset_r))
83         ct->flags |= RSET_FLAG_VOLATILE;
84     info->cmp = between_parms->cmp;
85     info->rfd_list = NULL;
86     
87     info->term_index_s = info->rset_l->no_rset_terms;
88     ct->no_rset_terms =
89         info->rset_l->no_rset_terms + 
90         info->rset_m->no_rset_terms + 
91         info->rset_r->no_rset_terms;
92     ct->rset_terms = (RSET_TERM *)
93         xmalloc (sizeof (*ct->rset_terms) * ct->no_rset_terms);
94
95     memcpy (ct->rset_terms, info->rset_l->rset_terms,
96             info->rset_l->no_rset_terms * sizeof(*ct->rset_terms));
97     memcpy (ct->rset_terms + info->rset_l->no_rset_terms,
98             info->rset_m->rset_terms,
99             info->rset_m->no_rset_terms * sizeof(*ct->rset_terms));
100     memcpy (ct->rset_terms + info->rset_l->no_rset_terms + 
101                              info->rset_m->no_rset_terms,
102             info->rset_r->rset_terms,
103             info->rset_r->no_rset_terms * sizeof(*ct->rset_terms));
104     return info;
105 }
106
107 static RSFD r_open (RSET ct, int flag)
108 {
109     struct rset_between_info *info = (struct rset_between_info *) ct->buf;
110     struct rset_between_rfd *rfd;
111
112     if (flag & RSETF_WRITE)
113     {
114         logf (LOG_FATAL, "between set type is read-only");
115         return NULL;
116     }
117     rfd = (struct rset_between_rfd *) xmalloc (sizeof(*rfd));
118     rfd->next = info->rfd_list;
119     info->rfd_list = rfd;
120     rfd->info = info;
121
122     rfd->buf_l = xmalloc (info->key_size);
123     rfd->buf_m = xmalloc (info->key_size);
124     rfd->buf_r = xmalloc (info->key_size);
125     rfd->rfd_l = rset_open (info->rset_l, RSETF_READ);
126     rfd->rfd_m = rset_open (info->rset_m, RSETF_READ);
127     rfd->rfd_r = rset_open (info->rset_r, RSETF_READ);
128     rfd->more_l = rset_read (info->rset_l, rfd->rfd_l, rfd->buf_l,
129                              &rfd->term_index_l);
130     rfd->more_m = rset_read (info->rset_m, rfd->rfd_m, rfd->buf_m,
131                              &rfd->term_index_m);
132     rfd->more_r = rset_read (info->rset_r, rfd->rfd_r, rfd->buf_r,
133                              &rfd->term_index_r);
134     rfd->level=0;
135     return rfd;
136 }
137
138 static void r_close (RSFD rfd)
139 {
140     struct rset_between_info *info = ((struct rset_between_rfd*)rfd)->info;
141     struct rset_between_rfd **rfdp;
142     
143     for (rfdp = &info->rfd_list; *rfdp; rfdp = &(*rfdp)->next)
144         if (*rfdp == rfd)
145         {
146             xfree ((*rfdp)->buf_l);
147             xfree ((*rfdp)->buf_m);
148             xfree ((*rfdp)->buf_r);
149             rset_close (info->rset_l, (*rfdp)->rfd_l);
150             rset_close (info->rset_m, (*rfdp)->rfd_m);
151             rset_close (info->rset_r, (*rfdp)->rfd_r);
152             *rfdp = (*rfdp)->next;
153             xfree (rfd);
154             return;
155         }
156     logf (LOG_FATAL, "r_close but no rfd match!");
157     assert (0);
158 }
159
160 static void r_delete (RSET ct)
161 {
162     struct rset_between_info *info = (struct rset_between_info *) ct->buf;
163
164     assert (info->rfd_list == NULL);
165     xfree (ct->rset_terms);
166     rset_delete (info->rset_l);
167     rset_delete (info->rset_m);
168     rset_delete (info->rset_r);
169     xfree (info);
170 }
171
172 static void r_rewind (RSFD rfd)
173 {
174     struct rset_between_info *info = ((struct rset_between_rfd*)rfd)->info;
175     struct rset_between_rfd *p = (struct rset_between_rfd *) rfd;
176
177     logf (LOG_DEBUG, "rsbetween_rewind");
178     rset_rewind (info->rset_l, p->rfd_l);
179     rset_rewind (info->rset_m, p->rfd_m);
180     rset_rewind (info->rset_r, p->rfd_r);
181     p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l, &p->term_index_l);
182     p->more_m = rset_read (info->rset_m, p->rfd_m, p->buf_m, &p->term_index_m);
183     p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r, &p->term_index_r);
184     p->level=0;
185 }
186
187 static int r_count (RSET ct)
188 {
189     return 0;
190 }
191
192 static int r_read (RSFD rfd, void *buf, int *term_index)
193 {
194     struct rset_between_rfd *p = (struct rset_between_rfd *) rfd;
195     struct rset_between_info *info = p->info;
196     int cmp_l;
197     int cmp_r;
198
199
200     while (p->more_m)
201     {
202
203         /* forward L until past m, count levels, note rec boundaries */
204         if (p->more_l)
205             cmp_l= (*info->cmp)(p->buf_l, p->buf_m);
206         else
207             cmp_l=2; /* past this record */
208         while (cmp_l < 0)   /* l before m */
209         {
210             if (cmp_l == -2)
211                 p->level=0; /* earlier record */
212             if (cmp_l == -1)
213                 p->level++; /* relevant start tag */
214             if (p->more_l)
215             {
216                 p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l,
217                                    &p->term_index_l);
218                 cmp_l= (*info->cmp)(p->buf_l, p->buf_m);
219             }
220             else
221                 cmp_l=2; 
222         } /* forward L */
223         
224         /* forward R until past m, count levels */
225         if (p->more_r)
226             cmp_r= (*info->cmp)(p->buf_r, p->buf_m);
227         else
228             cmp_r=2; 
229         while (cmp_r < 0)   /* r before m */
230         {
231             /* -2, earlier record, doesn't matter */
232             if (cmp_r == -1)
233                 p->level--; /* relevant end tag */
234             if (p->more_r)
235             {
236                 p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r,
237                                    &p->term_index_r);
238                 cmp_r= (*info->cmp)(p->buf_r, p->buf_m);
239             }
240             else
241                 cmp_r=2; 
242         } /* forward R */
243         
244         if ( ( p->level <= 0 ) && ! p->more_l)
245             return 0; /* no more start tags, nothing more to find */
246
247         if ( p->level > 0)  /* within a tag pair (or deeper) */
248         {
249             memcpy (buf, p->buf_m, info->key_size);
250             *term_index = p->term_index_m;
251             return 1;  
252         }
253         else
254             if ( ! p->more_l )  /* not in data, no more starts */
255                 return 0;  /* ergo, nothing can be found. stop scanning */
256         
257         p->more_m = rset_read (info->rset_m, p->rfd_m, p->buf_m,
258                                &p->term_index_m);
259     } /* while more_m */
260       
261     return 0;  /* no more data possible */
262
263 }  /* r_read */
264
265
266 static int r_write (RSFD rfd, const void *buf)
267 {
268     logf (LOG_FATAL, "between set type is read-only");
269     return -1;
270 }
271