1 /* $Id: rsbetween.c,v 1.25 2004-09-09 10:08:06 heikki Exp $
2 Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
5 This file is part of the Zebra server.
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 /* rsbetween is (mostly) used for xml searches. It returns the hits of the
25 * "middle" rset, that are in between the "left" and "right" rsets. For
26 * example "Shakespeare" in between "<title>" and </title>. The thing is
27 * complicated by the inclusion of attributes (from their own rset). If attrs
28 * specified, they must match the "left" rset (start tag). "Hamlet" between
29 * "<title lang=eng>" and "</title>". (This assumes that the attributes are
30 * indexed to the same seqno as the tags).
41 #define RSBETWEEN_DEBUG 0
43 static RSFD r_open_between (RSET ct, int flag);
44 static void r_close_between (RSFD rfd);
45 static void r_delete_between (RSET ct);
46 static void r_rewind_between (RSFD rfd);
47 static int r_forward_between(RSFD rfd, void *buf, const void *untilbuf);
48 static int r_read_between (RSFD rfd, void *buf);
49 static int r_write_between (RSFD rfd, const void *buf);
50 static void r_pos_between (RSFD rfd, double *current, double *total);
52 static const struct rset_control control =
66 const struct rset_control *rset_kind_between = &control;
68 struct rset_between_info {
69 RSET rset_l; /* left arg, start tag */
70 RSET rset_m; /* the thing itself */
71 RSET rset_r; /* right arg, end tag */
72 RSET rset_attr; /* attributes , optional */
75 struct rset_between_rfd {
88 int level; /* counting start/end tags */
93 static void log2 (struct rset_between_rfd *p, char *msg, int cmp_l, int cmp_r)
98 logf(LOG_DEBUG,"btw: %s l=%s(%d/%d) m=%s(%d) r=%s(%d/%d), lev=%d",
100 (*p->info->printer)(p->buf_l, buf_l), p->more_l, cmp_l,
101 (*p->info->printer)(p->buf_m, buf_m), p->more_m,
102 (*p->info->printer)(p->buf_r, buf_r), p->more_r, cmp_r,
107 RSET rsbetween_create( NMEM nmem, const struct key_control *kcontrol,
109 RSET rset_l, RSET rset_m, RSET rset_r, RSET rset_attr)
111 RSET rnew=rset_create_base(&control, nmem, kcontrol, scope);
112 struct rset_between_info *info=
113 (struct rset_between_info *) nmem_malloc(rnew->nmem,sizeof(*info));
114 info->rset_l = rset_l;
115 info->rset_m = rset_m;
116 info->rset_r = rset_r;
117 info->rset_attr = rset_attr;
123 static void r_delete_between (RSET ct)
125 struct rset_between_info *info = (struct rset_between_info *) ct->priv;
127 rset_delete (info->rset_l);
128 rset_delete (info->rset_m);
129 rset_delete (info->rset_r);
131 rset_delete (info->rset_attr);
135 static RSFD r_open_between (RSET ct, int flag)
137 struct rset_between_info *info = (struct rset_between_info *) ct->priv;
139 struct rset_between_rfd *p;
141 if (flag & RSETF_WRITE)
143 logf (LOG_FATAL, "between set type is read-only");
146 rfd=rfd_create_base(ct);
148 p=(struct rset_between_rfd *)rfd->priv;
150 p = (struct rset_between_rfd *) nmem_malloc(ct->nmem, (sizeof(*p)));
152 p->buf_l = nmem_malloc(ct->nmem, (ct->keycontrol->key_size));
153 p->buf_m = nmem_malloc(ct->nmem, (ct->keycontrol->key_size));
154 p->buf_r = nmem_malloc(ct->nmem, (ct->keycontrol->key_size));
155 p->buf_attr = nmem_malloc(ct->nmem, (ct->keycontrol->key_size));
158 p->rfd_l = rset_open (info->rset_l, RSETF_READ);
159 p->rfd_m = rset_open (info->rset_m, RSETF_READ);
160 p->rfd_r = rset_open (info->rset_r, RSETF_READ);
162 p->more_l = rset_read (p->rfd_l, p->buf_l);
163 p->more_m = rset_read (p->rfd_m, p->buf_m);
164 p->more_r = rset_read (p->rfd_r, p->buf_r);
167 p->rfd_attr = rset_open (info->rset_attr, RSETF_READ);
168 p->more_attr = rset_read (p->rfd_attr, p->buf_attr);
175 static void r_close_between (RSFD rfd)
177 struct rset_between_info *info =(struct rset_between_info *)rfd->rset->priv;
178 struct rset_between_rfd *p=(struct rset_between_rfd *)rfd->priv;
180 rset_close (p->rfd_l);
181 rset_close (p->rfd_m);
182 rset_close (p->rfd_r);
184 rset_close (p->rfd_attr);
185 rfd_delete_base(rfd);
188 static void r_rewind_between (RSFD rfd)
190 struct rset_between_info *info =(struct rset_between_info *)rfd->rset->priv;
191 struct rset_between_rfd *p=(struct rset_between_rfd *)rfd->priv;
194 logf (LOG_DEBUG, "rsbetween_rewind");
196 rset_rewind (p->rfd_l);
197 rset_rewind (p->rfd_m);
198 rset_rewind (p->rfd_r);
199 p->more_l = rset_read (p->rfd_l, p->buf_l);
200 p->more_m = rset_read (p->rfd_m, p->buf_m);
201 p->more_r = rset_read (p->rfd_r, p->buf_r);
204 rset_rewind (p->rfd_attr);
205 p->more_attr = rset_read (p->rfd_attr, p->buf_attr);
213 static int r_forward_between(RSFD rfd, void *buf, const void *untilbuf)
215 struct rset_between_rfd *p=(struct rset_between_rfd *)rfd->priv;
218 log2( p, "fwd: before forward", 0,0);
220 /* It is enough to forward the m pointer here, the read will */
221 /* naturally forward the l, m, and attr pointers */
223 p->more_m=rset_forward(p->rfd_m, p->buf_m,untilbuf);
225 log2( p, "fwd: after forward M", 0,0);
227 rc = r_read_between(rfd, buf);
229 log2( p, "fwd: after forward", 0,0);
237 static int r_read_between (RSFD rfd, void *buf)
239 struct rset_between_info *info =(struct rset_between_info *)rfd->rset->priv;
240 struct rset_between_rfd *p=(struct rset_between_rfd *)rfd->priv;
241 const struct key_control *kctrl=rfd->rset->keycontrol;
249 log2( p, "start of loop", cmp_l, cmp_r);
252 /* forward L until past m, count levels, note rec boundaries */
254 cmp_l= (*kctrl->cmp)(p->buf_l, p->buf_m);
258 cmp_l=rfd->rset->scope; /* past this record */
261 log2( p, "after first L", cmp_l, cmp_r);
264 while (cmp_l < 0) /* l before m */
266 if (cmp_l <= - rfd->rset->scope) /* ==-2 */
267 p->level=0; /* earlier record */
268 if (cmp_l > - rfd->rset->scope) /* == -1 */
270 p->level++; /* relevant start tag */
272 if (!info->rset_attr)
280 cmp_attr = (*kctrl->cmp)(p->buf_attr, p->buf_l);
286 else if (cmp_attr > 0)
288 else if (cmp_attr > - rfd->rset->scope) /* == -1 */
289 p->more_attr = rset_read (p->rfd_attr, p->buf_attr);
290 /* if we had a forward that went all the way to
291 * the seqno, we could use that. But fwd only goes
293 else if (cmp_attr <= - rfd->rset->scope) /* ==-2 */
295 p->more_attr = rset_forward( p->rfd_attr,
296 p->buf_attr, p->buf_l);
298 logf(LOG_DEBUG, "btw: after frowarding attr m=%d",
302 } /* while more_attr */
307 if (cmp_l <= - rfd->rset->scope )/* ==-2 */
311 p->more_l=rset_forward(p->rfd_l, p->buf_l, p->buf_m);
313 cmp_l= (*kctrl->cmp)(p->buf_l, p->buf_m);
315 cmp_l=rfd->rset->scope; /*2*/
317 log2( p, "after forwarding L", cmp_l, cmp_r);
322 p->more_l = rset_read (p->rfd_l, p->buf_l);
325 p->more_l = rset_read (p->rfd_l, p->buf_l);
329 cmp_l= (*kctrl->cmp)(p->buf_l, p->buf_m);
332 cmp_l=rfd->rset->scope; /*2*/
334 log2( p, "end of L loop", cmp_l, cmp_r);
339 /* forward R until past m, count levels */
341 log2( p, "Before moving R", cmp_l, cmp_r);
344 cmp_r= (*kctrl->cmp)(p->buf_r, p->buf_m);
346 cmp_r=rfd->rset->scope; /*2*/
348 log2( p, "after first R", cmp_l, cmp_r);
350 while (cmp_r < 0) /* r before m */
352 /* -2, earlier record, don't count level */
353 if (cmp_r > -rfd->rset->scope) /* == -1 */
354 p->level--; /* relevant end tag */
358 if (cmp_r <= - rfd->rset->scope) /* == -2 */
360 p->more_r=rset_forward(p->rfd_r, p->buf_r, p->buf_m);
363 p->more_r = rset_read (p->rfd_r, p->buf_r);
366 cmp_r= (*kctrl->cmp)(p->buf_r, p->buf_m);
369 p->more_r = rset_read (p->rfd_r, p->buf_r);
370 cmp_r= (*kctrl->cmp)(p->buf_r, p->buf_m);
374 cmp_r=rfd->rset->scope; /*2*/
376 log2( p, "End of R loop", cmp_l, cmp_r);
380 if ( ( p->level <= 0 ) && ! p->more_l)
381 return 0; /* no more start tags, nothing more to find */
383 if ( attr_match && p->level > 0) /* within a tag pair (or deeper) */
385 memcpy (buf, p->buf_m, kctrl->key_size);
387 log2( p, "Returning a hit (and forwarding m)", cmp_l, cmp_r);
389 p->more_m = rset_read (p->rfd_m, p->buf_m);
390 if (cmp_l >= rfd->rset->scope) /* == 2 */
395 else if ( ! p->more_l ) /* not in data, no more starts */
398 log2( p, "no more starts, exiting without a hit", cmp_l, cmp_r);
400 return 0; /* ergo, nothing can be found. stop scanning */
403 if (cmp_l >= rfd->rset->scope) /* == 2 */
406 p->more_m=rset_forward(p->rfd_m, p->buf_m, p->buf_l);
409 p->more_m = rset_read (p->rfd_m, p->buf_m);
412 if (cmp_l >= rfd->rset->scope ) /* == 2 */
414 p->more_m = rset_read (p->rfd_m, p->buf_m);
417 log2( p, "End of M loop", cmp_l, cmp_r);
422 log2( p, "Exiting, nothing more in m", cmp_l, cmp_r);
424 return 0; /* no more data possible */
430 static int r_write_between (RSFD rfd, const void *buf)
432 logf (LOG_FATAL, "between set type is read-only");
437 static void r_pos_between (RSFD rfd, double *current, double *total)
439 struct rset_between_rfd *p=(struct rset_between_rfd *)rfd->priv;
445 rset_pos(p->rfd_l, &lcur, <ot);
446 rset_pos(p->rfd_m, &mcur, &mtot);
447 rset_pos(p->rfd_r, &rcur, &rtot);
448 if ( (ltot<0) && (mtot<0) && (rtot<0) ) { /*no position */
449 *current=mcur; /* return same as you got */
450 *total=mtot; /* probably -1 for not available */
452 if ( ltot<0) { ltot=0; lcur=0;} /* if only one useful, use it */
453 if ( mtot<0) { mtot=0; mcur=0;}
454 if ( rtot<0) { rtot=0; rcur=0;}
455 if ( ltot+mtot+rtot < 1 ) { /* empty rset */
460 r=1.0*(lcur+mcur+rcur)/(ltot+mtot+rtot); /* weighed average of l and r */
464 yaz_log(LOG_DEBUG,"betw_pos: (%s/%s) %0.1f/%0.1f= %0.4f ",
465 info->rset_l->control->desc, info->rset_r->control->desc,
466 *current, *total, r);