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