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