8c8a258f4838f0163230a0060c02b6ceedf42131
[idzebra-moved-to-github.git] / index / zrpn.c
1 /* $Id: zrpn.c,v 1.141.2.9 2005-04-29 18:38:49 adam Exp $
2    Copyright (C) 1995-2005
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
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
10 version.
11
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
15 for more details.
16
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
20 02111-1307, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <assert.h>
26 #ifdef WIN32
27 #include <io.h>
28 #else
29 #include <unistd.h>
30 #endif
31 #include <ctype.h>
32
33 #include "index.h"
34 #include <zebra_xpath.h>
35
36 #include <charmap.h>
37 #include <rstemp.h>
38 #include <rsnull.h>
39 #include <rsbool.h>
40 #include <rsbetween.h>
41 #include <rsprox.h>
42
43 struct rpn_char_map_info {
44     ZebraMaps zm;
45     int reg_type;
46 };
47
48 typedef struct {
49     int type;
50     int major;
51     int minor;
52     Z_AttributesPlusTerm *zapt;
53 } AttrType;
54
55
56 static const char **rpn_char_map_handler(void *vp, const char **from, int len)
57 {
58     struct rpn_char_map_info *p = (struct rpn_char_map_info *) vp;
59     const char **out = zebra_maps_input(p->zm, p->reg_type, from, len, 0);
60 #if 0
61     if (out && *out)
62     {
63         const char *outp = *out;
64         yaz_log(LOG_LOG, "---");
65         while (*outp)
66         {
67             yaz_log(LOG_LOG, "%02X", *outp);
68             outp++;
69         }
70     }
71 #endif
72     return out;
73 }
74
75 static void rpn_char_map_prepare(struct zebra_register *reg, int reg_type,
76                                   struct rpn_char_map_info *map_info)
77 {
78     map_info->zm = reg->zebra_maps;
79     map_info->reg_type = reg_type;
80     dict_grep_cmap(reg->dict, map_info, rpn_char_map_handler);
81 }
82
83 static int attr_find_ex(AttrType *src, oid_value *attributeSetP,
84                          const char **string_value)
85 {
86     int num_attributes;
87
88     num_attributes = src->zapt->attributes->num_attributes;
89     while (src->major < num_attributes)
90     {
91         Z_AttributeElement *element;
92
93         element = src->zapt->attributes->attributes[src->major];
94         if (src->type == *element->attributeType)
95         {
96             switch (element->which) 
97             {
98             case Z_AttributeValue_numeric:
99                 ++(src->major);
100                 if (element->attributeSet && attributeSetP)
101                 {
102                     oident *attrset;
103
104                     attrset = oid_getentbyoid(element->attributeSet);
105                     *attributeSetP = attrset->value;
106                 }
107                 return *element->value.numeric;
108                 break;
109             case Z_AttributeValue_complex:
110                 if (src->minor >= element->value.complex->num_list)
111                     break;
112                 if (element->attributeSet && attributeSetP)
113                 {
114                     oident *attrset;
115                     
116                     attrset = oid_getentbyoid(element->attributeSet);
117                     *attributeSetP = attrset->value;
118                 }
119                 if (element->value.complex->list[src->minor]->which ==  
120                     Z_StringOrNumeric_numeric)
121                 {
122                     ++(src->minor);
123                     return
124                         *element->value.complex->list[src->minor-1]->u.numeric;
125                 }
126                 else if (element->value.complex->list[src->minor]->which ==  
127                          Z_StringOrNumeric_string)
128                 {
129                     if (!string_value)
130                         break;
131                     ++(src->minor);
132                     *string_value = 
133                         element->value.complex->list[src->minor-1]->u.string;
134                     return -2;
135                 }
136                 else
137                     break;
138             default:
139                 assert(0);
140             }
141         }
142         ++(src->major);
143     }
144     return -1;
145 }
146
147 static int attr_find(AttrType *src, oid_value *attributeSetP)
148 {
149     return attr_find_ex(src, attributeSetP, 0);
150 }
151
152 static void attr_init(AttrType *src, Z_AttributesPlusTerm *zapt,
153                        int type)
154 {
155     src->zapt = zapt;
156     src->type = type;
157     src->major = 0;
158     src->minor = 0;
159 }
160
161 #define TERM_COUNT        
162        
163 struct grep_info {        
164 #ifdef TERM_COUNT        
165     int *term_no;        
166 #endif        
167     ISAMS_P *isam_p_buf;
168     int isam_p_size;        
169     int isam_p_indx;
170     ZebraHandle zh;
171     int reg_type;
172     ZebraSet termset;
173 };        
174
175 static void term_untrans(ZebraHandle zh, int reg_type,
176                            char *dst, const char *src)
177 {
178     int len = 0;
179     while (*src)
180     {
181         const char *cp = zebra_maps_output(zh->reg->zebra_maps,
182                                             reg_type, &src);
183         if (!cp && len < IT_MAX_WORD-1)
184             dst[len++] = *src++;
185         else
186             while (*cp && len < IT_MAX_WORD-1)
187                 dst[len++] = *cp++;
188     }
189     dst[len] = '\0';
190 }
191
192 static void add_isam_p(const char *name, const char *info,
193                         struct grep_info *p)
194 {
195     if (p->isam_p_indx == p->isam_p_size)
196     {
197         ISAMS_P *new_isam_p_buf;
198 #ifdef TERM_COUNT        
199         int *new_term_no;        
200 #endif
201         p->isam_p_size = 2*p->isam_p_size + 100;
202         new_isam_p_buf = (ISAMS_P *) xmalloc(sizeof(*new_isam_p_buf) *
203                                              p->isam_p_size);
204         if (p->isam_p_buf)
205         {
206             memcpy(new_isam_p_buf, p->isam_p_buf,
207                     p->isam_p_indx * sizeof(*p->isam_p_buf));
208             xfree(p->isam_p_buf);
209         }
210         p->isam_p_buf = new_isam_p_buf;
211
212 #ifdef TERM_COUNT
213         new_term_no = (int *) xmalloc(sizeof(*new_term_no) *
214                                        p->isam_p_size);
215         if (p->term_no)
216         {
217             memcpy(new_term_no, p->isam_p_buf,
218                     p->isam_p_indx * sizeof(*p->term_no));
219             xfree(p->term_no);
220         }
221         p->term_no = new_term_no;
222 #endif
223     }
224     assert(*info == sizeof(*p->isam_p_buf));
225     memcpy(p->isam_p_buf + p->isam_p_indx, info+1, sizeof(*p->isam_p_buf));
226
227 #if 1
228     if (p->termset)
229     {
230         const char *db;
231         int set, use;
232         char term_tmp[IT_MAX_WORD];
233         int su_code = 0;
234         int len = key_SU_decode(&su_code, name);
235         
236         term_untrans(p->zh, p->reg_type, term_tmp, name+len+1);
237         yaz_log(LOG_LOG, "grep: %d %c %s", su_code, name[len], term_tmp);
238         zebraExplain_lookup_ord(p->zh->reg->zei,
239                                  su_code, &db, &set, &use);
240         yaz_log(LOG_LOG, "grep:  set=%d use=%d db=%s", set, use, db);
241         
242         resultSetAddTerm(p->zh, p->termset, name[len], db,
243                           set, use, term_tmp);
244     }
245 #endif
246     (p->isam_p_indx)++;
247 }
248
249 static int grep_handle(char *name, const char *info, void *p)
250 {
251     add_isam_p(name, info, (struct grep_info *) p);
252     return 0;
253 }
254
255 static int term_pre(ZebraMaps zebra_maps, int reg_type, const char **src,
256                      const char *ct1, const char *ct2, int first)
257 {
258     const char *s1, *s0 = *src;
259     const char **map;
260
261     /* skip white space */
262     while (*s0)
263     {
264         if (ct1 && strchr(ct1, *s0))
265             break;
266         if (ct2 && strchr(ct2, *s0))
267             break;
268         s1 = s0;
269         map = zebra_maps_input(zebra_maps, reg_type, &s1, strlen(s1), first);
270         if (**map != *CHR_SPACE)
271             break;
272         s0 = s1;
273     }
274     *src = s0;
275     return *s0;
276 }
277
278
279 static void esc_str(char *out_buf, int out_size,
280                     const char *in_buf, int in_size)
281 {
282     int k;
283
284     assert(out_buf);
285     assert(in_buf);
286     assert(out_size > 20);
287     *out_buf = '\0';
288     for (k = 0; k<in_size; k++)
289     {
290         int c = in_buf[k] & 0xff;
291         int pc;
292         if (c < 32 || c > 126)
293             pc = '?';
294         else
295             pc = c;
296         sprintf(out_buf +strlen(out_buf), "%02X:%c  ", c, pc);
297         if (strlen(out_buf) > out_size-20)
298         {
299             strcat(out_buf, "..");
300             break;
301         }
302     }
303 }
304
305 #define REGEX_CHARS " []()|.*+?!"
306
307 /* term_100: handle term, where trunc = none(no operators at all) */
308 static int term_100(ZebraMaps zebra_maps, int reg_type,
309                      const char **src, char *dst, int space_split,
310                      char *dst_term)
311 {
312     const char *s0;
313     const char **map;
314     int i = 0;
315     int j = 0;
316
317     const char *space_start = 0;
318     const char *space_end = 0;
319
320     if (!term_pre(zebra_maps, reg_type, src, NULL, NULL, !space_split))
321         return 0;
322     s0 = *src;
323     while (*s0)
324     {
325         const char *s1 = s0;
326         int q_map_match = 0;
327         map = zebra_maps_search(zebra_maps, reg_type, &s0, strlen(s0), 
328                                 &q_map_match);
329         if (space_split)
330         {
331             if (**map == *CHR_SPACE)
332                 break;
333         }
334         else  /* complete subfield only. */
335         {
336             if (**map == *CHR_SPACE)
337             {   /* save space mapping for later  .. */
338                 space_start = s1;
339                 space_end = s0;
340                 continue;
341             }
342             else if (space_start)
343             {   /* reload last space */
344                 while (space_start < space_end)
345                 {
346                     if (strchr(REGEX_CHARS, *space_start))
347                         dst[i++] = '\\';
348                     dst_term[j++] = *space_start;
349                     dst[i++] = *space_start++;
350                 }
351                 /* and reset */
352                 space_start = space_end = 0;
353             }
354         }
355         /* add non-space char */
356         memcpy(dst_term+j, s1, s0 - s1);
357         j += (s0 - s1);
358         if (!q_map_match)
359         {
360             while (s1 < s0)
361             {
362                 if (strchr(REGEX_CHARS, *s1))
363                     dst[i++] = '\\';
364                 dst[i++] = *s1++;
365             }
366         }
367         else
368         {
369             char tmpbuf[80];
370             esc_str(tmpbuf, sizeof(tmpbuf), map[0], strlen(map[0]));
371             
372             strcpy(dst + i, map[0]);
373             i += strlen(map[0]);
374         }
375     }
376     dst[i] = '\0';
377     dst_term[j] = '\0';
378     *src = s0;
379     return i;
380 }
381
382 /* term_101: handle term, where trunc = Process # */
383 static int term_101(ZebraMaps zebra_maps, int reg_type,
384                      const char **src, char *dst, int space_split,
385                      char *dst_term)
386 {
387     const char *s0;
388     const char **map;
389     int i = 0;
390     int j = 0;
391
392     if (!term_pre(zebra_maps, reg_type, src, "#", "#", !space_split))
393         return 0;
394     s0 = *src;
395     while (*s0)
396     {
397         if (*s0 == '#')
398         {
399             dst[i++] = '.';
400             dst[i++] = '*';
401             dst_term[j++] = *s0++;
402         }
403         else
404         {
405             const char *s1 = s0;
406             int q_map_match = 0;
407             map = zebra_maps_search(zebra_maps, reg_type, &s0, strlen(s0), 
408                                     &q_map_match);
409             if (space_split && **map == *CHR_SPACE)
410                 break;
411
412             /* add non-space char */
413             memcpy(dst_term+j, s1, s0 - s1);
414             j += (s0 - s1);
415             if (!q_map_match)
416             {
417                 while (s1 < s0)
418                 {
419                     if (strchr(REGEX_CHARS, *s1))
420                         dst[i++] = '\\';
421                     dst[i++] = *s1++;
422                 }
423             }
424             else
425             {
426                 char tmpbuf[80];
427                 esc_str(tmpbuf, sizeof(tmpbuf), map[0], strlen(map[0]));
428                 
429                 strcpy(dst + i, map[0]);
430                 i += strlen(map[0]);
431             }
432         }
433     }
434     dst[i] = '\0';
435     dst_term[j++] = '\0';
436     *src = s0;
437     return i;
438 }
439
440 /* term_103: handle term, where trunc = re-2 (regular expressions) */
441 static int term_103(ZebraMaps zebra_maps, int reg_type, const char **src,
442                      char *dst, int *errors, int space_split,
443                      char *dst_term)
444 {
445     int i = 0;
446     int j = 0;
447     const char *s0;
448     const char **map;
449
450     if (!term_pre(zebra_maps, reg_type, src, "^\\()[].*+?|", "(", !space_split))
451         return 0;
452     s0 = *src;
453     if (errors && *s0 == '+' && s0[1] && s0[2] == '+' && s0[3] &&
454         isdigit(((const unsigned char *)s0)[1]))
455     {
456         *errors = s0[1] - '0';
457         s0 += 3;
458         if (*errors > 3)
459             *errors = 3;
460     }
461     while (*s0)
462     {
463         if (strchr("^\\()[].*+?|-", *s0))
464         {
465             dst_term[j++] = *s0;
466             dst[i++] = *s0++;
467         }
468         else
469         {
470             const char *s1 = s0;
471             int q_map_match = 0;
472             map = zebra_maps_search(zebra_maps, reg_type, &s0, strlen(s0), 
473                                     &q_map_match);
474             if (space_split && **map == *CHR_SPACE)
475                 break;
476
477             /* add non-space char */
478             memcpy(dst_term+j, s1, s0 - s1);
479             j += (s0 - s1);
480             if (!q_map_match)
481             {
482                 while (s1 < s0)
483                 {
484                     if (strchr(REGEX_CHARS, *s1))
485                         dst[i++] = '\\';
486                     dst[i++] = *s1++;
487                 }
488             }
489             else
490             {
491                 char tmpbuf[80];
492                 esc_str(tmpbuf, sizeof(tmpbuf), map[0], strlen(map[0]));
493                 
494                 strcpy(dst + i, map[0]);
495                 i += strlen(map[0]);
496             }
497         }
498     }
499     dst[i] = '\0';
500     dst_term[j] = '\0';
501     *src = s0;
502     
503     return i;
504 }
505
506 /* term_103: handle term, where trunc = re-1 (regular expressions) */
507 static int term_102 (ZebraMaps zebra_maps, int reg_type, const char **src,
508                      char *dst, int space_split, char *dst_term)
509 {
510     return term_103(zebra_maps, reg_type, src, dst, NULL, space_split,
511                      dst_term);
512 }
513
514 /* term_104: handle term, where trunc=Process # and ! */
515 static int term_104(ZebraMaps zebra_maps, int reg_type,
516                      const char **src, char *dst, int space_split,
517                      char *dst_term)
518 {
519     const char *s0, *s1;
520     const char **map;
521     int i = 0;
522     int j = 0;
523
524     if (!term_pre(zebra_maps, reg_type, src, "?*#", "?*#", !space_split))
525         return 0;
526     s0 = *src;
527     while (*s0)
528     {
529         if (*s0 == '?')
530         {
531             dst_term[j++] = *s0++;
532             if (*s0 >= '0' && *s0 <= '9')
533             {
534                 int limit = 0;
535                 while (*s0 >= '0' && *s0 <= '9')
536                 {
537                     limit = limit * 10 + (*s0 - '0');
538                     dst_term[j++] = *s0++;
539                 }
540                 if (limit > 20)
541                     limit = 20;
542                 while (--limit >= 0)
543                 {
544                     dst[i++] = '.';
545                     dst[i++] = '?';
546                 }
547             }
548             else
549             {
550                 dst[i++] = '.';
551                 dst[i++] = '*';
552             }
553         }
554         else if (*s0 == '*')
555         {
556             dst[i++] = '.';
557             dst[i++] = '*';
558             dst_term[j++] = *s0++;
559         }
560         else if (*s0 == '#')
561         {
562             dst[i++] = '.';
563             dst_term[j++] = *s0++;
564         }
565         else
566         {
567             s1 = s0;
568             map = zebra_maps_input(zebra_maps, reg_type, &s0, strlen(s0), 0);
569             if (space_split && **map == *CHR_SPACE)
570                 break;
571             while (s1 < s0)
572             {
573                 if (strchr(REGEX_CHARS, *s1))
574                     dst[i++] = '\\';
575                 dst_term[j++] = *s1;
576                 dst[i++] = *s1++;
577             }
578         }
579     }
580     dst[i] = '\0';
581     dst_term[j++] = '\0';
582     *src = s0;
583     return i;
584 }
585
586 /* term_105/106: handle term, where trunc=Process * and ! and right trunc */
587 static int term_105 (ZebraMaps zebra_maps, int reg_type,
588                      const char **src, char *dst, int space_split,
589                      char *dst_term, int right_truncate)
590 {
591     const char *s0, *s1;
592     const char **map;
593     int i = 0;
594     int j = 0;
595
596     if (!term_pre(zebra_maps, reg_type, src, "*!", "*!", !space_split))
597         return 0;
598     s0 = *src;
599     while (*s0)
600     {
601         if (*s0 == '*')
602         {
603             dst[i++] = '.';
604             dst[i++] = '*';
605             dst_term[j++] = *s0++;
606         }
607         else if (*s0 == '!')
608         {
609             dst[i++] = '.';
610             dst_term[j++] = *s0++;
611         }
612         else
613         {
614             s1 = s0;
615             map = zebra_maps_input(zebra_maps, reg_type, &s0, strlen(s0), 0);
616             if (space_split && **map == *CHR_SPACE)
617                 break;
618             while (s1 < s0)
619             {
620                 if (strchr(REGEX_CHARS, *s1))
621                     dst[i++] = '\\';
622                 dst_term[j++] = *s1;
623                 dst[i++] = *s1++;
624             }
625         }
626     }
627     if (right_truncate)
628     {
629         dst[i++] = '.';
630         dst[i++] = '*';
631     }
632     dst[i] = '\0';
633     
634     dst_term[j++] = '\0';
635     *src = s0;
636     return i;
637 }
638
639
640 /* gen_regular_rel - generate regular expression from relation
641  *  val:     border value (inclusive)
642  *  islt:    1 if <=; 0 if >=.
643  */
644 static void gen_regular_rel(char *dst, int val, int islt)
645 {
646     int dst_p;
647     int w, d, i;
648     int pos = 0;
649     char numstr[20];
650
651     yaz_log(LOG_DEBUG, "gen_regular_rel. val=%d, islt=%d", val, islt);
652     if (val >= 0)
653     {
654         if (islt)
655             strcpy(dst, "(-[0-9]+|(");
656         else
657             strcpy(dst, "((");
658     } 
659     else
660     {
661         if (!islt)
662         {
663             strcpy(dst, "([0-9]+|-(");
664             dst_p = strlen(dst);
665             islt = 1;
666         }
667         else
668         {
669             strcpy(dst, "(-(");
670             islt = 0;
671         }
672         val = -val;
673     }
674     dst_p = strlen(dst);
675     sprintf(numstr, "%d", val);
676     for (w = strlen(numstr); --w >= 0; pos++)
677     {
678         d = numstr[w];
679         if (pos > 0)
680         {
681             if (islt)
682             {
683                 if (d == '0')
684                     continue;
685                 d--;
686             } 
687             else
688             {
689                 if (d == '9')
690                     continue;
691                 d++;
692             }
693         }
694         
695         strcpy(dst + dst_p, numstr);
696         dst_p = strlen(dst) - pos - 1;
697
698         if (islt)
699         {
700             if (d != '0')
701             {
702                 dst[dst_p++] = '[';
703                 dst[dst_p++] = '0';
704                 dst[dst_p++] = '-';
705                 dst[dst_p++] = d;
706                 dst[dst_p++] = ']';
707             }
708             else
709                 dst[dst_p++] = d;
710         }
711         else
712         {
713             if (d != '9')
714             { 
715                 dst[dst_p++] = '[';
716                 dst[dst_p++] = d;
717                 dst[dst_p++] = '-';
718                 dst[dst_p++] = '9';
719                 dst[dst_p++] = ']';
720             }
721             else
722                 dst[dst_p++] = d;
723         }
724         for (i = 0; i<pos; i++)
725         {
726             dst[dst_p++] = '[';
727             dst[dst_p++] = '0';
728             dst[dst_p++] = '-';
729             dst[dst_p++] = '9';
730             dst[dst_p++] = ']';
731         }
732         dst[dst_p++] = '|';
733     }
734     dst[dst_p] = '\0';
735     if (islt)
736     {
737         /* match everything less than 10^(pos-1) */
738         strcat(dst, "0*");
739         for (i = 1; i<pos; i++)
740             strcat(dst, "[0-9]?");
741     }
742     else
743     {
744         /* match everything greater than 10^pos */
745         for (i = 0; i <= pos; i++)
746             strcat(dst, "[0-9]");
747         strcat(dst, "[0-9]*");
748     }
749     strcat(dst, "))");
750 }
751
752 void string_rel_add_char(char **term_p, const char *src, int *indx)
753 {
754     if (src[*indx] == '\\')
755         *(*term_p)++ = src[(*indx)++];
756     *(*term_p)++ = src[(*indx)++];
757 }
758
759 /*
760  *   >  abc     ([b-].*|a[c-].*|ab[d-].*|abc.+)
761  *              ([^-a].*|a[^-b].*ab[^-c].*|abc.+)
762  *   >= abc     ([b-].*|a[c-].*|ab[c-].*)
763  *              ([^-a].*|a[^-b].*|ab[c-].*)
764  *   <  abc     ([-0].*|a[-a].*|ab[-b].*)
765  *              ([^a-].*|a[^b-].*|ab[^c-].*)
766  *   <= abc     ([-0].*|a[-a].*|ab[-b].*|abc)
767  *              ([^a-].*|a[^b-].*|ab[^c-].*|abc)
768  */
769 static int string_relation(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
770                             const char **term_sub, char *term_dict,
771                             oid_value attributeSet,
772                             int reg_type, int space_split, char *term_dst)
773 {
774     AttrType relation;
775     int relation_value;
776     int i;
777     char *term_tmp = term_dict + strlen(term_dict);
778     char term_component[2*IT_MAX_WORD+20];
779
780     attr_init(&relation, zapt, 2);
781     relation_value = attr_find(&relation, NULL);
782
783     yaz_log(LOG_DEBUG, "string relation value=%d", relation_value);
784     switch (relation_value)
785     {
786     case 1:
787         if (!term_100 (zh->reg->zebra_maps, reg_type,
788                        term_sub, term_component,
789                        space_split, term_dst))
790             return 0;
791         yaz_log(LOG_DEBUG, "Relation <");
792         
793         *term_tmp++ = '(';
794         for (i = 0; term_component[i]; )
795         {
796             int j = 0;
797
798             if (i)
799                 *term_tmp++ = '|';
800             while (j < i)
801                 string_rel_add_char (&term_tmp, term_component, &j);
802
803             *term_tmp++ = '[';
804
805             *term_tmp++ = '^';
806             string_rel_add_char (&term_tmp, term_component, &i);
807             *term_tmp++ = '-';
808
809             *term_tmp++ = ']';
810             *term_tmp++ = '.';
811             *term_tmp++ = '*';
812
813             if ((term_tmp - term_dict) > IT_MAX_WORD)
814                 break;
815         }
816         *term_tmp++ = ')';
817         *term_tmp = '\0';
818         break;
819     case 2:
820         if (!term_100 (zh->reg->zebra_maps, reg_type,
821                        term_sub, term_component,
822                        space_split, term_dst))
823             return 0;
824         yaz_log(LOG_DEBUG, "Relation <=");
825
826         *term_tmp++ = '(';
827         for (i = 0; term_component[i]; )
828         {
829             int j = 0;
830
831             while (j < i)
832                 string_rel_add_char (&term_tmp, term_component, &j);
833             *term_tmp++ = '[';
834
835             *term_tmp++ = '^';
836             string_rel_add_char (&term_tmp, term_component, &i);
837             *term_tmp++ = '-';
838
839             *term_tmp++ = ']';
840             *term_tmp++ = '.';
841             *term_tmp++ = '*';
842
843             *term_tmp++ = '|';
844
845             if ((term_tmp - term_dict) > IT_MAX_WORD)
846                 break;
847         }
848         for (i = 0; term_component[i]; )
849             string_rel_add_char (&term_tmp, term_component, &i);
850         *term_tmp++ = ')';
851         *term_tmp = '\0';
852         break;
853     case 5:
854         if (!term_100 (zh->reg->zebra_maps, reg_type,
855                        term_sub, term_component, space_split, term_dst))
856             return 0;
857         yaz_log(LOG_DEBUG, "Relation >");
858
859         *term_tmp++ = '(';
860         for (i = 0; term_component[i];)
861         {
862             int j = 0;
863
864             while (j < i)
865                 string_rel_add_char (&term_tmp, term_component, &j);
866             *term_tmp++ = '[';
867             
868             *term_tmp++ = '^';
869             *term_tmp++ = '-';
870             string_rel_add_char (&term_tmp, term_component, &i);
871
872             *term_tmp++ = ']';
873             *term_tmp++ = '.';
874             *term_tmp++ = '*';
875
876             *term_tmp++ = '|';
877
878             if ((term_tmp - term_dict) > IT_MAX_WORD)
879                 break;
880         }
881         for (i = 0; term_component[i];)
882             string_rel_add_char (&term_tmp, term_component, &i);
883         *term_tmp++ = '.';
884         *term_tmp++ = '+';
885         *term_tmp++ = ')';
886         *term_tmp = '\0';
887         break;
888     case 4:
889         if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub,
890                        term_component, space_split, term_dst))
891             return 0;
892         yaz_log(LOG_DEBUG, "Relation >=");
893
894         *term_tmp++ = '(';
895         for (i = 0; term_component[i];)
896         {
897             int j = 0;
898
899             if (i)
900                 *term_tmp++ = '|';
901             while (j < i)
902                 string_rel_add_char (&term_tmp, term_component, &j);
903             *term_tmp++ = '[';
904
905             if (term_component[i+1])
906             {
907                 *term_tmp++ = '^';
908                 *term_tmp++ = '-';
909                 string_rel_add_char (&term_tmp, term_component, &i);
910             }
911             else
912             {
913                 string_rel_add_char (&term_tmp, term_component, &i);
914                 *term_tmp++ = '-';
915             }
916             *term_tmp++ = ']';
917             *term_tmp++ = '.';
918             *term_tmp++ = '*';
919
920             if ((term_tmp - term_dict) > IT_MAX_WORD)
921                 break;
922         }
923         *term_tmp++ = ')';
924         *term_tmp = '\0';
925         break;
926     case 3:
927     default:
928         yaz_log(LOG_DEBUG, "Relation =");
929         if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub,
930                        term_component, space_split, term_dst))
931             return 0;
932         strcat (term_tmp, "(");
933         strcat (term_tmp, term_component);
934         strcat (term_tmp, ")");
935     }
936     return 1;
937 }
938
939 static int string_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
940                         const char **term_sub, 
941                         oid_value attributeSet, NMEM stream,
942                         struct grep_info *grep_info,
943                         int reg_type, int complete_flag,
944                         int num_bases, char **basenames,
945                         char *term_dst, int xpath_use);
946
947 static RSET term_trunc (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
948                         const char **term_sub, 
949                         oid_value attributeSet, NMEM stream,
950                         struct grep_info *grep_info,
951                         int reg_type, int complete_flag,
952                         int num_bases, char **basenames,
953                         char *term_dst,
954                         const char *rank_type, int xpath_use)
955 {
956     int r;
957     grep_info->isam_p_indx = 0;
958     r = string_term (zh, zapt, term_sub, attributeSet, stream, grep_info,
959                      reg_type, complete_flag, num_bases, basenames,
960                      term_dst, xpath_use);
961     if (r < 1)
962         return 0;
963     yaz_log(LOG_DEBUG, "term: %s", term_dst);
964     return rset_trunc (zh, grep_info->isam_p_buf,
965                        grep_info->isam_p_indx, term_dst,
966                        strlen(term_dst), rank_type, 1 /* preserve pos */,
967                        zapt->term->which);
968 }
969
970 static char *nmem_strdup_i(NMEM nmem, int v)
971 {
972     char val_str[64];
973     sprintf (val_str, "%d", v);
974     return nmem_strdup (nmem, val_str);
975 }
976     
977 static int string_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
978                         const char **term_sub, 
979                         oid_value attributeSet, NMEM stream,
980                         struct grep_info *grep_info,
981                         int reg_type, int complete_flag,
982                         int num_bases, char **basenames,
983                         char *term_dst, int xpath_use)
984 {
985     char term_dict[2*IT_MAX_WORD+4000];
986     int j, r, base_no;
987     AttrType truncation;
988     int truncation_value;
989     AttrType use;
990     int use_value;
991     const char *use_string = 0;
992     oid_value curAttributeSet = attributeSet;
993     const char *termp;
994     struct rpn_char_map_info rcmi;
995     int space_split = complete_flag ? 0 : 1;
996
997     int bases_ok = 0;     /* no of databases with OK attribute */
998     int errCode = 0;      /* err code (if any is not OK) */
999     char *errString = 0;  /* addinfo */
1000
1001     rpn_char_map_prepare (zh->reg, reg_type, &rcmi);
1002     attr_init (&use, zapt, 1);
1003     use_value = attr_find_ex (&use, &curAttributeSet, &use_string);
1004     yaz_log(LOG_DEBUG, "string_term, use value %d", use_value);
1005     attr_init (&truncation, zapt, 5);
1006     truncation_value = attr_find (&truncation, NULL);
1007     yaz_log(LOG_DEBUG, "truncation value %d", truncation_value);
1008
1009     if (use_value == -1)    /* no attribute - assumy "any" */
1010         use_value = 1016;
1011     for (base_no = 0; base_no < num_bases; base_no++)
1012     {
1013         int attr_ok = 0;
1014         int regex_range = 0;
1015         int init_pos = 0;
1016         attent attp;
1017         data1_local_attribute id_xpath_attr;
1018         data1_local_attribute *local_attr;
1019         int max_pos, prefix_len = 0;
1020
1021         termp = *term_sub;
1022
1023         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
1024         {
1025             zh->errCode = 109; /* Database unavailable */
1026             zh->errString = basenames[base_no];
1027             return -1;
1028         }
1029         if (xpath_use > 0 && use_value == -2) 
1030         {
1031             use_value = xpath_use;
1032             attp.local_attributes = &id_xpath_attr;
1033             attp.attset_ordinal = VAL_IDXPATH;
1034             id_xpath_attr.next = 0;
1035             id_xpath_attr.local = use_value;
1036         }
1037         else if (curAttributeSet == VAL_IDXPATH)
1038         {
1039             attp.local_attributes = &id_xpath_attr;
1040             attp.attset_ordinal = VAL_IDXPATH;
1041             id_xpath_attr.next = 0;
1042             id_xpath_attr.local = use_value;
1043         }
1044         else
1045         {
1046             if ((r=att_getentbyatt (zh, &attp, curAttributeSet, use_value,
1047                                             use_string)))
1048             {
1049                 yaz_log(LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
1050                       curAttributeSet, use_value, r);
1051                 if (r == -1)
1052                 {
1053                     /* set was found, but value wasn't defined */
1054                     errCode = 114;
1055                     if (use_string)
1056                         errString = nmem_strdup(stream, use_string);
1057                     else
1058                         errString = nmem_strdup_i(stream, use_value);
1059                 }
1060                 else
1061                 {
1062                     int oid[OID_SIZE];
1063                     struct oident oident;
1064                     
1065                     oident.proto = PROTO_Z3950;
1066                     oident.oclass = CLASS_ATTSET;
1067                     oident.value = curAttributeSet;
1068                     oid_ent_to_oid (&oident, oid);
1069                     
1070                     errCode = 121;
1071                     errString = nmem_strdup (stream, oident.desc);
1072                 }
1073                 continue;
1074             }
1075         }
1076         for (local_attr = attp.local_attributes; local_attr;
1077              local_attr = local_attr->next)
1078         {
1079             int ord;
1080             char ord_buf[32];
1081             int i, ord_len;
1082             
1083             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
1084                                          local_attr->local);
1085             if (ord < 0)
1086                 continue;
1087             if (prefix_len)
1088                 term_dict[prefix_len++] = '|';
1089             else
1090                 term_dict[prefix_len++] = '(';
1091             
1092             ord_len = key_SU_encode (ord, ord_buf);
1093             for (i = 0; i<ord_len; i++)
1094             {
1095                 term_dict[prefix_len++] = 1;
1096                 term_dict[prefix_len++] = ord_buf[i];
1097             }
1098         }
1099         if (!prefix_len)
1100         {
1101 #if 1
1102             bases_ok++;
1103 #else
1104             errCode = 114;
1105             errString = nmem_strdup_i(stream, use_value);
1106             continue;
1107 #endif
1108         }
1109         else
1110         {
1111             attr_ok = 1;
1112             bases_ok++; /* this has OK attributes */
1113         }
1114
1115         term_dict[prefix_len++] = ')';
1116         term_dict[prefix_len++] = 1;
1117         term_dict[prefix_len++] = reg_type;
1118         yaz_log(LOG_DEBUG, "reg_type = %d", term_dict[prefix_len-1]);
1119         term_dict[prefix_len] = '\0';
1120         j = prefix_len;
1121         switch (truncation_value)
1122         {
1123         case -1:         /* not specified */
1124         case 100:        /* do not truncate */
1125             if (!string_relation (zh, zapt, &termp, term_dict,
1126                                   attributeSet,
1127                                   reg_type, space_split, term_dst))
1128                 return 0;
1129             break;
1130         case 1:          /* right truncation */
1131             term_dict[j++] = '(';
1132             if (!term_100 (zh->reg->zebra_maps, reg_type,
1133                            &termp, term_dict + j, space_split, term_dst))
1134                 return 0;
1135             strcat (term_dict, ".*)");
1136             break;
1137         case 2:          /* keft truncation */
1138             term_dict[j++] = '('; term_dict[j++] = '.'; term_dict[j++] = '*';
1139             if (!term_100 (zh->reg->zebra_maps, reg_type,
1140                            &termp, term_dict + j, space_split, term_dst))
1141                 return 0;
1142             strcat (term_dict, ")");
1143             break;
1144         case 3:          /* left&right truncation */
1145             term_dict[j++] = '('; term_dict[j++] = '.'; term_dict[j++] = '*';
1146             if (!term_100 (zh->reg->zebra_maps, reg_type,
1147                            &termp, term_dict + j, space_split, term_dst))
1148                 return 0;
1149             strcat (term_dict, ".*)");
1150             break;
1151         case 101:        /* process # in term */
1152             term_dict[j++] = '(';
1153             if (!term_101 (zh->reg->zebra_maps, reg_type,
1154                            &termp, term_dict + j, space_split, term_dst))
1155                 return 0;
1156             strcat (term_dict, ")");
1157             break;
1158         case 102:        /* Regexp-1 */
1159             term_dict[j++] = '(';
1160             if (!term_102 (zh->reg->zebra_maps, reg_type,
1161                            &termp, term_dict + j, space_split, term_dst))
1162                 return 0;
1163             strcat (term_dict, ")");
1164             break;
1165         case 103:       /* Regexp-2 */
1166             r = 1;
1167             term_dict[j++] = '(';
1168             init_pos = 2;
1169             if (!term_103 (zh->reg->zebra_maps, reg_type,
1170                            &termp, term_dict + j, &regex_range,
1171                            space_split, term_dst))
1172                 return 0;
1173             strcat (term_dict, ")");
1174             break;
1175         case 104:        /* process # and ! in term */
1176             term_dict[j++] = '(';
1177             if (!term_104 (zh->reg->zebra_maps, reg_type,
1178                            &termp, term_dict + j, space_split, term_dst))
1179                 return 0;
1180             strcat (term_dict, ")");
1181             break;
1182         case 105:        /* process * and ! in term */
1183             term_dict[j++] = '(';
1184             if (!term_105 (zh->reg->zebra_maps, reg_type,
1185                            &termp, term_dict + j, space_split, term_dst, 1))
1186                 return 0;
1187             strcat (term_dict, ")");
1188             break;
1189         case 106:        /* process * and ! in term */
1190             term_dict[j++] = '(';
1191             if (!term_105 (zh->reg->zebra_maps, reg_type,
1192                            &termp, term_dict + j, space_split, term_dst, 0))
1193                 return 0;
1194             strcat (term_dict, ")");
1195             break;
1196         default:
1197             zh->errCode = 120;
1198             zh->errString = nmem_strdup_i(stream, truncation_value);
1199             return -1;
1200         }
1201         if (attr_ok)
1202         {
1203             yaz_log(LOG_DEBUG, "dict_lookup_grep: %s", term_dict+prefix_len);
1204             r = dict_lookup_grep (zh->reg->dict, term_dict, regex_range,
1205                                   grep_info, &max_pos, init_pos,
1206                                   grep_handle);
1207             if (r)
1208                 yaz_log(LOG_WARN, "dict_lookup_grep fail %d", r);
1209         }
1210     }
1211     if (!bases_ok)
1212     {
1213         zh->errCode = errCode;
1214         zh->errString = errString;
1215         return -1;
1216     }
1217     *term_sub = termp;
1218     yaz_log(LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1219     return 1;
1220 }
1221
1222
1223 /* convert APT search term to UTF8 */
1224 static int zapt_term_to_utf8 (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1225                               char *termz)
1226 {
1227     size_t sizez;
1228     Z_Term *term = zapt->term;
1229
1230     switch (term->which)
1231     {
1232     case Z_Term_general:
1233         if (zh->iconv_to_utf8 != 0)
1234         {
1235             char *inbuf = term->u.general->buf;
1236             size_t inleft = term->u.general->len;
1237             char *outbuf = termz;
1238             size_t outleft = IT_MAX_WORD-1;
1239             size_t ret;
1240
1241             ret = yaz_iconv(zh->iconv_to_utf8, &inbuf, &inleft,
1242                         &outbuf, &outleft);
1243             if (ret == (size_t)(-1))
1244             {
1245                 ret = yaz_iconv(zh->iconv_to_utf8, 0, 0, 0, 0);
1246                 zh->errCode = 125;
1247                 return -1;
1248             }
1249             *outbuf = 0;
1250         }
1251         else
1252         {
1253             sizez = term->u.general->len;
1254             if (sizez > IT_MAX_WORD-1)
1255                 sizez = IT_MAX_WORD-1;
1256             memcpy (termz, term->u.general->buf, sizez);
1257             termz[sizez] = '\0';
1258         }
1259         break;
1260     case Z_Term_characterString:
1261         sizez = strlen(term->u.characterString);
1262         if (sizez > IT_MAX_WORD-1)
1263             sizez = IT_MAX_WORD-1;
1264         memcpy (termz, term->u.characterString, sizez);
1265         termz[sizez] = '\0';
1266         break;
1267     default:
1268         zh->errCode = 124;
1269         return -1;
1270     }
1271     return 0;
1272 }
1273
1274 /* convert APT SCAN term to internal cmap */
1275 static int trans_scan_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1276                             char *termz, int reg_type)
1277 {
1278     char termz0[IT_MAX_WORD];
1279
1280     if (zapt_term_to_utf8(zh, zapt, termz0))
1281         return -1;    /* error */
1282     else
1283     {
1284         const char **map;
1285         const char *cp = (const char *) termz0;
1286         const char *cp_end = cp + strlen(cp);
1287         const char *src;
1288         int i = 0;
1289         const char *space_map = NULL;
1290         int len;
1291             
1292         while ((len = (cp_end - cp)) > 0)
1293         {
1294             map = zebra_maps_input (zh->reg->zebra_maps, reg_type, &cp, len, 0);
1295             if (**map == *CHR_SPACE)
1296                 space_map = *map;
1297             else
1298             {
1299                 if (i && space_map)
1300                     for (src = space_map; *src; src++)
1301                         termz[i++] = *src;
1302                 space_map = NULL;
1303                 for (src = *map; *src; src++)
1304                     termz[i++] = *src;
1305             }
1306         }
1307         termz[i] = '\0';
1308     }
1309     return 0;
1310 }
1311
1312 char *normalize_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1313                      const char *termz, NMEM stream, unsigned reg_id)
1314 {
1315     WRBUF wrbuf = 0;
1316     AttrType truncation;
1317     int truncation_value;
1318     char *ex_list = 0;
1319
1320     attr_init (&truncation, zapt, 5);
1321     truncation_value = attr_find (&truncation, NULL);
1322
1323     switch (truncation_value)
1324     {
1325     default:
1326         ex_list = "";
1327         break;
1328     case 101:
1329         ex_list = "#";
1330         break;
1331     case 102:
1332     case 103:
1333         ex_list = 0;
1334         break;
1335     case 104:
1336         ex_list = "!#";
1337         break;
1338     case 105:
1339         ex_list = "!*";
1340         break;
1341     }
1342     if (ex_list)
1343         wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, ex_list,
1344                               termz, strlen(termz));
1345     if (!wrbuf)
1346         return nmem_strdup(stream, termz);
1347     else
1348     {
1349         char *buf = (char*) nmem_malloc (stream, wrbuf_len(wrbuf)+1);
1350         memcpy (buf, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
1351         buf[wrbuf_len(wrbuf)] = '\0';
1352         return buf;
1353     }
1354 }
1355
1356 static void grep_info_delete (struct grep_info *grep_info)
1357 {
1358 #ifdef TERM_COUNT
1359     xfree(grep_info->term_no);
1360 #endif
1361     xfree (grep_info->isam_p_buf);
1362 }
1363
1364 static int grep_info_prepare (ZebraHandle zh,
1365                               Z_AttributesPlusTerm *zapt,
1366                               struct grep_info *grep_info,
1367                               int reg_type,
1368                               NMEM stream)
1369 {
1370     AttrType termset;
1371     int termset_value_numeric;
1372     const char *termset_value_string;
1373
1374 #ifdef TERM_COUNT
1375     grep_info->term_no = 0;
1376 #endif
1377     grep_info->isam_p_size = 0;
1378     grep_info->isam_p_buf = NULL;
1379     grep_info->zh = zh;
1380     grep_info->reg_type = reg_type;
1381     grep_info->termset = 0;
1382
1383     if (!zapt)
1384         return 0;
1385     attr_init (&termset, zapt, 8);
1386     termset_value_numeric =
1387         attr_find_ex (&termset, NULL, &termset_value_string);
1388     if (termset_value_numeric != -1)
1389     {
1390         char resname[32];
1391         const char *termset_name = 0;
1392         if (termset_value_numeric != -2)
1393         {
1394             sprintf (resname, "%d", termset_value_numeric);
1395             termset_name = resname;
1396         }
1397         else
1398             termset_name = termset_value_string;
1399         yaz_log(LOG_LOG, "creating termset set %s", termset_name);
1400         grep_info->termset = resultSetAdd (zh, termset_name, 1);
1401         if (!grep_info->termset)
1402         {
1403             zh->errCode = 128;
1404             zh->errString = nmem_strdup (stream, termset_name);
1405             return -1;
1406         }
1407     }
1408     return 0;
1409 }
1410                                
1411
1412 static RSET rpn_search_APT_phrase (ZebraHandle zh,
1413                                    Z_AttributesPlusTerm *zapt,
1414                                    const char *termz_org,
1415                                    oid_value attributeSet,
1416                                    NMEM stream,
1417                                    int reg_type, int complete_flag,
1418                                    const char *rank_type, int xpath_use,
1419                                    int num_bases, char **basenames)
1420 {
1421     char term_dst[IT_MAX_WORD+1];
1422     RSET rset[60], result;
1423     int  rset_no = 0;
1424     struct grep_info grep_info;
1425     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1426     const char *termp = termz;
1427
1428     *term_dst = 0;
1429     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1430         return 0;
1431     while (1)
1432     { 
1433         yaz_log(LOG_DEBUG, "APT_phrase termp=%s", termp);
1434         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1435                                     stream, &grep_info,
1436                                     reg_type, complete_flag,
1437                                     num_bases, basenames,
1438                                     term_dst, rank_type,
1439                                     xpath_use);
1440         if (!rset[rset_no])
1441             break;
1442         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1443             break;
1444     }
1445     grep_info_delete (&grep_info);
1446     if (rset_no == 0)
1447     {
1448         rset_null_parms parms;
1449         
1450         parms.rset_term = rset_term_create (termz, -1, rank_type,
1451                                             zapt->term->which);
1452         return rset_create (rset_kind_null, &parms);
1453     }
1454     else if (rset_no == 1)
1455         return (rset[0]);
1456     else
1457     {
1458         /* new / old prox */
1459         rset_prox_parms parms;
1460         
1461         parms.rset = rset;
1462         parms.rset_no = rset_no;
1463         parms.ordered = 1;
1464         parms.exclusion = 0;
1465         parms.relation = 3;
1466         parms.distance = 1;
1467         parms.key_size = sizeof(struct it_key);
1468         parms.cmp = key_compare_it;
1469         parms.getseq = key_get_seq;
1470         parms.log_item = key_logdump_txt;
1471         result = rset_create(rset_kind_prox, &parms);
1472     }
1473     return result;
1474 }
1475
1476 static RSET rpn_search_APT_or_list (ZebraHandle zh,
1477                                     Z_AttributesPlusTerm *zapt,
1478                                     const char *termz_org,
1479                                     oid_value attributeSet,
1480                                     NMEM stream,
1481                                     int reg_type, int complete_flag,
1482                                     const char *rank_type,
1483                                     int xpath_use,
1484                                     int num_bases, char **basenames)
1485 {
1486     char term_dst[IT_MAX_WORD+1];
1487     RSET rset[60], result;
1488     int i, rset_no = 0;
1489     struct grep_info grep_info;
1490     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1491     const char *termp = termz;
1492
1493     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1494         return 0;
1495     while (1)
1496     { 
1497         yaz_log(LOG_DEBUG, "APT_or_list termp=%s", termp);
1498         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1499                                     stream, &grep_info,
1500                                     reg_type, complete_flag,
1501                                     num_bases, basenames,
1502                                     term_dst, rank_type,
1503                                     xpath_use);
1504         if (!rset[rset_no])
1505             break;
1506         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1507             break;
1508     }
1509     grep_info_delete (&grep_info);
1510     if (rset_no == 0)
1511     {
1512         rset_null_parms parms;
1513         
1514         parms.rset_term = rset_term_create (termz, -1, rank_type,
1515                                             zapt->term->which);
1516         return rset_create (rset_kind_null, &parms);
1517     }
1518     result = rset[0];
1519     for (i = 1; i<rset_no; i++)
1520     {
1521         rset_bool_parms bool_parms;
1522
1523         bool_parms.rset_l = result;
1524         bool_parms.rset_r = rset[i];
1525         bool_parms.key_size = sizeof(struct it_key);
1526         bool_parms.cmp = key_compare_it;
1527         bool_parms.log_item = key_logdump_txt;
1528         result = rset_create (rset_kind_or, &bool_parms);
1529     }
1530     return result;
1531 }
1532
1533 static RSET rpn_search_APT_and_list (ZebraHandle zh,
1534                                      Z_AttributesPlusTerm *zapt,
1535                                      const char *termz_org,
1536                                      oid_value attributeSet,
1537                                      NMEM stream,
1538                                      int reg_type, int complete_flag,
1539                                      const char *rank_type, 
1540                                      int xpath_use,
1541                                      int num_bases, char **basenames)
1542 {
1543     char term_dst[IT_MAX_WORD+1];
1544     RSET rset[60], result;
1545     int i, rset_no = 0;
1546     struct grep_info grep_info;
1547     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1548     const char *termp = termz;
1549
1550     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1551         return 0;
1552     while (1)
1553     { 
1554         yaz_log(LOG_DEBUG, "APT_and_list termp=%s", termp);
1555         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1556                                     stream, &grep_info,
1557                                     reg_type, complete_flag,
1558                                     num_bases, basenames,
1559                                     term_dst, rank_type,
1560                                     xpath_use);
1561         if (!rset[rset_no])
1562             break;
1563         assert (rset[rset_no]);
1564         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1565             break;
1566     }
1567     grep_info_delete (&grep_info);
1568     if (rset_no == 0)
1569     {
1570         rset_null_parms parms;
1571         
1572         parms.rset_term = rset_term_create (termz, -1, rank_type,
1573                                             zapt->term->which);
1574         return rset_create (rset_kind_null, &parms);
1575     }
1576     result = rset[0];
1577     for (i = 1; i<rset_no; i++)
1578     {
1579         rset_bool_parms bool_parms;
1580
1581         bool_parms.rset_l = result;
1582         bool_parms.rset_r = rset[i];
1583         bool_parms.key_size = sizeof(struct it_key);
1584         bool_parms.cmp = key_compare_it;
1585         bool_parms.log_item = key_logdump_txt;
1586         result = rset_create (rset_kind_and_forward, &bool_parms);
1587     }
1588     return result;
1589 }
1590
1591 static int numeric_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1592                              const char **term_sub,
1593                              char *term_dict,
1594                              oid_value attributeSet,
1595                              struct grep_info *grep_info,
1596                              int *max_pos,
1597                              int reg_type,
1598                              char *term_dst)
1599 {
1600     AttrType relation;
1601     int relation_value;
1602     int term_value;
1603     int r;
1604     char *term_tmp = term_dict + strlen(term_dict);
1605
1606     attr_init (&relation, zapt, 2);
1607     relation_value = attr_find (&relation, NULL);
1608
1609     yaz_log(LOG_DEBUG, "numeric relation value=%d", relation_value);
1610
1611     if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub, term_tmp, 1,
1612                    term_dst))
1613         return 0;
1614     term_value = atoi (term_tmp);
1615     switch (relation_value)
1616     {
1617     case 1:
1618         yaz_log(LOG_DEBUG, "Relation <");
1619         gen_regular_rel (term_tmp, term_value-1, 1);
1620         break;
1621     case 2:
1622         yaz_log(LOG_DEBUG, "Relation <=");
1623         gen_regular_rel (term_tmp, term_value, 1);
1624         break;
1625     case 4:
1626         yaz_log(LOG_DEBUG, "Relation >=");
1627         gen_regular_rel (term_tmp, term_value, 0);
1628         break;
1629     case 5:
1630         yaz_log(LOG_DEBUG, "Relation >");
1631         gen_regular_rel (term_tmp, term_value+1, 0);
1632         break;
1633     case 3:
1634     default:
1635         yaz_log(LOG_DEBUG, "Relation =");
1636         sprintf (term_tmp, "(0*%d)", term_value);
1637     }
1638     yaz_log(LOG_DEBUG, "dict_lookup_grep: %s", term_tmp);
1639     r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info, max_pos,
1640                           0, grep_handle);
1641     if (r)
1642         yaz_log(LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
1643     yaz_log(LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1644     return 1;
1645 }
1646
1647 static int numeric_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1648                          const char **term_sub, 
1649                          oid_value attributeSet, struct grep_info *grep_info,
1650                          int reg_type, int complete_flag,
1651                          int num_bases, char **basenames,
1652                          char *term_dst, int xpath_use, NMEM stream)
1653 {
1654     char term_dict[2*IT_MAX_WORD+2];
1655     int r, base_no;
1656     AttrType use;
1657     int use_value;
1658     const char *use_string = 0;
1659     oid_value curAttributeSet = attributeSet;
1660     const char *termp;
1661     struct rpn_char_map_info rcmi;
1662
1663     int bases_ok = 0;     /* no of databases with OK attribute */
1664     int errCode = 0;      /* err code (if any is not OK) */
1665     char *errString = 0;  /* addinfo */
1666
1667     rpn_char_map_prepare (zh->reg, reg_type, &rcmi);
1668     attr_init (&use, zapt, 1);
1669     use_value = attr_find_ex (&use, &curAttributeSet, &use_string);
1670
1671     if (use_value == -1)
1672         use_value = 1016;
1673
1674     for (base_no = 0; base_no < num_bases; base_no++)
1675     {
1676         attent attp;
1677         data1_local_attribute id_xpath_attr;
1678         data1_local_attribute *local_attr;
1679         int max_pos, prefix_len = 0;
1680
1681         termp = *term_sub;
1682         if (use_value == -2)  /* string attribute (assume IDXPATH/any) */
1683         {
1684             use_value = xpath_use;
1685             attp.local_attributes = &id_xpath_attr;
1686             attp.attset_ordinal = VAL_IDXPATH;
1687             id_xpath_attr.next = 0;
1688             id_xpath_attr.local = use_value;
1689         }
1690         else if (curAttributeSet == VAL_IDXPATH)
1691         {
1692             attp.local_attributes = &id_xpath_attr;
1693             attp.attset_ordinal = VAL_IDXPATH;
1694             id_xpath_attr.next = 0;
1695             id_xpath_attr.local = use_value;
1696         }
1697         else
1698         {
1699             if ((r=att_getentbyatt (zh, &attp, curAttributeSet, use_value,
1700                                             use_string)))
1701             {
1702                 yaz_log(LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
1703                       curAttributeSet, use_value, r);
1704                 if (r == -1)
1705                 {
1706                     errString = nmem_strdup_i (stream, use_value);
1707                     errCode = 114;
1708                 }
1709                 else
1710                     errCode = 121;
1711                 continue;
1712             }
1713         }
1714         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
1715         {
1716             zh->errCode = 109; /* Database unavailable */
1717             zh->errString = basenames[base_no];
1718             return -1;
1719         }
1720         for (local_attr = attp.local_attributes; local_attr;
1721              local_attr = local_attr->next)
1722         {
1723             int ord;
1724             char ord_buf[32];
1725             int i, ord_len;
1726
1727             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
1728                                           local_attr->local);
1729             if (ord < 0)
1730                 continue;
1731             if (prefix_len)
1732                 term_dict[prefix_len++] = '|';
1733             else
1734                 term_dict[prefix_len++] = '(';
1735
1736             ord_len = key_SU_encode (ord, ord_buf);
1737             for (i = 0; i<ord_len; i++)
1738             {
1739                 term_dict[prefix_len++] = 1;
1740                 term_dict[prefix_len++] = ord_buf[i];
1741             }
1742         }
1743         if (!prefix_len)
1744         {
1745             char val_str[32];
1746             sprintf (val_str, "%d", use_value);
1747             errCode = 114;
1748             errString = nmem_strdup (stream, val_str);
1749             continue;
1750         }
1751         bases_ok++;
1752         term_dict[prefix_len++] = ')';        
1753         term_dict[prefix_len++] = 1;
1754         term_dict[prefix_len++] = reg_type;
1755         yaz_log(LOG_DEBUG, "reg_type = %d", term_dict[prefix_len-1]);
1756         term_dict[prefix_len] = '\0';
1757         if (!numeric_relation (zh, zapt, &termp, term_dict,
1758                                attributeSet, grep_info, &max_pos, reg_type,
1759                                term_dst))
1760             return 0;
1761     }
1762     if (!bases_ok)
1763     {
1764         zh->errCode = errCode;
1765         zh->errString = errString;
1766         return -1;
1767     }
1768     *term_sub = termp;
1769     yaz_log(LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1770     return 1;
1771 }
1772
1773 static RSET rpn_search_APT_numeric (ZebraHandle zh,
1774                                     Z_AttributesPlusTerm *zapt,
1775                                     const char *termz,
1776                                     oid_value attributeSet,
1777                                     NMEM stream,
1778                                     int reg_type, int complete_flag,
1779                                     const char *rank_type, int xpath_use,
1780                                     int num_bases, char **basenames)
1781 {
1782     char term_dst[IT_MAX_WORD+1];
1783     const char *termp = termz;
1784     RSET rset[60], result;
1785     int i, r, rset_no = 0;
1786     struct grep_info grep_info;
1787
1788     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1789         return 0;
1790     while (1)
1791     { 
1792         yaz_log(LOG_DEBUG, "APT_numeric termp=%s", termp);
1793         grep_info.isam_p_indx = 0;
1794         r = numeric_term (zh, zapt, &termp, attributeSet, &grep_info,
1795                           reg_type, complete_flag, num_bases, basenames,
1796                           term_dst, xpath_use,
1797                           stream);
1798         if (r < 1)
1799             break;
1800         yaz_log(LOG_DEBUG, "term: %s", term_dst);
1801         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
1802                                     grep_info.isam_p_indx, term_dst,
1803                                     strlen(term_dst), rank_type,
1804                                     0 /* preserve position */,
1805                                     zapt->term->which);
1806         assert (rset[rset_no]);
1807         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1808             break;
1809     }
1810     grep_info_delete (&grep_info);
1811     if (rset_no == 0)
1812     {
1813         rset_null_parms parms;
1814         
1815         parms.rset_term = rset_term_create (term_dst, -1, rank_type,
1816                                             zapt->term->which);
1817         return rset_create (rset_kind_null, &parms);
1818     }
1819     result = rset[0];
1820     for (i = 1; i<rset_no; i++)
1821     {
1822         rset_bool_parms bool_parms;
1823
1824         bool_parms.rset_l = result;
1825         bool_parms.rset_r = rset[i];
1826         bool_parms.key_size = sizeof(struct it_key);
1827         bool_parms.cmp = key_compare_it;
1828         bool_parms.log_item = key_logdump_txt;
1829         result = rset_create (rset_kind_and_forward, &bool_parms);
1830     }
1831     return result;
1832 }
1833
1834 static RSET rpn_search_APT_local (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1835                                   const char *termz,
1836                                   oid_value attributeSet,
1837                                   NMEM stream,
1838                                   const char *rank_type)
1839 {
1840     RSET result;
1841     RSFD rsfd;
1842     struct it_key key;
1843     rset_temp_parms parms;
1844
1845     parms.rset_term = rset_term_create (termz, -1, rank_type,
1846                                         zapt->term->which);
1847     parms.cmp = key_compare_it;
1848     parms.key_size = sizeof (struct it_key);
1849     parms.temp_path = res_get (zh->res, "setTmpDir");
1850     result = rset_create (rset_kind_temp, &parms);
1851     rsfd = rset_open (result, RSETF_WRITE);
1852
1853     key.sysno = atoi (termz);
1854     key.seqno = 1;
1855     if (key.sysno <= 0)
1856         key.sysno = 1;
1857     rset_write (result, rsfd, &key);
1858     rset_close (result, rsfd);
1859     return result;
1860 }
1861
1862 static RSET rpn_sort_spec (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1863                            oid_value attributeSet, NMEM stream,
1864                            Z_SortKeySpecList *sort_sequence,
1865                            const char *rank_type)
1866 {
1867     rset_null_parms parms;    
1868     int i;
1869     int sort_relation_value;
1870     AttrType sort_relation_type;
1871     int use_value;
1872     AttrType use_type;
1873     Z_SortKeySpec *sks;
1874     Z_SortKey *sk;
1875     Z_AttributeElement *ae;
1876     int oid[OID_SIZE];
1877     oident oe;
1878     char termz[20];
1879     
1880     attr_init (&sort_relation_type, zapt, 7);
1881     sort_relation_value = attr_find (&sort_relation_type, &attributeSet);
1882
1883     attr_init (&use_type, zapt, 1);
1884     use_value = attr_find (&use_type, &attributeSet);
1885
1886     if (!sort_sequence->specs)
1887     {
1888         sort_sequence->num_specs = 10;
1889         sort_sequence->specs = (Z_SortKeySpec **)
1890             nmem_malloc (stream, sort_sequence->num_specs *
1891                          sizeof(*sort_sequence->specs));
1892         for (i = 0; i<sort_sequence->num_specs; i++)
1893             sort_sequence->specs[i] = 0;
1894     }
1895     if (zapt->term->which != Z_Term_general)
1896         i = 0;
1897     else
1898         i = atoi_n ((char *) zapt->term->u.general->buf,
1899                     zapt->term->u.general->len);
1900     if (i >= sort_sequence->num_specs)
1901         i = 0;
1902     sprintf (termz, "%d", i);
1903
1904     oe.proto = PROTO_Z3950;
1905     oe.oclass = CLASS_ATTSET;
1906     oe.value = attributeSet;
1907     if (!oid_ent_to_oid (&oe, oid))
1908         return 0;
1909
1910     sks = (Z_SortKeySpec *) nmem_malloc (stream, sizeof(*sks));
1911     sks->sortElement = (Z_SortElement *)
1912         nmem_malloc (stream, sizeof(*sks->sortElement));
1913     sks->sortElement->which = Z_SortElement_generic;
1914     sk = sks->sortElement->u.generic = (Z_SortKey *)
1915         nmem_malloc (stream, sizeof(*sk));
1916     sk->which = Z_SortKey_sortAttributes;
1917     sk->u.sortAttributes = (Z_SortAttributes *)
1918         nmem_malloc (stream, sizeof(*sk->u.sortAttributes));
1919
1920     sk->u.sortAttributes->id = oid;
1921     sk->u.sortAttributes->list = (Z_AttributeList *)
1922         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list));
1923     sk->u.sortAttributes->list->num_attributes = 1;
1924     sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
1925         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list->attributes));
1926     ae = *sk->u.sortAttributes->list->attributes = (Z_AttributeElement *)
1927         nmem_malloc (stream, sizeof(**sk->u.sortAttributes->list->attributes));
1928     ae->attributeSet = 0;
1929     ae->attributeType = (int *)
1930         nmem_malloc (stream, sizeof(*ae->attributeType));
1931     *ae->attributeType = 1;
1932     ae->which = Z_AttributeValue_numeric;
1933     ae->value.numeric = (int *)
1934         nmem_malloc (stream, sizeof(*ae->value.numeric));
1935     *ae->value.numeric = use_value;
1936
1937     sks->sortRelation = (int *)
1938         nmem_malloc (stream, sizeof(*sks->sortRelation));
1939     if (sort_relation_value == 1)
1940         *sks->sortRelation = Z_SortKeySpec_ascending;
1941     else if (sort_relation_value == 2)
1942         *sks->sortRelation = Z_SortKeySpec_descending;
1943     else 
1944         *sks->sortRelation = Z_SortKeySpec_ascending;
1945
1946     sks->caseSensitivity = (int *)
1947         nmem_malloc (stream, sizeof(*sks->caseSensitivity));
1948     *sks->caseSensitivity = 0;
1949
1950     sks->which = Z_SortKeySpec_null;
1951     sks->u.null = odr_nullval ();
1952     sort_sequence->specs[i] = sks;
1953
1954     parms.rset_term = rset_term_create (termz, -1, rank_type,
1955                                         zapt->term->which);
1956     return rset_create (rset_kind_null, &parms);
1957 }
1958
1959
1960 static int parse_xpath(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1961                        oid_value attributeSet,
1962                        struct xpath_location_step *xpath, int max, NMEM mem)
1963 {
1964     oid_value curAttributeSet = attributeSet;
1965     AttrType use;
1966     const char *use_string = 0;
1967     
1968     attr_init (&use, zapt, 1);
1969     attr_find_ex (&use, &curAttributeSet, &use_string);
1970
1971     if (!use_string || *use_string != '/')
1972         return -1;
1973
1974     return zebra_parse_xpath_str(use_string, xpath, max, mem);
1975 }
1976  
1977                
1978
1979 static RSET xpath_trunc(ZebraHandle zh, NMEM stream,
1980                         int reg_type, const char *term, int use,
1981                         oid_value curAttributeSet)
1982 {
1983     RSET rset;
1984     struct grep_info grep_info;
1985     char term_dict[2048];
1986     char ord_buf[32];
1987     int prefix_len = 0;
1988     int ord = zebraExplain_lookupSU (zh->reg->zei, curAttributeSet, use);
1989     int ord_len, i, r, max_pos;
1990     int term_type = Z_Term_characterString;
1991     const char *flags = "void";
1992
1993     if (grep_info_prepare (zh, 0 /* zapt */, &grep_info, '0', stream))
1994     {
1995         rset_null_parms parms;
1996         
1997         parms.rset_term = rset_term_create (term, strlen(term),
1998                                             flags, term_type);
1999         parms.rset_term->nn = 0;
2000         return rset_create (rset_kind_null, &parms);
2001     }
2002
2003     if (ord < 0)
2004     {
2005         rset_null_parms parms;
2006         
2007         parms.rset_term = rset_term_create (term, strlen(term),
2008                                             flags, term_type);
2009         parms.rset_term->nn = 0;
2010         return rset_create (rset_kind_null, &parms);
2011     }
2012     if (prefix_len)
2013         term_dict[prefix_len++] = '|';
2014     else
2015         term_dict[prefix_len++] = '(';
2016     
2017     ord_len = key_SU_encode (ord, ord_buf);
2018     for (i = 0; i<ord_len; i++)
2019     {
2020         term_dict[prefix_len++] = 1;
2021         term_dict[prefix_len++] = ord_buf[i];
2022     }
2023     term_dict[prefix_len++] = ')';
2024     term_dict[prefix_len++] = 1;
2025     term_dict[prefix_len++] = reg_type;
2026     
2027     strcpy (term_dict+prefix_len, term);
2028     
2029     grep_info.isam_p_indx = 0;
2030     r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
2031                           &grep_info, &max_pos, 0, grep_handle);
2032     yaz_log (LOG_LOG, "%s %d positions", term, grep_info.isam_p_indx);
2033     rset = rset_trunc (zh, grep_info.isam_p_buf,
2034                        grep_info.isam_p_indx, term, strlen(term),
2035                        flags, 1, term_type);
2036     grep_info_delete (&grep_info);
2037     return rset;
2038 }
2039
2040 static RSET rpn_search_xpath (ZebraHandle zh,
2041                               oid_value attributeSet,
2042                               int num_bases, char **basenames,
2043                               NMEM stream, const char *rank_type, RSET rset,
2044                               int xpath_len, struct xpath_location_step *xpath)
2045 {
2046     oid_value curAttributeSet = attributeSet;
2047     int base_no;
2048     int i;
2049
2050     if (xpath_len < 0)
2051         return rset;
2052
2053     yaz_log (LOG_DEBUG, "len=%d", xpath_len);
2054     for (i = 0; i<xpath_len; i++)
2055     {
2056         yaz_log (LOG_DEBUG, "XPATH %d %s", i, xpath[i].part);
2057     }
2058
2059     curAttributeSet = VAL_IDXPATH;
2060
2061     /*
2062       //a    ->    a/.*
2063       //a/b  ->    b/a/.*
2064       /a     ->    a/
2065       /a/b   ->    b/a/
2066
2067       /      ->    none
2068
2069    a[@attr=value]/b[@other=othervalue]
2070
2071  /e/@a val      range(e/,range(@a,freetext(w,1015,val),@a),e/)
2072  /a/b val       range(b/a/,freetext(w,1016,val),b/a/)
2073  /a/b/@c val    range(b/a/,range(@c,freetext(w,1016,val),@c),b/a/)
2074  /a/b[@c=y] val range(b/a/,freetext(w,1016,val),b/a/,@c=y)
2075  /a[@c=y]/b val range(a/,range(b/a/,freetext(w,1016,val),b/a/),a/,@c=y)
2076  /a[@c=x]/b[@c=y] range(a/,range(b/a/,freetext(w,1016,val),b/a/,@c=y),a/,@c=x)
2077       
2078     */
2079
2080     dict_grep_cmap (zh->reg->dict, 0, 0);
2081
2082     for (base_no = 0; base_no < num_bases; base_no++)
2083     {
2084         int level = xpath_len;
2085         int first_path = 1;
2086         
2087         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2088         {
2089             zh->errCode = 109; /* Database unavailable */
2090             zh->errString = basenames[base_no];
2091             return rset;
2092         }
2093         while (--level >= 0)
2094         {
2095             char xpath_rev[128];
2096             int i, len;
2097             rset_between_parms parms;
2098             RSET rset_start_tag = 0, rset_end_tag = 0, rset_attr = 0;
2099
2100             *xpath_rev = 0;
2101             len = 0;
2102             for (i = level; i >= 1; --i)
2103             {
2104                 const char *cp = xpath[i].part;
2105                 if (*cp)
2106                 {
2107                     for (;*cp; cp++)
2108                         if (*cp == '*')
2109                         {
2110                             memcpy (xpath_rev + len, "[^/]*", 5);
2111                             len += 5;
2112                         }
2113                         else if (*cp == ' ')
2114                         {
2115
2116                             xpath_rev[len++] = 1;
2117                             xpath_rev[len++] = ' ';
2118                         }
2119
2120                         else
2121                             xpath_rev[len++] = *cp;
2122                     xpath_rev[len++] = '/';
2123                 }
2124                 else if (i == 1)  /* // case */
2125                 {
2126                     xpath_rev[len++] = '.';
2127                     xpath_rev[len++] = '*';
2128                 }
2129             }
2130             xpath_rev[len] = 0;
2131
2132             if (xpath[level].predicate &&
2133                 xpath[level].predicate->which == XPATH_PREDICATE_RELATION &&
2134                 xpath[level].predicate->u.relation.name[0])
2135             {
2136                 WRBUF wbuf = wrbuf_alloc();
2137                 wrbuf_puts(wbuf, xpath[level].predicate->u.relation.name+1);
2138                 if (xpath[level].predicate->u.relation.value)
2139                 {
2140                     const char *cp = xpath[level].predicate->u.relation.value;
2141                     wrbuf_putc(wbuf, '=');
2142                     
2143                     while (*cp)
2144                     {
2145                         if (strchr(REGEX_CHARS, *cp))
2146                             wrbuf_putc(wbuf, '\\');
2147                         wrbuf_putc(wbuf, *cp);
2148                         cp++;
2149                     }
2150                 }
2151                 wrbuf_puts(wbuf, "");
2152                 rset_attr = xpath_trunc (
2153                     zh, stream, '0', wrbuf_buf(wbuf), 3, curAttributeSet);
2154                 wrbuf_free(wbuf, 1);
2155             } 
2156             else 
2157             {
2158                 if (!first_path)
2159                     continue;
2160             }
2161             yaz_log (LOG_DEBUG, "xpath_rev (%d) = %s", level, xpath_rev);
2162             if (strlen(xpath_rev))
2163             {
2164                 rset_start_tag = xpath_trunc(zh, stream, 
2165                                          '0', xpath_rev, 1, curAttributeSet);
2166             
2167                 rset_end_tag = xpath_trunc(zh, stream,
2168                                        '0', xpath_rev, 2, curAttributeSet);
2169
2170                 parms.key_size = sizeof(struct it_key);
2171                 parms.cmp = key_compare_it;
2172                 parms.rset_l = rset_start_tag;
2173                 parms.rset_m = rset;
2174                 parms.rset_r = rset_end_tag;
2175                 parms.rset_attr = rset_attr;
2176                 parms.printer = key_print_it;
2177                 rset = rset_create (rset_kind_between, &parms);
2178             }
2179             first_path = 0;
2180         }
2181     }
2182
2183     return rset;
2184 }
2185
2186
2187
2188 static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
2189                             oid_value attributeSet, NMEM stream,
2190                             Z_SortKeySpecList *sort_sequence,
2191                             int num_bases, char **basenames)
2192 {
2193     unsigned reg_id;
2194     char *search_type = NULL;
2195     char rank_type[128];
2196     int complete_flag;
2197     int sort_flag;
2198     char termz[IT_MAX_WORD+1];
2199     RSET rset = 0;
2200     int xpath_len;
2201     int xpath_use = 0;
2202     struct xpath_location_step xpath[10];
2203
2204     zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2205                      rank_type, &complete_flag, &sort_flag);
2206     
2207     yaz_log(LOG_DEBUG, "reg_id=%c", reg_id);
2208     yaz_log(LOG_DEBUG, "complete_flag=%d", complete_flag);
2209     yaz_log(LOG_DEBUG, "search_type=%s", search_type);
2210     yaz_log(LOG_DEBUG, "rank_type=%s", rank_type);
2211
2212     if (zapt_term_to_utf8(zh, zapt, termz))
2213         return 0;
2214
2215     if (sort_flag)
2216         return rpn_sort_spec (zh, zapt, attributeSet, stream, sort_sequence,
2217                               rank_type);
2218     xpath_len = parse_xpath(zh, zapt, attributeSet, xpath, 10, stream);
2219     if (xpath_len >= 0)
2220     {
2221         xpath_use = 1016;
2222         if (xpath[xpath_len-1].part[0] == '@')
2223             xpath_use = 1015;
2224     }
2225
2226     if (!strcmp (search_type, "phrase"))
2227     {
2228         rset = rpn_search_APT_phrase (zh, zapt, termz, attributeSet, stream,
2229                                       reg_id, complete_flag, rank_type,
2230                                       xpath_use,
2231                                       num_bases, basenames);
2232     }
2233     else if (!strcmp (search_type, "and-list"))
2234     {
2235         rset = rpn_search_APT_and_list (zh, zapt, termz, attributeSet, stream,
2236                                         reg_id, complete_flag, rank_type,
2237                                         xpath_use,
2238                                         num_bases, basenames);
2239     }
2240     else if (!strcmp (search_type, "or-list"))
2241     {
2242         rset = rpn_search_APT_or_list (zh, zapt, termz, attributeSet, stream,
2243                                        reg_id, complete_flag, rank_type,
2244                                        xpath_use,
2245                                        num_bases, basenames);
2246     }
2247     else if (!strcmp (search_type, "local"))
2248     {
2249         rset = rpn_search_APT_local (zh, zapt, termz, attributeSet, stream,
2250                                      rank_type);
2251     }
2252     else if (!strcmp (search_type, "numeric"))
2253     {
2254         rset = rpn_search_APT_numeric (zh, zapt, termz, attributeSet, stream,
2255                                        reg_id, complete_flag, rank_type,
2256                                        xpath_use,
2257                                        num_bases, basenames);
2258     }
2259     else if (!strcmp (search_type, "always"))
2260     {
2261         rset = 0;
2262     }
2263     else
2264         zh->errCode = 118;
2265     return rpn_search_xpath (zh, attributeSet, num_bases, basenames,
2266                              stream, rank_type, rset, xpath_len, xpath);
2267 }
2268
2269 static RSET rpn_search_structure (ZebraHandle zh, Z_RPNStructure *zs,
2270                                   oid_value attributeSet, NMEM stream,
2271                                   Z_SortKeySpecList *sort_sequence,
2272                                   int num_bases, char **basenames)
2273 {
2274     RSET r = NULL;
2275     if (zs->which == Z_RPNStructure_complex)
2276     {
2277         Z_Operator *zop = zs->u.complex->roperator;
2278         rset_bool_parms bool_parms;
2279
2280         bool_parms.rset_l = rpn_search_structure (zh, zs->u.complex->s1,
2281                                                   attributeSet, stream,
2282                                                   sort_sequence,
2283                                                   num_bases, basenames);
2284         if (bool_parms.rset_l == NULL)
2285             return NULL;
2286         bool_parms.rset_r = rpn_search_structure (zh, zs->u.complex->s2,
2287                                                   attributeSet, stream,
2288                                                   sort_sequence,
2289                                                   num_bases, basenames);
2290         if (bool_parms.rset_r == NULL)
2291         {
2292             rset_delete (bool_parms.rset_l);
2293             return NULL;
2294         }
2295         bool_parms.key_size = sizeof(struct it_key);
2296         bool_parms.cmp = key_compare_it;
2297         bool_parms.log_item = key_logdump_txt;
2298
2299         switch (zop->which)
2300         {
2301         case Z_Operator_and:
2302             if (res_get(zh->res, "rsetforward"))
2303                 r = rset_create (rset_kind_and_forward, &bool_parms);
2304             else
2305                 r = rset_create (rset_kind_and, &bool_parms);
2306             break;
2307         case Z_Operator_or:
2308             r = rset_create (rset_kind_or, &bool_parms);
2309             break;
2310         case Z_Operator_and_not:
2311             r = rset_create (rset_kind_not, &bool_parms);
2312             break;
2313         case Z_Operator_prox:
2314             if (zop->u.prox->which != Z_ProximityOperator_known)
2315             {
2316                 zh->errCode = 132;
2317                 return NULL;
2318             }
2319             if (*zop->u.prox->u.known != Z_ProxUnit_word)
2320             {
2321                 char *val = (char *) nmem_malloc (stream, 16);
2322                 zh->errCode = 132;
2323                 zh->errString = val;
2324                 sprintf (val, "%d", *zop->u.prox->u.known);
2325                 return NULL;
2326             }
2327             else
2328             {
2329                 /* new / old prox */
2330                 rset_prox_parms parms;
2331                 RSET twosets[2];
2332                 
2333                 twosets[0] = bool_parms.rset_l;
2334                 twosets[1] = bool_parms.rset_r;
2335                 parms.rset = twosets;
2336                 parms.rset_no = 2;
2337                 parms.ordered = *zop->u.prox->ordered;
2338                 parms.exclusion = (!zop->u.prox->exclusion ? 0 :
2339                                    *zop->u.prox->exclusion);
2340                 parms.relation = *zop->u.prox->relationType;
2341                 parms.distance = *zop->u.prox->distance;
2342                 parms.key_size = sizeof(struct it_key);
2343                 parms.cmp = key_compare_it;
2344                 parms.getseq = key_get_seq;
2345                 parms.log_item = key_logdump_txt;
2346                 r = rset_create(rset_kind_prox, &parms);
2347             }
2348             break;
2349         default:
2350             zh->errCode = 110;
2351             return NULL;
2352         }
2353     }
2354     else if (zs->which == Z_RPNStructure_simple)
2355     {
2356         if (zs->u.simple->which == Z_Operand_APT)
2357         {
2358             yaz_log(LOG_DEBUG, "rpn_search_APT");
2359             r = rpn_search_APT (zh, zs->u.simple->u.attributesPlusTerm,
2360                                 attributeSet, stream, sort_sequence,
2361                                 num_bases, basenames);
2362         }
2363         else if (zs->u.simple->which == Z_Operand_resultSetId)
2364         {
2365             yaz_log(LOG_DEBUG, "rpn_search_ref");
2366             r = resultSetRef (zh, zs->u.simple->u.resultSetId);
2367             if (!r)
2368             {
2369                 r = rset_create (rset_kind_null, NULL);
2370                 zh->errCode = 30;
2371                 zh->errString =
2372                     nmem_strdup (stream, zs->u.simple->u.resultSetId);
2373                 return 0;
2374             }
2375             else
2376                 rset_dup(r);
2377         }
2378         else
2379         {
2380             zh->errCode = 3;
2381             return 0;
2382         }
2383     }
2384     else
2385     {
2386         zh->errCode = 3;
2387         return 0;
2388     }
2389     return r;
2390 }
2391
2392
2393 RSET rpn_search (ZebraHandle zh, NMEM nmem,
2394                  Z_RPNQuery *rpn, int num_bases, char **basenames, 
2395                  const char *setname,
2396                  ZebraSet sset)
2397 {
2398     RSET rset;
2399     oident *attrset;
2400     oid_value attributeSet;
2401     Z_SortKeySpecList *sort_sequence;
2402     int sort_status, i;
2403
2404     zh->errCode = 0;
2405     zh->errString = NULL;
2406     zh->hits = 0;
2407
2408     sort_sequence = (Z_SortKeySpecList *)
2409         nmem_malloc (nmem, sizeof(*sort_sequence));
2410     sort_sequence->num_specs = 10;
2411     sort_sequence->specs = (Z_SortKeySpec **)
2412         nmem_malloc (nmem, sort_sequence->num_specs *
2413                      sizeof(*sort_sequence->specs));
2414     for (i = 0; i<sort_sequence->num_specs; i++)
2415         sort_sequence->specs[i] = 0;
2416     
2417     attrset = oid_getentbyoid (rpn->attributeSetId);
2418     attributeSet = attrset->value;
2419     rset = rpn_search_structure (zh, rpn->RPNStructure, attributeSet,
2420                                  nmem, sort_sequence, num_bases, basenames);
2421     if (!rset)
2422         return 0;
2423
2424     if (zh->errCode)
2425         yaz_log(LOG_DEBUG, "search error: %d", zh->errCode);
2426     
2427     for (i = 0; sort_sequence->specs[i]; i++)
2428         ;
2429     sort_sequence->num_specs = i;
2430     if (!i)
2431         resultSetRank (zh, sset, rset);
2432     else
2433     {
2434         yaz_log(LOG_DEBUG, "resultSetSortSingle in rpn_search");
2435         resultSetSortSingle (zh, nmem, sset, rset,
2436                              sort_sequence, &sort_status);
2437         if (zh->errCode)
2438         {
2439             yaz_log(LOG_DEBUG, "resultSetSortSingle status = %d", zh->errCode);
2440         }
2441     }
2442     return rset;
2443 }
2444
2445 struct scan_info_entry {
2446     char *term;
2447     ISAMS_P isam_p;
2448 };
2449
2450 struct scan_info {
2451     struct scan_info_entry *list;
2452     ODR odr;
2453     int before, after;
2454     char prefix[20];
2455 };
2456
2457 static int scan_handle (char *name, const char *info, int pos, void *client)
2458 {
2459     int len_prefix, idx;
2460     struct scan_info *scan_info = (struct scan_info *) client;
2461
2462     len_prefix = strlen(scan_info->prefix);
2463     if (memcmp (name, scan_info->prefix, len_prefix))
2464         return 1;
2465     if (pos > 0)        idx = scan_info->after - pos + scan_info->before;
2466     else
2467         idx = - pos - 1;
2468     scan_info->list[idx].term = (char *)
2469         odr_malloc (scan_info->odr, strlen(name + len_prefix)+1);
2470     strcpy (scan_info->list[idx].term, name + len_prefix);
2471     assert (*info == sizeof(ISAMS_P));
2472     memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAMS_P));
2473     return 0;
2474 }
2475
2476 static void scan_term_untrans (ZebraHandle zh, NMEM stream, int reg_type,
2477                                char **dst, const char *src)
2478 {
2479     char term_src[IT_MAX_WORD];
2480     char term_dst[IT_MAX_WORD];
2481     
2482     term_untrans (zh, reg_type, term_src, src);
2483
2484     if (zh->iconv_from_utf8 != 0)
2485     {
2486         int len;
2487         char *inbuf = term_src;
2488         size_t inleft = strlen(term_src);
2489         char *outbuf = term_dst;
2490         size_t outleft = sizeof(term_dst)-1;
2491         size_t ret;
2492         
2493         ret = yaz_iconv (zh->iconv_from_utf8, &inbuf, &inleft,
2494                          &outbuf, &outleft);
2495         if (ret == (size_t)(-1))
2496             len = 0;
2497         else
2498             len = outbuf - term_dst;
2499         *dst = nmem_malloc (stream, len + 1);
2500         if (len > 0)
2501             memcpy (*dst, term_dst, len);
2502         (*dst)[len] = '\0';
2503     }
2504     else
2505         *dst = nmem_strdup (stream, term_src);
2506 }
2507
2508 static void count_set (RSET r, int *count)
2509 {
2510     int psysno = 0;
2511     int kno = 0;
2512     struct it_key key;
2513     RSFD rfd;
2514     int term_index;
2515
2516     yaz_log(LOG_DEBUG, "count_set");
2517
2518     *count = 0;
2519     rfd = rset_open (r, RSETF_READ);
2520     while (rset_read (r, rfd, &key, &term_index))
2521     {
2522         if (key.sysno != psysno)
2523         {
2524             psysno = key.sysno;
2525             (*count)++;
2526         }
2527         kno++;
2528     }
2529     rset_close (r, rfd);
2530     yaz_log(LOG_DEBUG, "%d keys, %d records", kno, *count);
2531 }
2532
2533 void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
2534                oid_value attributeset,
2535                int num_bases, char **basenames,
2536                int *position, int *num_entries, ZebraScanEntry **list,
2537                int *is_partial, RSET limit_set, int return_zero)
2538 {
2539     int i;
2540     int pos = *position;
2541     int num = *num_entries;
2542     int before;
2543     int after;
2544     int base_no;
2545     char termz[IT_MAX_WORD+20];
2546     AttrType use;
2547     int use_value;
2548     const char *use_string = 0;
2549     struct scan_info *scan_info_array;
2550     ZebraScanEntry *glist;
2551     int ords[32], ord_no = 0;
2552     int ptr[32];
2553
2554     int bases_ok = 0;     /* no of databases with OK attribute */
2555     int errCode = 0;      /* err code (if any is not OK) */
2556     char *errString = 0;  /* addinfo */
2557
2558     unsigned reg_id;
2559     char *search_type = NULL;
2560     char rank_type[128];
2561     int complete_flag;
2562     int sort_flag;
2563
2564     *list = 0;
2565
2566     if (attributeset == VAL_NONE)
2567         attributeset = VAL_BIB1;
2568
2569     if (!limit_set)
2570     {
2571         AttrType termset;
2572         int termset_value_numeric;
2573         const char *termset_value_string;
2574         attr_init (&termset, zapt, 8);
2575         termset_value_numeric =
2576             attr_find_ex (&termset, NULL, &termset_value_string);
2577         if (termset_value_numeric != -1)
2578         {
2579             char resname[32];
2580             const char *termset_name = 0;
2581             
2582             if (termset_value_numeric != -2)
2583             {
2584                 
2585                 sprintf (resname, "%d", termset_value_numeric);
2586                 termset_name = resname;
2587             }
2588             else
2589                 termset_name = termset_value_string;
2590             
2591             limit_set = resultSetRef (zh, termset_name);
2592         }
2593     }
2594         
2595     yaz_log (LOG_DEBUG, "position = %d, num = %d set=%d",
2596              pos, num, attributeset);
2597         
2598     attr_init (&use, zapt, 1);
2599     use_value = attr_find_ex (&use, &attributeset, &use_string);
2600
2601     if (zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2602                          rank_type, &complete_flag, &sort_flag))
2603     {
2604         *num_entries = 0;
2605         zh->errCode = 113;
2606         return ;
2607     }
2608     yaz_log (LOG_DEBUG, "use_value = %d", use_value);
2609
2610     if (use_value == -1)
2611         use_value = 1016;
2612     for (base_no = 0; base_no < num_bases && ord_no < 32; base_no++)
2613     {
2614         int r;
2615         attent attp;
2616         data1_local_attribute *local_attr;
2617
2618         if ((r=att_getentbyatt (zh, &attp, attributeset, use_value,
2619                                 use_string)))
2620         {
2621             yaz_log(LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d",
2622                   attributeset, use_value);
2623             if (r == -1)
2624             {
2625                 char val_str[32];
2626                 sprintf (val_str, "%d", use_value);
2627                 errCode = 114;
2628                 errString = odr_strdup (stream, val_str);
2629             }   
2630             else
2631                 errCode = 121;
2632             continue;
2633         }
2634         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2635         {
2636             zh->errString = basenames[base_no];
2637             zh->errCode = 109; /* Database unavailable */
2638             *num_entries = 0;
2639             return;
2640         }
2641         bases_ok++;
2642         for (local_attr = attp.local_attributes; local_attr && ord_no < 32;
2643              local_attr = local_attr->next)
2644         {
2645             int ord;
2646
2647             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
2648                                          local_attr->local);
2649             if (ord > 0)
2650                 ords[ord_no++] = ord;
2651         }
2652     }
2653     if (!bases_ok && errCode)
2654     {
2655         zh->errCode = errCode;
2656         zh->errString = errString;
2657         *num_entries = 0;
2658     }
2659     if (ord_no == 0)
2660     {
2661         *num_entries = 0;
2662         return;
2663     }
2664     /* prepare dictionary scanning */
2665     if (num < 1)
2666     {
2667         *num_entries = 0;
2668         return;
2669     }
2670     before = pos-1;
2671     if (before < 0)
2672         before = 0;
2673     after = 1+num-pos;
2674     if (after < 0)
2675         after = 0;
2676     scan_info_array = (struct scan_info *)
2677         odr_malloc (stream, ord_no * sizeof(*scan_info_array));
2678     for (i = 0; i < ord_no; i++)
2679     {
2680         int j, prefix_len = 0;
2681         int before_tmp = before, after_tmp = after;
2682         struct scan_info *scan_info = scan_info_array + i;
2683         struct rpn_char_map_info rcmi;
2684
2685         rpn_char_map_prepare (zh->reg, reg_id, &rcmi);
2686
2687         scan_info->before = before;
2688         scan_info->after = after;
2689         scan_info->odr = stream;
2690
2691         scan_info->list = (struct scan_info_entry *)
2692             odr_malloc (stream, (before+after) * sizeof(*scan_info->list));
2693         for (j = 0; j<before+after; j++)
2694             scan_info->list[j].term = NULL;
2695
2696         prefix_len += key_SU_encode (ords[i], termz + prefix_len);
2697         termz[prefix_len++] = reg_id;
2698         termz[prefix_len] = 0;
2699         strcpy (scan_info->prefix, termz);
2700
2701         if (trans_scan_term (zh, zapt, termz+prefix_len, reg_id))
2702             return ;
2703                     
2704         dict_scan (zh->reg->dict, termz, &before_tmp, &after_tmp,
2705                    scan_info, scan_handle);
2706     }
2707     glist = (ZebraScanEntry *)
2708         odr_malloc (stream, (before+after)*sizeof(*glist));
2709
2710     /* consider terms after main term */
2711     for (i = 0; i < ord_no; i++)
2712         ptr[i] = before;
2713     
2714     *is_partial = 0;
2715     for (i = 0; i<after; i++)
2716     {
2717         int j, j0 = -1;
2718         const char *mterm = NULL;
2719         const char *tst;
2720         RSET rset;
2721         int lo = i + pos-1; /* offset in result list */
2722         
2723         for (j = 0; j < ord_no; j++)
2724         {
2725             if (ptr[j] < before+after &&
2726                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2727                 (!mterm || strcmp (tst, mterm) < 0))
2728             {
2729                 j0 = j;
2730                 mterm = tst;
2731             }
2732         }
2733         if (j0 == -1)
2734             break;
2735         if (lo >= 0)
2736         {
2737             scan_term_untrans (zh, stream->mem, reg_id,
2738                                &glist[lo].term, mterm);
2739             rset = rset_trunc(zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
2740                               glist[lo].term, strlen(glist[lo].term),
2741                               NULL, 0, zapt->term->which);
2742         }
2743         ptr[j0]++;
2744         for (j = j0+1; j<ord_no; j++)
2745         {
2746             if (ptr[j] < before+after &&
2747                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2748                 !strcmp (tst, mterm))
2749             {
2750                 if (lo >= 0)
2751                 {
2752                     rset_bool_parms bool_parms;
2753                     RSET rset2;
2754                     
2755                     rset2 =
2756                         rset_trunc(zh,
2757                                    &scan_info_array[j].list[ptr[j]].isam_p, 1,
2758                                    glist[lo].term,
2759                                    strlen(glist[lo].term), NULL, 0,
2760                                    zapt->term->which);
2761                     
2762                     bool_parms.key_size = sizeof(struct it_key);
2763                     bool_parms.cmp = key_compare_it;
2764                     bool_parms.log_item = key_logdump_txt;
2765                     bool_parms.rset_l = rset;
2766                     bool_parms.rset_r = rset2;
2767                     
2768                     rset = rset_create (rset_kind_or, &bool_parms);
2769                 }
2770                 ptr[j]++;
2771             }
2772         }
2773         if (lo >= 0)
2774         {
2775             if (limit_set)
2776             {
2777                 rset_bool_parms bool_parms;
2778                 
2779                 bool_parms.key_size = sizeof(struct it_key);
2780                 bool_parms.cmp = key_compare_it;
2781                 bool_parms.log_item = key_logdump_txt;
2782                 bool_parms.rset_l = rset;
2783                 bool_parms.rset_r = rset_dup(limit_set);
2784                 
2785                 rset = rset_create (rset_kind_and, &bool_parms);
2786             }
2787             count_set (rset, &glist[lo].occurrences);
2788             rset_delete (rset);
2789         }
2790     }
2791     if (i < after)
2792     {
2793         *num_entries -= (after-i);
2794         *is_partial = 1;
2795     }
2796
2797     /* consider terms before main term */
2798     for (i = 0; i<ord_no; i++)
2799         ptr[i] = 0;
2800
2801     for (i = 0; i<before; i++)
2802     {
2803         int j, j0 = -1;
2804         const char *mterm = NULL;
2805         const char *tst;
2806         RSET rset;
2807         
2808         for (j = 0; j <ord_no; j++)
2809         {
2810             if (ptr[j] < before &&
2811                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2812                 (!mterm || strcmp (tst, mterm) > 0))
2813             {
2814                 j0 = j;
2815                 mterm = tst;
2816             }
2817         }
2818         if (j0 == -1)
2819             break;
2820
2821         scan_term_untrans (zh, stream->mem, reg_id,
2822                            &glist[before-1-i].term, mterm);
2823
2824         rset = rset_trunc
2825                (zh, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1,
2826                 glist[before-1-i].term, strlen(glist[before-1-i].term),
2827                 NULL, 0, zapt->term->which);
2828
2829         ptr[j0]++;
2830
2831         for (j = j0+1; j<ord_no; j++)
2832         {
2833             if (ptr[j] < before &&
2834                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2835                 !strcmp (tst, mterm))
2836             {
2837                 rset_bool_parms bool_parms;
2838                 RSET rset2;
2839
2840                 rset2 = rset_trunc (zh,
2841                          &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1,
2842                                     glist[before-1-i].term,
2843                                     strlen(glist[before-1-i].term), NULL, 0,
2844                                     zapt->term->which);
2845
2846                 bool_parms.key_size = sizeof(struct it_key);
2847                 bool_parms.cmp = key_compare_it;
2848                 bool_parms.log_item = key_logdump_txt;
2849                 bool_parms.rset_l = rset;
2850                 bool_parms.rset_r = rset2;
2851               
2852                 rset = rset_create (rset_kind_or, &bool_parms);
2853
2854                 ptr[j]++;
2855             }
2856         }
2857         if (limit_set)
2858         {
2859             rset_bool_parms bool_parms;
2860
2861             bool_parms.key_size = sizeof(struct it_key);
2862             bool_parms.cmp = key_compare_it;
2863             bool_parms.log_item = key_logdump_txt;
2864             bool_parms.rset_l = rset;
2865             bool_parms.rset_r = rset_dup(limit_set);
2866
2867             rset = rset_create (rset_kind_and, &bool_parms);
2868         }
2869         count_set (rset, &glist[before-1-i].occurrences);
2870         rset_delete (rset);
2871     }
2872     i = before-i;
2873     if (i)
2874     {
2875         *is_partial = 1;
2876         *position -= i;
2877         *num_entries -= i;
2878     }
2879     *list = glist + i;               /* list is set to first 'real' entry */
2880     
2881     yaz_log(LOG_DEBUG, "position = %d, num_entries = %d",
2882           *position, *num_entries);
2883     if (zh->errCode)
2884         yaz_log(LOG_DEBUG, "scan error: %d", zh->errCode);
2885 }
2886