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