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