XPATH fixes - leaf attributes part of tag path
[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.119 2002-08-02 10:07:48 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                     yaz_log (LOG_LOG, "value=%s", p->u.relation.value);
2085
2086                     cp++;
2087                 }                           
2088                 else
2089                 {
2090                     for (i = 0; *cp && !strchr(" ]", *cp); i++)
2091                         cp++;
2092                     p->u.relation.value = nmem_malloc (mem, i+1);
2093                     if (i)
2094                         memcpy (p->u.relation.value, cp - i, i);
2095                     p->u.relation.value[i] = 0;
2096                 }
2097                 while (*cp == ' ')
2098                     cp++;
2099             }
2100             if (*cp == ']')
2101                 cp++;
2102         } /* end of ] predicate */
2103         no++;
2104         if (*cp != '/')
2105             break;
2106         cp++;
2107     }
2108     return no;
2109 }
2110                 
2111
2112 static RSET xpath_trunc(ZebraHandle zh, NMEM stream,
2113                         int reg_type, const char *term, int use,
2114                         oid_value curAttributeSet)
2115 {
2116     RSET rset;
2117     struct grep_info grep_info;
2118     char term_dict[2048];
2119     char ord_buf[32];
2120     int prefix_len = 0;
2121     int ord = zebraExplain_lookupSU (zh->reg->zei, curAttributeSet, use);
2122     int ord_len, i, r, max_pos;
2123
2124     if (grep_info_prepare (zh, 0 /* zapt */, &grep_info, '0', stream))
2125         return 0;
2126
2127     if (ord < 0)
2128         return 0;
2129     if (prefix_len)
2130         term_dict[prefix_len++] = '|';
2131     else
2132         term_dict[prefix_len++] = '(';
2133     
2134     ord_len = key_SU_encode (ord, ord_buf);
2135     for (i = 0; i<ord_len; i++)
2136     {
2137         term_dict[prefix_len++] = 1;
2138         term_dict[prefix_len++] = ord_buf[i];
2139     }
2140     term_dict[prefix_len++] = ')';
2141     term_dict[prefix_len++] = 1;
2142     term_dict[prefix_len++] = reg_type;
2143     
2144     strcpy (term_dict+prefix_len, term);
2145     
2146     grep_info.isam_p_indx = 0;
2147     r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
2148                           &grep_info, &max_pos, 0, grep_handle);
2149     yaz_log (LOG_LOG, "%s %d positions", term,
2150              grep_info.isam_p_indx);
2151     rset = rset_trunc (zh, grep_info.isam_p_buf,
2152                        grep_info.isam_p_indx, term, strlen(term),
2153                        "void", 1, Z_Term_characterString);
2154     grep_info_delete (&grep_info);
2155     return rset;
2156 }
2157
2158 static RSET rpn_search_xpath (ZebraHandle zh,
2159                               oid_value attributeSet,
2160                               int num_bases, char **basenames,
2161                               NMEM stream, const char *rank_type, RSET rset,
2162                               int xpath_len, struct xpath_location_step *xpath)
2163 {
2164     oid_value curAttributeSet = attributeSet;
2165     int base_no;
2166     int i;
2167
2168     if (xpath_len < 0)
2169         return rset;
2170
2171     yaz_log (LOG_LOG, "len=%d", xpath_len);
2172     for (i = 0; i<xpath_len; i++)
2173     {
2174         yaz_log (LOG_LOG, "XPATH %d %s", i, xpath[i].part);
2175
2176     }
2177
2178     curAttributeSet = VAL_IDXPATH;
2179
2180     /*
2181       //a    ->    a/.*
2182       //a/b  ->    b/a/.*
2183       /a     ->    a/
2184       /a/b   ->    b/a/
2185
2186       /      ->    none
2187
2188    a[@attr=value]/b[@other=othervalue]
2189
2190  /e/@a val      range(e/,range(@a,freetext(w,1015,val),@a),e/)
2191  /a/b val       range(b/a/,freetext(w,1016,val),b/a/)
2192  /a/b/@c val    range(b/a/,range(@c,freetext(w,1016,val),@c),b/a/)
2193  /a/b[@c=y] val range(b/a/,freetext(w,1016,val),b/a/,@c=y)
2194  /a[@c=y]/b val range(a/,range(b/a/,freetext(w,1016,val),b/a/),a/,@c=y)
2195  /a[@c=x]/b[@c=y] range(a/,range(b/a/,freetext(w,1016,val),b/a/,@c=y),a/,@c=x)
2196       
2197     */
2198
2199     dict_grep_cmap (zh->reg->dict, 0, 0);
2200
2201     for (base_no = 0; base_no < num_bases; base_no++)
2202     {
2203         int level = xpath_len;
2204         int first_path = 1;
2205         
2206         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2207         {
2208             zh->errCode = 109; /* Database unavailable */
2209             zh->errString = basenames[base_no];
2210             return rset;
2211         }
2212         while (--level >= 0)
2213         {
2214             char xpath_rev[128];
2215             int i, len;
2216             rset_between_parms parms;
2217             RSET rset_start_tag = 0, rset_end_tag = 0, rset_attr = 0;
2218
2219             *xpath_rev = 0;
2220             len = 0;
2221             for (i = level; i >= 1; --i)
2222             {
2223                 const char *cp = xpath[i].part;
2224                 if (*cp)
2225                 {
2226                     for (;*cp; cp++)
2227                         if (*cp == '*')
2228                         {
2229                             memcpy (xpath_rev + len, "[^/]*", 5);
2230                             len += 5;
2231                         }
2232                         else if (*cp == ' ')
2233                         {
2234
2235                             xpath_rev[len++] = 1;
2236                             xpath_rev[len++] = ' ';
2237                         }
2238
2239                         else
2240                             xpath_rev[len++] = *cp;
2241                     xpath_rev[len++] = '/';
2242                 }
2243                 else if (i == 1)  /* // case */
2244                 {
2245                     xpath_rev[len++] = '.';
2246                     xpath_rev[len++] = '*';
2247                 }
2248             }
2249             xpath_rev[len] = 0;
2250
2251             if (xpath[level].predicate &&
2252                 xpath[level].predicate->which == XPATH_PREDICATE_RELATION &&
2253                 xpath[level].predicate->u.relation.name[0])
2254             {
2255                 char predicate_str[128];
2256
2257                 strcpy (predicate_str,
2258                         xpath[level].predicate->u.relation.name+1);
2259                 if (xpath[level].predicate->u.relation.value)
2260                 {
2261                     strcat (predicate_str, "=");
2262                     strcat (predicate_str,
2263                             xpath[level].predicate->u.relation.value);
2264                 }
2265                 rset_attr = xpath_trunc (
2266                     zh, stream, '0', predicate_str, 3, curAttributeSet);
2267             } 
2268             else 
2269             {
2270                 if (!first_path)
2271                     continue;
2272             }
2273             yaz_log (LOG_LOG, "xpath_rev (%d) = %s", level, xpath_rev);
2274             if (strlen(xpath_rev))
2275             {
2276                 rset_start_tag = xpath_trunc(zh, stream, 
2277                                          '0', xpath_rev, 1, curAttributeSet);
2278             
2279                 rset_end_tag = xpath_trunc(zh, stream,
2280                                        '0', xpath_rev, 2, curAttributeSet);
2281             
2282                 parms.key_size = sizeof(struct it_key);
2283                 parms.cmp = key_compare_it;
2284                 parms.rset_l = rset_start_tag;
2285                 parms.rset_m = rset;
2286                 parms.rset_r = rset_end_tag;
2287                 parms.rset_attr = rset_attr;
2288                 parms.printer = key_print_it;
2289                 rset = rset_create (rset_kind_between, &parms);
2290             }
2291             first_path = 0;
2292         }
2293     }
2294
2295     return rset;
2296 }
2297
2298
2299
2300 static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
2301                             oid_value attributeSet, NMEM stream,
2302                             Z_SortKeySpecList *sort_sequence,
2303                             int num_bases, char **basenames)
2304 {
2305     unsigned reg_id;
2306     char *search_type = NULL;
2307     char rank_type[128];
2308     int complete_flag;
2309     int sort_flag;
2310     char termz[IT_MAX_WORD+1];
2311     RSET rset = 0;
2312     int xpath_len;
2313     int xpath_use = 0;
2314     struct xpath_location_step xpath[10];
2315
2316     zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2317                      rank_type, &complete_flag, &sort_flag);
2318     
2319     logf (LOG_DEBUG, "reg_id=%c", reg_id);
2320     logf (LOG_DEBUG, "complete_flag=%d", complete_flag);
2321     logf (LOG_DEBUG, "search_type=%s", search_type);
2322     logf (LOG_DEBUG, "rank_type=%s", rank_type);
2323
2324     if (trans_term (zh, zapt, termz))
2325         return 0;
2326
2327     if (sort_flag)
2328         return rpn_sort_spec (zh, zapt, attributeSet, stream, sort_sequence,
2329                               rank_type);
2330     xpath_len = parse_xpath(zh, zapt, attributeSet, xpath, stream);
2331     if (xpath_len >= 0)
2332     {
2333         xpath_use = 1016;
2334         if (xpath[xpath_len-1].part[0] == '@')
2335             xpath_use = 1015;
2336     }
2337
2338     if (!strcmp (search_type, "phrase"))
2339     {
2340         rset = rpn_search_APT_phrase (zh, zapt, termz, attributeSet, stream,
2341                                       reg_id, complete_flag, rank_type,
2342                                       xpath_use,
2343                                       num_bases, basenames);
2344     }
2345     else if (!strcmp (search_type, "and-list"))
2346     {
2347         rset = rpn_search_APT_and_list (zh, zapt, termz, attributeSet, stream,
2348                                         reg_id, complete_flag, rank_type,
2349                                         xpath_use,
2350                                         num_bases, basenames);
2351     }
2352     else if (!strcmp (search_type, "or-list"))
2353     {
2354         rset = rpn_search_APT_or_list (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, "local"))
2360     {
2361         rset = rpn_search_APT_local (zh, zapt, termz, attributeSet, stream,
2362                                      rank_type);
2363     }
2364     else if (!strcmp (search_type, "numeric"))
2365     {
2366         rset = rpn_search_APT_numeric (zh, zapt, termz, attributeSet, stream,
2367                                        reg_id, complete_flag, rank_type,
2368                                        num_bases, basenames);
2369     }
2370     else if (!strcmp (search_type, "always"))
2371     {
2372         rset = 0;
2373     }
2374     else
2375         zh->errCode = 118;
2376     return rpn_search_xpath (zh, attributeSet, num_bases, basenames,
2377                              stream, rank_type, rset, xpath_len, xpath);
2378 }
2379
2380 static RSET rpn_search_structure (ZebraHandle zh, Z_RPNStructure *zs,
2381                                   oid_value attributeSet, NMEM stream,
2382                                   Z_SortKeySpecList *sort_sequence,
2383                                   int num_bases, char **basenames)
2384 {
2385     RSET r = NULL;
2386     if (zs->which == Z_RPNStructure_complex)
2387     {
2388         Z_Operator *zop = zs->u.complex->roperator;
2389         rset_bool_parms bool_parms;
2390
2391         bool_parms.rset_l = rpn_search_structure (zh, zs->u.complex->s1,
2392                                                   attributeSet, stream,
2393                                                   sort_sequence,
2394                                                   num_bases, basenames);
2395         if (bool_parms.rset_l == NULL)
2396             return NULL;
2397         bool_parms.rset_r = rpn_search_structure (zh, zs->u.complex->s2,
2398                                                   attributeSet, stream,
2399                                                   sort_sequence,
2400                                                   num_bases, basenames);
2401         if (bool_parms.rset_r == NULL)
2402         {
2403             rset_delete (bool_parms.rset_l);
2404             return NULL;
2405         }
2406         bool_parms.key_size = sizeof(struct it_key);
2407         bool_parms.cmp = key_compare_it;
2408
2409         switch (zop->which)
2410         {
2411         case Z_Operator_and:
2412             r = rset_create (rset_kind_and, &bool_parms);
2413             break;
2414         case Z_Operator_or:
2415             r = rset_create (rset_kind_or, &bool_parms);
2416             break;
2417         case Z_Operator_and_not:
2418             r = rset_create (rset_kind_not, &bool_parms);
2419             break;
2420         case Z_Operator_prox:
2421 #ifdef ASN_COMPILED
2422             if (zop->u.prox->which != Z_ProximityOperator_known)
2423             {
2424                 zh->errCode = 132;
2425                 return NULL;
2426             }
2427 #else
2428             if (zop->u.prox->which != Z_ProxCode_known)
2429             {
2430                 zh->errCode = 132;
2431                 return NULL;
2432             }
2433 #endif
2434
2435 #ifdef ASN_COMPILED
2436             if (*zop->u.prox->u.known != Z_ProxUnit_word)
2437             {
2438                 char *val = (char *) nmem_malloc (stream, 16);
2439                 zh->errCode = 132;
2440                 zh->errString = val;
2441                 sprintf (val, "%d", *zop->u.prox->u.known);
2442                 return NULL;
2443             }
2444 #else
2445             if (*zop->u.prox->proximityUnitCode != Z_ProxUnit_word)
2446             {
2447                 char *val = (char *) nmem_malloc (stream, 16);
2448                 zh->errCode = 132;
2449                 zh->errString = val;
2450                 sprintf (val, "%d", *zop->u.prox->proximityUnitCode);
2451                 return NULL;
2452             }
2453 #endif
2454             else
2455             {
2456                 RSET rsets[2];
2457
2458                 rsets[0] = bool_parms.rset_l;
2459                 rsets[1] = bool_parms.rset_r;
2460                 
2461                 r = rpn_prox (zh, rsets, 2, 
2462                               *zop->u.prox->ordered,
2463                               (!zop->u.prox->exclusion ? 0 :
2464                                *zop->u.prox->exclusion),
2465                               *zop->u.prox->relationType,
2466                               *zop->u.prox->distance);
2467                 rset_delete (rsets[0]);
2468                 rset_delete (rsets[1]);
2469             }
2470             break;
2471         default:
2472             zh->errCode = 110;
2473             return NULL;
2474         }
2475     }
2476     else if (zs->which == Z_RPNStructure_simple)
2477     {
2478         if (zs->u.simple->which == Z_Operand_APT)
2479         {
2480             logf (LOG_DEBUG, "rpn_search_APT");
2481             r = rpn_search_APT (zh, zs->u.simple->u.attributesPlusTerm,
2482                                 attributeSet, stream, sort_sequence,
2483                                 num_bases, basenames);
2484         }
2485         else if (zs->u.simple->which == Z_Operand_resultSetId)
2486         {
2487             logf (LOG_DEBUG, "rpn_search_ref");
2488             r = resultSetRef (zh, zs->u.simple->u.resultSetId);
2489             if (!r)
2490             {
2491                 r = rset_create (rset_kind_null, NULL);
2492                 zh->errCode = 30;
2493                 zh->errString =
2494                     nmem_strdup (stream, zs->u.simple->u.resultSetId);
2495                 return 0;
2496             }
2497         }
2498         else
2499         {
2500             zh->errCode = 3;
2501             return 0;
2502         }
2503     }
2504     else
2505     {
2506         zh->errCode = 3;
2507         return 0;
2508     }
2509     return r;
2510 }
2511
2512
2513 RSET rpn_search (ZebraHandle zh, NMEM nmem,
2514                  Z_RPNQuery *rpn, int num_bases, char **basenames, 
2515                  const char *setname,
2516                  ZebraSet sset)
2517 {
2518     RSET rset;
2519     oident *attrset;
2520     oid_value attributeSet;
2521     Z_SortKeySpecList *sort_sequence;
2522     int sort_status, i;
2523
2524     zh->errCode = 0;
2525     zh->errString = NULL;
2526     zh->hits = 0;
2527
2528     sort_sequence = (Z_SortKeySpecList *)
2529         nmem_malloc (nmem, sizeof(*sort_sequence));
2530     sort_sequence->num_specs = 10;
2531     sort_sequence->specs = (Z_SortKeySpec **)
2532         nmem_malloc (nmem, sort_sequence->num_specs *
2533                      sizeof(*sort_sequence->specs));
2534     for (i = 0; i<sort_sequence->num_specs; i++)
2535         sort_sequence->specs[i] = 0;
2536     
2537     attrset = oid_getentbyoid (rpn->attributeSetId);
2538     attributeSet = attrset->value;
2539     rset = rpn_search_structure (zh, rpn->RPNStructure, attributeSet,
2540                                  nmem, sort_sequence, num_bases, basenames);
2541     if (!rset)
2542         return 0;
2543
2544     if (zh->errCode)
2545         logf (LOG_DEBUG, "search error: %d", zh->errCode);
2546     
2547     for (i = 0; sort_sequence->specs[i]; i++)
2548         ;
2549     sort_sequence->num_specs = i;
2550     if (!i)
2551         resultSetRank (zh, sset, rset);
2552     else
2553     {
2554         logf (LOG_DEBUG, "resultSetSortSingle in rpn_search");
2555         resultSetSortSingle (zh, nmem, sset, rset,
2556                              sort_sequence, &sort_status);
2557         if (zh->errCode)
2558         {
2559             logf (LOG_DEBUG, "resultSetSortSingle status = %d", zh->errCode);
2560         }
2561     }
2562     return rset;
2563 }
2564
2565 struct scan_info_entry {
2566     char *term;
2567     ISAMS_P isam_p;
2568 };
2569
2570 struct scan_info {
2571     struct scan_info_entry *list;
2572     ODR odr;
2573     int before, after;
2574     char prefix[20];
2575 };
2576
2577 static int scan_handle (char *name, const char *info, int pos, void *client)
2578 {
2579     int len_prefix, idx;
2580     struct scan_info *scan_info = (struct scan_info *) client;
2581
2582     len_prefix = strlen(scan_info->prefix);
2583     if (memcmp (name, scan_info->prefix, len_prefix))
2584         return 1;
2585     if (pos > 0)        idx = scan_info->after - pos + scan_info->before;
2586     else
2587         idx = - pos - 1;
2588     scan_info->list[idx].term = (char *)
2589         odr_malloc (scan_info->odr, strlen(name + len_prefix)+1);
2590     strcpy (scan_info->list[idx].term, name + len_prefix);
2591     assert (*info == sizeof(ISAMS_P));
2592     memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAMS_P));
2593     return 0;
2594 }
2595
2596 static void scan_term_untrans (ZebraHandle zh, NMEM stream, int reg_type,
2597                                char **dst, const char *src)
2598 {
2599     char term_dst[1024];
2600     
2601     term_untrans (zh, reg_type, term_dst, src);
2602     
2603     *dst = (char *) nmem_malloc (stream, strlen(term_dst)+1);
2604     strcpy (*dst, term_dst);
2605 }
2606
2607 static void count_set (RSET r, int *count)
2608 {
2609     int psysno = 0;
2610     int kno = 0;
2611     struct it_key key;
2612     RSFD rfd;
2613     int term_index;
2614
2615     logf (LOG_DEBUG, "count_set");
2616
2617     *count = 0;
2618     rfd = rset_open (r, RSETF_READ);
2619     while (rset_read (r, rfd, &key, &term_index))
2620     {
2621         if (key.sysno != psysno)
2622         {
2623             psysno = key.sysno;
2624             (*count)++;
2625         }
2626         kno++;
2627     }
2628     rset_close (r, rfd);
2629     logf (LOG_DEBUG, "%d keys, %d records", kno, *count);
2630 }
2631
2632 void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
2633                oid_value attributeset,
2634                int num_bases, char **basenames,
2635                int *position, int *num_entries, ZebraScanEntry **list,
2636                int *is_partial)
2637 {
2638     int i;
2639     int pos = *position;
2640     int num = *num_entries;
2641     int before;
2642     int after;
2643     int base_no;
2644     char termz[IT_MAX_WORD+20];
2645     AttrType use;
2646     int use_value;
2647     struct scan_info *scan_info_array;
2648     ZebraScanEntry *glist;
2649     int ords[32], ord_no = 0;
2650     int ptr[32];
2651
2652     unsigned reg_id;
2653     char *search_type = NULL;
2654     char rank_type[128];
2655     int complete_flag;
2656     int sort_flag;
2657     *list = 0;
2658
2659     if (attributeset == VAL_NONE)
2660         attributeset = VAL_BIB1;
2661
2662     yaz_log (LOG_DEBUG, "position = %d, num = %d set=%d",
2663              pos, num, attributeset);
2664         
2665     attr_init (&use, zapt, 1);
2666     use_value = attr_find (&use, &attributeset);
2667
2668     if (zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2669                          rank_type, &complete_flag, &sort_flag))
2670     {
2671         *num_entries = 0;
2672         zh->errCode = 113;
2673         return ;
2674     }
2675     yaz_log (LOG_DEBUG, "use_value = %d", use_value);
2676
2677     if (use_value == -1)
2678         use_value = 1016;
2679     for (base_no = 0; base_no < num_bases && ord_no < 32; base_no++)
2680     {
2681         int r;
2682         attent attp;
2683         data1_local_attribute *local_attr;
2684
2685         if ((r=att_getentbyatt (zh, &attp, attributeset, use_value)))
2686         {
2687             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d",
2688                   attributeset, use_value);
2689             if (r == -1)
2690                 zh->errCode = 114;
2691             else
2692                 zh->errCode = 121;
2693             *num_entries = 0;
2694             return;
2695         }
2696         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2697         {
2698             zh->errString = basenames[base_no];
2699             zh->errCode = 109; /* Database unavailable */
2700             *num_entries = 0;
2701             return;
2702         }
2703         for (local_attr = attp.local_attributes; local_attr && ord_no < 32;
2704              local_attr = local_attr->next)
2705         {
2706             int ord;
2707
2708             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
2709                                          local_attr->local);
2710             if (ord > 0)
2711                 ords[ord_no++] = ord;
2712         }
2713     }
2714     if (ord_no == 0)
2715     {
2716         *num_entries = 0;
2717         zh->errCode = 113;
2718         return;
2719     }
2720     /* prepare dictionary scanning */
2721     before = pos-1;
2722     after = 1+num-pos;
2723     scan_info_array = (struct scan_info *)
2724         odr_malloc (stream, ord_no * sizeof(*scan_info_array));
2725     for (i = 0; i < ord_no; i++)
2726     {
2727         int j, prefix_len = 0;
2728         int before_tmp = before, after_tmp = after;
2729         struct scan_info *scan_info = scan_info_array + i;
2730         struct rpn_char_map_info rcmi;
2731
2732         rpn_char_map_prepare (zh->reg, reg_id, &rcmi);
2733
2734         scan_info->before = before;
2735         scan_info->after = after;
2736         scan_info->odr = stream;
2737
2738         scan_info->list = (struct scan_info_entry *)
2739             odr_malloc (stream, (before+after) * sizeof(*scan_info->list));
2740         for (j = 0; j<before+after; j++)
2741             scan_info->list[j].term = NULL;
2742
2743         prefix_len += key_SU_encode (ords[i], termz + prefix_len);
2744         termz[prefix_len++] = reg_id;
2745         termz[prefix_len] = 0;
2746         strcpy (scan_info->prefix, termz);
2747
2748         trans_scan_term (zh, zapt, termz+prefix_len, reg_id);
2749                     
2750         dict_scan (zh->reg->dict, termz, &before_tmp, &after_tmp,
2751                    scan_info, scan_handle);
2752     }
2753     glist = (ZebraScanEntry *)
2754         odr_malloc (stream, (before+after)*sizeof(*glist));
2755
2756     /* consider terms after main term */
2757     for (i = 0; i < ord_no; i++)
2758         ptr[i] = before;
2759     
2760     *is_partial = 0;
2761     for (i = 0; i<after; i++)
2762     {
2763         int j, j0 = -1;
2764         const char *mterm = NULL;
2765         const char *tst;
2766         RSET rset;
2767         
2768         for (j = 0; j < ord_no; j++)
2769         {
2770             if (ptr[j] < before+after &&
2771                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2772                 (!mterm || strcmp (tst, mterm) < 0))
2773             {
2774                 j0 = j;
2775                 mterm = tst;
2776             }
2777         }
2778         if (j0 == -1)
2779             break;
2780         scan_term_untrans (zh, stream->mem, reg_id,
2781                            &glist[i+before].term, mterm);
2782         rset = rset_trunc (zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
2783                            glist[i+before].term, strlen(glist[i+before].term),
2784                            NULL, 0, zapt->term->which);
2785
2786         ptr[j0]++;
2787         for (j = j0+1; j<ord_no; j++)
2788         {
2789             if (ptr[j] < before+after &&
2790                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2791                 !strcmp (tst, mterm))
2792             {
2793                 rset_bool_parms bool_parms;
2794                 RSET rset2;
2795
2796                 rset2 =
2797                    rset_trunc (zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
2798                                glist[i+before].term,
2799                                strlen(glist[i+before].term), NULL, 0,
2800                                zapt->term->which);
2801
2802                 bool_parms.key_size = sizeof(struct it_key);
2803                 bool_parms.cmp = key_compare_it;
2804                 bool_parms.rset_l = rset;
2805                 bool_parms.rset_r = rset2;
2806               
2807                 rset = rset_create (rset_kind_or, &bool_parms);
2808
2809                 ptr[j]++;
2810             }
2811         }
2812         count_set (rset, &glist[i+before].occurrences);
2813         rset_delete (rset);
2814     }
2815     if (i < after)
2816     {
2817         *num_entries -= (after-i);
2818         *is_partial = 1;
2819     }
2820
2821     /* consider terms before main term */
2822     for (i = 0; i<ord_no; i++)
2823         ptr[i] = 0;
2824
2825     for (i = 0; i<before; i++)
2826     {
2827         int j, j0 = -1;
2828         const char *mterm = NULL;
2829         const char *tst;
2830         RSET rset;
2831         
2832         for (j = 0; j <ord_no; j++)
2833         {
2834             if (ptr[j] < before &&
2835                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2836                 (!mterm || strcmp (tst, mterm) > 0))
2837             {
2838                 j0 = j;
2839                 mterm = tst;
2840             }
2841         }
2842         if (j0 == -1)
2843             break;
2844
2845         scan_term_untrans (zh, stream->mem, reg_id,
2846                            &glist[before-1-i].term, mterm);
2847
2848         rset = rset_trunc
2849                (zh, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1,
2850                 glist[before-1-i].term, strlen(glist[before-1-i].term),
2851                 NULL, 0, zapt->term->which);
2852
2853         ptr[j0]++;
2854
2855         for (j = j0+1; j<ord_no; j++)
2856         {
2857             if (ptr[j] < before &&
2858                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2859                 !strcmp (tst, mterm))
2860             {
2861                 rset_bool_parms bool_parms;
2862                 RSET rset2;
2863
2864                 rset2 = rset_trunc (zh,
2865                          &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1,
2866                                     glist[before-1-i].term,
2867                                     strlen(glist[before-1-i].term), NULL, 0,
2868                                     zapt->term->which);
2869
2870                 bool_parms.key_size = sizeof(struct it_key);
2871                 bool_parms.cmp = key_compare_it;
2872                 bool_parms.rset_l = rset;
2873                 bool_parms.rset_r = rset2;
2874               
2875                 rset = rset_create (rset_kind_or, &bool_parms);
2876
2877                 ptr[j]++;
2878             }
2879         }
2880         count_set (rset, &glist[before-1-i].occurrences);
2881         rset_delete (rset);
2882     }
2883     i = before-i;
2884     if (i)
2885     {
2886         *is_partial = 1;
2887         *position -= i;
2888         *num_entries -= i;
2889     }
2890     *list = glist + i;               /* list is set to first 'real' entry */
2891     
2892     logf (LOG_DEBUG, "position = %d, num_entries = %d",
2893           *position, *num_entries);
2894     if (zh->errCode)
2895         logf (LOG_DEBUG, "scan error: %d", zh->errCode);
2896 }
2897