bd0ceab8f68489439e84a0c49f9a4b4c87b97ec5
[idzebra-moved-to-github.git] / index / zrpn.c
1 /* $Id: zrpn.c,v 1.122 2002-08-28 19:52:29 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 (zh->iconv_to_utf8 != 0)
1109         {
1110             char *inbuf = term->u.general->buf;
1111             size_t inleft = term->u.general->len;
1112             char *outbuf = termz;
1113             size_t outleft = IT_MAX_WORD-1;
1114             size_t ret;
1115
1116             yaz_log (LOG_DEBUG, "converting general from ISO-8859-1");
1117             ret = yaz_iconv(zh->iconv_to_utf8, &inbuf, &inleft,
1118                         &outbuf, &outleft);
1119             if (ret == (size_t)(-1))
1120             {
1121                 ret = yaz_iconv(zh->iconv_to_utf8, 0, 0, 0, 0);
1122                 zh->errCode = 125;
1123                 return -1;
1124             }
1125             *outbuf = 0;
1126             return 0;
1127         }
1128         sizez = term->u.general->len;
1129         if (sizez > IT_MAX_WORD-1)
1130             sizez = IT_MAX_WORD-1;
1131         memcpy (termz, term->u.general->buf, sizez);
1132         termz[sizez] = '\0';
1133         break;
1134     case Z_Term_characterString:
1135         sizez = strlen(term->u.characterString);
1136         if (sizez > IT_MAX_WORD-1)
1137             sizez = IT_MAX_WORD-1;
1138         memcpy (termz, term->u.characterString, sizez);
1139         termz[sizez] = '\0';
1140         break;
1141     default:
1142         zh->errCode = 124;
1143     }
1144     return 0;
1145 }
1146
1147 static void trans_scan_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1148                              char *termz, int reg_type)
1149 {
1150     Z_Term *term = zapt->term;
1151     const char **map;
1152     const char *cp = (const char *) term->u.general->buf;
1153     const char *cp_end = cp + term->u.general->len;
1154     const char *src;
1155     int i = 0;
1156     const char *space_map = NULL;
1157     int len;
1158     
1159     while ((len = (cp_end - cp)) > 0)
1160     {
1161         map = zebra_maps_input (zh->reg->zebra_maps, reg_type, &cp, len);
1162         if (**map == *CHR_SPACE)
1163             space_map = *map;
1164         else
1165         {
1166             if (i && space_map)
1167                 for (src = space_map; *src; src++)
1168                     termz[i++] = *src;
1169             space_map = NULL;
1170             for (src = *map; *src; src++)
1171                 termz[i++] = *src;
1172         }
1173     }
1174     termz[i] = '\0';
1175 }
1176
1177 static RSET rpn_prox (ZebraHandle zh, RSET *rset, int rset_no,
1178                       int ordered, int exclusion, int relation, int distance)
1179 {
1180     int i;
1181     RSFD *rsfd;
1182     int  *more;
1183     struct it_key **buf;
1184     RSET result;
1185     char prox_term[1024];
1186     int length_prox_term = 0;
1187     int min_nn = 10000000;
1188     int term_index;
1189     int term_type = Z_Term_characterString;
1190     const char *flags = NULL;
1191     
1192     rsfd = (RSFD *) xmalloc (sizeof(*rsfd)*rset_no);
1193     more = (int *) xmalloc (sizeof(*more)*rset_no);
1194     buf = (struct it_key **) xmalloc (sizeof(*buf)*rset_no);
1195
1196     *prox_term = '\0';
1197     for (i = 0; i<rset_no; i++)
1198     {
1199         int j;
1200         for (j = 0; j<rset[i]->no_rset_terms; j++)
1201         {
1202             const char *nflags = rset[i]->rset_terms[j]->flags;
1203             char *term = rset[i]->rset_terms[j]->name;
1204             int lterm = strlen(term);
1205             if (lterm + length_prox_term < sizeof(prox_term)-1)
1206             {
1207                 if (length_prox_term)
1208                     prox_term[length_prox_term++] = ' ';
1209                 strcpy (prox_term + length_prox_term, term);
1210                 length_prox_term += lterm;
1211             }
1212             if (min_nn > rset[i]->rset_terms[j]->nn)
1213                 min_nn = rset[i]->rset_terms[j]->nn;
1214             flags = nflags;
1215             term_type = rset[i]->rset_terms[j]->type;
1216
1217             /* only if all term types are of type characterString .. */
1218             /* the resulting term is of that type */
1219             if (term_type != Z_Term_characterString)
1220                 term_type = Z_Term_general;
1221         }
1222     }
1223     for (i = 0; i<rset_no; i++)
1224     {
1225         buf[i] = 0;
1226         rsfd[i] = 0;
1227     }
1228     for (i = 0; i<rset_no; i++)
1229     {
1230         buf[i] = (struct it_key *) xmalloc (sizeof(**buf));
1231         rsfd[i] = rset_open (rset[i], RSETF_READ);
1232         if (!(more[i] = rset_read (rset[i], rsfd[i], buf[i], &term_index)))
1233             break;
1234     }
1235     if (i != rset_no)
1236     {
1237         /* at least one is empty ... return null set */
1238         rset_null_parms parms;
1239         
1240         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1241                                             flags, term_type);
1242         parms.rset_term->nn = 0;
1243         result = rset_create (rset_kind_null, &parms);
1244     }
1245     else if (ordered && relation == 3 && exclusion == 0 && distance == 1)
1246     {
1247         /* special proximity case = phrase search ... */
1248         rset_temp_parms parms;
1249         RSFD rsfd_result;
1250
1251         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1252                                             flags, term_type);
1253         parms.rset_term->nn = min_nn;
1254         parms.cmp = key_compare_it;
1255         parms.key_size = sizeof (struct it_key);
1256         parms.temp_path = res_get (zh->res, "setTmpDir");
1257         result = rset_create (rset_kind_temp, &parms);
1258         rsfd_result = rset_open (result, RSETF_WRITE);
1259         
1260         while (*more)
1261         {
1262             for (i = 1; i<rset_no; i++)
1263             {
1264                 int cmp;
1265                 
1266                 if (!more[i])
1267                 {
1268                     *more = 0;
1269                     break;
1270                 }
1271                 cmp = key_compare_it (buf[i], buf[i-1]);
1272                 if (cmp > 1)
1273                 {
1274                     more[i-1] = rset_read (rset[i-1], rsfd[i-1],
1275                                            buf[i-1], &term_index);
1276                     break;
1277                 }
1278                 else if (cmp == 1)
1279                 {
1280                     if (buf[i-1]->seqno+1 != buf[i]->seqno)
1281                     {
1282                         more[i-1] = rset_read (rset[i-1], rsfd[i-1],
1283                                                buf[i-1], &term_index);
1284                         break;
1285                     }
1286                 }
1287                 else
1288                 {
1289                     more[i] = rset_read (rset[i], rsfd[i], buf[i],
1290                                          &term_index);
1291                     break;
1292                 }
1293             }
1294             if (i == rset_no)
1295             {
1296                 rset_write (result, rsfd_result, buf[0]);
1297                 more[0] = rset_read (*rset, *rsfd, *buf, &term_index);
1298             }
1299         }
1300         rset_close (result, rsfd_result);
1301     }
1302     else if (rset_no == 2)
1303     {
1304         /* generic proximity case (two input sets only) ... */
1305         rset_temp_parms parms;
1306         RSFD rsfd_result;
1307
1308         logf (LOG_LOG, "generic prox, dist = %d, relation = %d, ordered =%d, exclusion=%d",
1309               distance, relation, ordered, exclusion);
1310         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1311                                             flags, term_type);
1312         parms.rset_term->nn = min_nn;
1313         parms.cmp = key_compare_it;
1314         parms.key_size = sizeof (struct it_key);
1315         parms.temp_path = res_get (zh->res, "setTmpDir");
1316         result = rset_create (rset_kind_temp, &parms);
1317         rsfd_result = rset_open (result, RSETF_WRITE);
1318
1319         while (more[0] && more[1]) 
1320         {
1321             int cmp = key_compare_it (buf[0], buf[1]);
1322             if (cmp < -1)
1323                 more[0] = rset_read (rset[0], rsfd[0], buf[0], &term_index);
1324             else if (cmp > 1)
1325                 more[1] = rset_read (rset[1], rsfd[1], buf[1], &term_index);
1326             else
1327             {
1328                 int sysno = buf[0]->sysno;
1329                 int seqno[500];
1330                 int n = 0;
1331                 
1332                 seqno[n++] = buf[0]->seqno;
1333                 while ((more[0] = rset_read (rset[0], rsfd[0], buf[0],
1334                                              &term_index)) &&
1335                        sysno == buf[0]->sysno)
1336                     if (n < 500)
1337                         seqno[n++] = buf[0]->seqno;
1338                 do
1339                 {
1340                     for (i = 0; i<n; i++)
1341                     {
1342                         int diff = buf[1]->seqno - seqno[i];
1343                         int excl = exclusion;
1344                         if (!ordered && diff < 0)
1345                             diff = -diff;
1346                         switch (relation)
1347                         {
1348                         case 1:      /* < */
1349                             if (diff < distance && diff >= 0)
1350                                 excl = !excl;
1351                             break;
1352                         case 2:      /* <= */
1353                             if (diff <= distance && diff >= 0)
1354                                 excl = !excl;
1355                             break;
1356                         case 3:      /* == */
1357                             if (diff == distance && diff >= 0)
1358                                 excl = !excl;
1359                             break;
1360                         case 4:      /* >= */
1361                             if (diff >= distance && diff >= 0)
1362                                 excl = !excl;
1363                             break;
1364                         case 5:      /* > */
1365                             if (diff > distance && diff >= 0)
1366                                 excl = !excl;
1367                             break;
1368                         case 6:      /* != */
1369                             if (diff != distance && diff >= 0)
1370                                 excl = !excl;
1371                             break;
1372                         }
1373                         if (excl)
1374                         {
1375                             rset_write (result, rsfd_result, buf[1]);
1376                             break;
1377                         }
1378                     }
1379                 } while ((more[1] = rset_read (rset[1], rsfd[1], buf[1],
1380                                                &term_index)) &&
1381                          sysno == buf[1]->sysno);
1382             }
1383         }
1384         rset_close (result, rsfd_result);
1385     }
1386     else
1387     {
1388         rset_null_parms parms;
1389         
1390         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1391                                             flags, term_type);
1392         parms.rset_term->nn = 0;
1393         result = rset_create (rset_kind_null, &parms);
1394     }
1395     for (i = 0; i<rset_no; i++)
1396     {
1397         if (rsfd[i])
1398             rset_close (rset[i], rsfd[i]);
1399         xfree (buf[i]);
1400     }
1401     xfree (buf);
1402     xfree (more);
1403     xfree (rsfd);
1404     return result;
1405 }
1406
1407
1408 char *normalize_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1409                      const char *termz, NMEM stream, unsigned reg_id)
1410 {
1411     WRBUF wrbuf = 0;
1412     AttrType truncation;
1413     int truncation_value;
1414     char *ex_list = 0;
1415
1416     attr_init (&truncation, zapt, 5);
1417     truncation_value = attr_find (&truncation, NULL);
1418
1419     switch (truncation_value)
1420     {
1421     default:
1422         ex_list = "";
1423         break;
1424     case 101:
1425         ex_list = "#";
1426         break;
1427     case 102:
1428     case 103:
1429         ex_list = 0;
1430         break;
1431     case 104:
1432         ex_list = "!#";
1433         break;
1434     case 105:
1435         ex_list = "!*";
1436         break;
1437     }
1438     if (ex_list)
1439         wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, ex_list,
1440                               termz, strlen(termz));
1441     if (!wrbuf)
1442         return nmem_strdup(stream, termz);
1443     else
1444     {
1445         char *buf = (char*) nmem_malloc (stream, wrbuf_len(wrbuf)+1);
1446         memcpy (buf, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
1447         buf[wrbuf_len(wrbuf)] = '\0';
1448         return buf;
1449     }
1450 }
1451
1452 static void grep_info_delete (struct grep_info *grep_info)
1453 {
1454 #ifdef TERM_COUNT
1455     xfree(grep_info->term_no);
1456 #endif
1457     xfree (grep_info->isam_p_buf);
1458 }
1459
1460 static int grep_info_prepare (ZebraHandle zh,
1461                               Z_AttributesPlusTerm *zapt,
1462                               struct grep_info *grep_info,
1463                               int reg_type,
1464                               NMEM stream)
1465 {
1466     AttrType termset;
1467     int termset_value_numeric;
1468     const char *termset_value_string;
1469
1470 #ifdef TERM_COUNT
1471     grep_info->term_no = 0;
1472 #endif
1473     grep_info->isam_p_size = 0;
1474     grep_info->isam_p_buf = NULL;
1475     grep_info->zh = zh;
1476     grep_info->reg_type = reg_type;
1477     grep_info->termset = 0;
1478
1479     if (!zapt)
1480         return 0;
1481     attr_init (&termset, zapt, 8);
1482     termset_value_numeric =
1483         attr_find_ex (&termset, NULL, &termset_value_string);
1484     if (termset_value_numeric != -1)
1485     {
1486         char resname[32];
1487         const char *termset_name = 0;
1488         if (termset_value_numeric != -2)
1489         {
1490     
1491             sprintf (resname, "%d", termset_value_numeric);
1492             termset_name = resname;
1493         }
1494         else
1495             termset_name = termset_value_string;
1496         logf (LOG_LOG, "creating termset set %s", termset_name);
1497         grep_info->termset = resultSetAdd (zh, termset_name, 1);
1498         if (!grep_info->termset)
1499         {
1500             zh->errCode = 128;
1501             zh->errString = nmem_strdup (stream, termset_name);
1502             return -1;
1503         }
1504     }
1505     return 0;
1506 }
1507                                
1508
1509 static RSET rpn_search_APT_phrase (ZebraHandle zh,
1510                                    Z_AttributesPlusTerm *zapt,
1511                                    const char *termz_org,
1512                                    oid_value attributeSet,
1513                                    NMEM stream,
1514                                    int reg_type, int complete_flag,
1515                                    const char *rank_type, int xpath_use,
1516                                    int num_bases, char **basenames)
1517 {
1518     char term_dst[IT_MAX_WORD+1];
1519     RSET rset[60], result;
1520     int i, rset_no = 0;
1521     struct grep_info grep_info;
1522     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1523     const char *termp = termz;
1524
1525     *term_dst = 0;
1526     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1527         return 0;
1528     while (1)
1529     { 
1530         logf (LOG_DEBUG, "APT_phrase termp=%s", termp);
1531         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1532                                     stream, &grep_info,
1533                                     reg_type, complete_flag,
1534                                     num_bases, basenames,
1535                                     term_dst, rank_type,
1536                                     xpath_use);
1537         if (!rset[rset_no])
1538             break;
1539         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1540             break;
1541     }
1542     grep_info_delete (&grep_info);
1543     if (rset_no == 0)
1544     {
1545         rset_null_parms parms;
1546         
1547         parms.rset_term = rset_term_create (termz, -1, rank_type,
1548                                             zapt->term->which);
1549         return rset_create (rset_kind_null, &parms);
1550     }
1551     else if (rset_no == 1)
1552         return (rset[0]);
1553     result = rpn_prox (zh, rset, rset_no, 1, 0, 3, 1);
1554     for (i = 0; i<rset_no; i++)
1555         rset_delete (rset[i]);
1556     return result;
1557 }
1558
1559 static RSET rpn_search_APT_or_list (ZebraHandle zh,
1560                                     Z_AttributesPlusTerm *zapt,
1561                                     const char *termz_org,
1562                                     oid_value attributeSet,
1563                                     NMEM stream,
1564                                     int reg_type, int complete_flag,
1565                                     const char *rank_type,
1566                                     int xpath_use,
1567                                     int num_bases, char **basenames)
1568 {
1569     char term_dst[IT_MAX_WORD+1];
1570     RSET rset[60], result;
1571     int i, rset_no = 0;
1572     struct grep_info grep_info;
1573     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1574     const char *termp = termz;
1575
1576     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1577         return 0;
1578     while (1)
1579     { 
1580         logf (LOG_DEBUG, "APT_or_list termp=%s", termp);
1581         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1582                                     stream, &grep_info,
1583                                     reg_type, complete_flag,
1584                                     num_bases, basenames,
1585                                     term_dst, rank_type,
1586                                     xpath_use);
1587         if (!rset[rset_no])
1588             break;
1589         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1590             break;
1591     }
1592     grep_info_delete (&grep_info);
1593     if (rset_no == 0)
1594     {
1595         rset_null_parms parms;
1596         
1597         parms.rset_term = rset_term_create (termz, -1, rank_type,
1598                                             zapt->term->which);
1599         return rset_create (rset_kind_null, &parms);
1600     }
1601     result = rset[0];
1602     for (i = 1; i<rset_no; i++)
1603     {
1604         rset_bool_parms bool_parms;
1605
1606         bool_parms.rset_l = result;
1607         bool_parms.rset_r = rset[i];
1608         bool_parms.key_size = sizeof(struct it_key);
1609         bool_parms.cmp = key_compare_it;
1610         result = rset_create (rset_kind_or, &bool_parms);
1611     }
1612     return result;
1613 }
1614
1615 static RSET rpn_search_APT_and_list (ZebraHandle zh,
1616                                      Z_AttributesPlusTerm *zapt,
1617                                      const char *termz_org,
1618                                      oid_value attributeSet,
1619                                      NMEM stream,
1620                                      int reg_type, int complete_flag,
1621                                      const char *rank_type, 
1622                                      int xpath_use,
1623                                      int num_bases, char **basenames)
1624 {
1625     char term_dst[IT_MAX_WORD+1];
1626     RSET rset[60], result;
1627     int i, rset_no = 0;
1628     struct grep_info grep_info;
1629     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1630     const char *termp = termz;
1631
1632     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1633         return 0;
1634     while (1)
1635     { 
1636         logf (LOG_DEBUG, "APT_and_list termp=%s", termp);
1637         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1638                                     stream, &grep_info,
1639                                     reg_type, complete_flag,
1640                                     num_bases, basenames,
1641                                     term_dst, rank_type,
1642                                     xpath_use);
1643         if (!rset[rset_no])
1644             break;
1645         assert (rset[rset_no]);
1646         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1647             break;
1648     }
1649     grep_info_delete (&grep_info);
1650     if (rset_no == 0)
1651     {
1652         rset_null_parms parms;
1653         
1654         parms.rset_term = rset_term_create (termz, -1, rank_type,
1655                                             zapt->term->which);
1656         return rset_create (rset_kind_null, &parms);
1657     }
1658     result = rset[0];
1659     for (i = 1; i<rset_no; i++)
1660     {
1661         rset_bool_parms bool_parms;
1662
1663         bool_parms.rset_l = result;
1664         bool_parms.rset_r = rset[i];
1665         bool_parms.key_size = sizeof(struct it_key);
1666         bool_parms.cmp = key_compare_it;
1667         result = rset_create (rset_kind_and, &bool_parms);
1668     }
1669     return result;
1670 }
1671
1672 static int numeric_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1673                              const char **term_sub,
1674                              char *term_dict,
1675                              oid_value attributeSet,
1676                              struct grep_info *grep_info,
1677                              int *max_pos,
1678                              int reg_type,
1679                              char *term_dst)
1680 {
1681     AttrType relation;
1682     int relation_value;
1683     int term_value;
1684     int r;
1685     char *term_tmp = term_dict + strlen(term_dict);
1686
1687     attr_init (&relation, zapt, 2);
1688     relation_value = attr_find (&relation, NULL);
1689
1690     logf (LOG_DEBUG, "numeric relation value=%d", relation_value);
1691
1692     if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub, term_tmp, 1,
1693                    term_dst))
1694         return 0;
1695     term_value = atoi (term_tmp);
1696     switch (relation_value)
1697     {
1698     case 1:
1699         logf (LOG_DEBUG, "Relation <");
1700         gen_regular_rel (term_tmp, term_value-1, 1);
1701         break;
1702     case 2:
1703         logf (LOG_DEBUG, "Relation <=");
1704         gen_regular_rel (term_tmp, term_value, 1);
1705         break;
1706     case 4:
1707         logf (LOG_DEBUG, "Relation >=");
1708         gen_regular_rel (term_tmp, term_value, 0);
1709         break;
1710     case 5:
1711         logf (LOG_DEBUG, "Relation >");
1712         gen_regular_rel (term_tmp, term_value+1, 0);
1713         break;
1714     case 3:
1715     default:
1716         logf (LOG_DEBUG, "Relation =");
1717         sprintf (term_tmp, "(0*%d)", term_value);
1718     }
1719     logf (LOG_DEBUG, "dict_lookup_grep: %s", term_tmp);
1720     r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info, max_pos,
1721                           0, grep_handle);
1722     if (r)
1723         logf (LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
1724     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1725     return 1;
1726 }
1727
1728 static int numeric_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1729                          const char **term_sub, 
1730                          oid_value attributeSet, struct grep_info *grep_info,
1731                          int reg_type, int complete_flag,
1732                          int num_bases, char **basenames,
1733                          char *term_dst)
1734 {
1735     char term_dict[2*IT_MAX_WORD+2];
1736     int r, base_no;
1737     AttrType use;
1738     int use_value;
1739     oid_value curAttributeSet = attributeSet;
1740     const char *termp;
1741     struct rpn_char_map_info rcmi;
1742
1743     rpn_char_map_prepare (zh->reg, reg_type, &rcmi);
1744     attr_init (&use, zapt, 1);
1745     use_value = attr_find (&use, &curAttributeSet);
1746     logf (LOG_DEBUG, "numeric_term, use value %d", use_value);
1747
1748     if (use_value == -1)
1749         use_value = 1016;
1750
1751     for (base_no = 0; base_no < num_bases; base_no++)
1752     {
1753         attent attp;
1754         data1_local_attribute *local_attr;
1755         int max_pos, prefix_len = 0;
1756
1757         termp = *term_sub;
1758         if ((r=att_getentbyatt (zh, &attp, curAttributeSet, use_value)))
1759         {
1760             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
1761                   curAttributeSet, use_value, r);
1762             if (r == -1)
1763                 zh->errCode = 114;
1764             else
1765                 zh->errCode = 121;
1766             return -1;
1767         }
1768         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
1769         {
1770             zh->errCode = 109; /* Database unavailable */
1771             zh->errString = basenames[base_no];
1772             return -1;
1773         }
1774         for (local_attr = attp.local_attributes; local_attr;
1775              local_attr = local_attr->next)
1776         {
1777             int ord;
1778             char ord_buf[32];
1779             int i, ord_len;
1780
1781             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
1782                                           local_attr->local);
1783             if (ord < 0)
1784                 continue;
1785             if (prefix_len)
1786                 term_dict[prefix_len++] = '|';
1787             else
1788                 term_dict[prefix_len++] = '(';
1789
1790             ord_len = key_SU_encode (ord, ord_buf);
1791             for (i = 0; i<ord_len; i++)
1792             {
1793                 term_dict[prefix_len++] = 1;
1794                 term_dict[prefix_len++] = ord_buf[i];
1795             }
1796         }
1797         if (!prefix_len)
1798         {
1799             zh->errCode = 114;
1800             return -1;
1801         }
1802         term_dict[prefix_len++] = ')';        
1803         term_dict[prefix_len++] = 1;
1804         term_dict[prefix_len++] = reg_type;
1805         logf (LOG_DEBUG, "reg_type = %d", term_dict[prefix_len-1]);
1806         term_dict[prefix_len] = '\0';
1807         if (!numeric_relation (zh, zapt, &termp, term_dict,
1808                                attributeSet, grep_info, &max_pos, reg_type,
1809                                term_dst))
1810             return 0;
1811     }
1812     *term_sub = termp;
1813     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1814     return 1;
1815 }
1816
1817 static RSET rpn_search_APT_numeric (ZebraHandle zh,
1818                                     Z_AttributesPlusTerm *zapt,
1819                                     const char *termz,
1820                                     oid_value attributeSet,
1821                                     NMEM stream,
1822                                     int reg_type, int complete_flag,
1823                                     const char *rank_type,
1824                                     int num_bases, char **basenames)
1825 {
1826     char term_dst[IT_MAX_WORD+1];
1827     const char *termp = termz;
1828     RSET rset[60], result;
1829     int i, r, rset_no = 0;
1830     struct grep_info grep_info;
1831
1832     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1833         return 0;
1834     while (1)
1835     { 
1836         logf (LOG_DEBUG, "APT_numeric termp=%s", termp);
1837         grep_info.isam_p_indx = 0;
1838         r = numeric_term (zh, zapt, &termp, attributeSet, &grep_info,
1839                           reg_type, complete_flag, num_bases, basenames,
1840                           term_dst);
1841         if (r < 1)
1842             break;
1843         logf (LOG_DEBUG, "term: %s", term_dst);
1844         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
1845                                     grep_info.isam_p_indx, term_dst,
1846                                     strlen(term_dst), rank_type,
1847                                     0 /* preserve position */,
1848                                     zapt->term->which);
1849         assert (rset[rset_no]);
1850         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1851             break;
1852     }
1853     grep_info_delete (&grep_info);
1854     if (rset_no == 0)
1855     {
1856         rset_null_parms parms;
1857         
1858         parms.rset_term = rset_term_create (term_dst, -1, rank_type,
1859                                             zapt->term->which);
1860         return rset_create (rset_kind_null, &parms);
1861     }
1862     result = rset[0];
1863     for (i = 1; i<rset_no; i++)
1864     {
1865         rset_bool_parms bool_parms;
1866
1867         bool_parms.rset_l = result;
1868         bool_parms.rset_r = rset[i];
1869         bool_parms.key_size = sizeof(struct it_key);
1870         bool_parms.cmp = key_compare_it;
1871         result = rset_create (rset_kind_and, &bool_parms);
1872     }
1873     return result;
1874 }
1875
1876 static RSET rpn_search_APT_local (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1877                                   const char *termz,
1878                                   oid_value attributeSet,
1879                                   NMEM stream,
1880                                   const char *rank_type)
1881 {
1882     RSET result;
1883     RSFD rsfd;
1884     struct it_key key;
1885     rset_temp_parms parms;
1886
1887     parms.rset_term = rset_term_create (termz, -1, rank_type,
1888                                         zapt->term->which);
1889     parms.cmp = key_compare_it;
1890     parms.key_size = sizeof (struct it_key);
1891     parms.temp_path = res_get (zh->res, "setTmpDir");
1892     result = rset_create (rset_kind_temp, &parms);
1893     rsfd = rset_open (result, RSETF_WRITE);
1894
1895     key.sysno = atoi (termz);
1896     key.seqno = 1;
1897     if (key.sysno <= 0)
1898         key.sysno = 1;
1899     rset_write (result, rsfd, &key);
1900     rset_close (result, rsfd);
1901     return result;
1902 }
1903
1904 static RSET rpn_sort_spec (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1905                            oid_value attributeSet, NMEM stream,
1906                            Z_SortKeySpecList *sort_sequence,
1907                            const char *rank_type)
1908 {
1909     rset_null_parms parms;    
1910     int i;
1911     int sort_relation_value;
1912     AttrType sort_relation_type;
1913     int use_value;
1914     AttrType use_type;
1915     Z_SortKeySpec *sks;
1916     Z_SortKey *sk;
1917     Z_AttributeElement *ae;
1918     int oid[OID_SIZE];
1919     oident oe;
1920     char termz[20];
1921     
1922     attr_init (&sort_relation_type, zapt, 7);
1923     sort_relation_value = attr_find (&sort_relation_type, &attributeSet);
1924
1925     attr_init (&use_type, zapt, 1);
1926     use_value = attr_find (&use_type, &attributeSet);
1927
1928     if (!sort_sequence->specs)
1929     {
1930         sort_sequence->num_specs = 10;
1931         sort_sequence->specs = (Z_SortKeySpec **)
1932             nmem_malloc (stream, sort_sequence->num_specs *
1933                          sizeof(*sort_sequence->specs));
1934         for (i = 0; i<sort_sequence->num_specs; i++)
1935             sort_sequence->specs[i] = 0;
1936     }
1937     if (zapt->term->which != Z_Term_general)
1938         i = 0;
1939     else
1940         i = atoi_n ((char *) zapt->term->u.general->buf,
1941                     zapt->term->u.general->len);
1942     if (i >= sort_sequence->num_specs)
1943         i = 0;
1944     sprintf (termz, "%d", i);
1945
1946     oe.proto = PROTO_Z3950;
1947     oe.oclass = CLASS_ATTSET;
1948     oe.value = attributeSet;
1949     if (!oid_ent_to_oid (&oe, oid))
1950         return 0;
1951
1952     sks = (Z_SortKeySpec *) nmem_malloc (stream, sizeof(*sks));
1953     sks->sortElement = (Z_SortElement *)
1954         nmem_malloc (stream, sizeof(*sks->sortElement));
1955     sks->sortElement->which = Z_SortElement_generic;
1956     sk = sks->sortElement->u.generic = (Z_SortKey *)
1957         nmem_malloc (stream, sizeof(*sk));
1958     sk->which = Z_SortKey_sortAttributes;
1959     sk->u.sortAttributes = (Z_SortAttributes *)
1960         nmem_malloc (stream, sizeof(*sk->u.sortAttributes));
1961
1962     sk->u.sortAttributes->id = oid;
1963     sk->u.sortAttributes->list = (Z_AttributeList *)
1964         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list));
1965     sk->u.sortAttributes->list->num_attributes = 1;
1966     sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
1967         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list->attributes));
1968     ae = *sk->u.sortAttributes->list->attributes = (Z_AttributeElement *)
1969         nmem_malloc (stream, sizeof(**sk->u.sortAttributes->list->attributes));
1970     ae->attributeSet = 0;
1971     ae->attributeType = (int *)
1972         nmem_malloc (stream, sizeof(*ae->attributeType));
1973     *ae->attributeType = 1;
1974     ae->which = Z_AttributeValue_numeric;
1975     ae->value.numeric = (int *)
1976         nmem_malloc (stream, sizeof(*ae->value.numeric));
1977     *ae->value.numeric = use_value;
1978
1979     sks->sortRelation = (int *)
1980         nmem_malloc (stream, sizeof(*sks->sortRelation));
1981     if (sort_relation_value == 1)
1982         *sks->sortRelation = Z_SortRelation_ascending;
1983     else if (sort_relation_value == 2)
1984         *sks->sortRelation = Z_SortRelation_descending;
1985     else 
1986         *sks->sortRelation = Z_SortRelation_ascending;
1987
1988     sks->caseSensitivity = (int *)
1989         nmem_malloc (stream, sizeof(*sks->caseSensitivity));
1990     *sks->caseSensitivity = 0;
1991
1992 #ifdef ASN_COMPILED
1993     sks->which = Z_SortKeySpec_null;
1994     sks->u.null = odr_nullval ();
1995 #else
1996     sks->missingValueAction = 0;
1997 #endif
1998
1999     sort_sequence->specs[i] = sks;
2000
2001     parms.rset_term = rset_term_create (termz, -1, rank_type,
2002                                         zapt->term->which);
2003     return rset_create (rset_kind_null, &parms);
2004 }
2005
2006 struct xpath_predicate {
2007     int which;
2008     union {
2009 #define XPATH_PREDICATE_RELATION 1
2010         struct {
2011             char *name;
2012             char *op;
2013             char *value;
2014         } relation;
2015 #define XPATH_PREDICATE_BOOLEAN 2
2016         struct {
2017             const char *op;
2018             struct xpath_predicate *left;
2019             struct xpath_predicate *right;
2020         } boolean;
2021     } u;
2022 };
2023
2024 struct xpath_location_step {
2025     char *part;
2026     struct xpath_predicate *predicate;
2027 };
2028
2029 static int parse_xpath(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
2030                        oid_value attributeSet,
2031                        struct xpath_location_step *xpath, NMEM mem)
2032 {
2033     oid_value curAttributeSet = attributeSet;
2034     AttrType use;
2035     const char *use_string = 0;
2036     const char *cp;
2037     int no = 0;
2038     
2039     attr_init (&use, zapt, 1);
2040     attr_find_ex (&use, &curAttributeSet, &use_string);
2041
2042     if (!use_string || *use_string != '/')
2043         return -1;
2044     cp = use_string;
2045     while (*cp)
2046     {
2047         int i = 0;
2048         while (*cp && !strchr("/[",*cp))
2049         {
2050             i++;
2051             cp++;
2052         }
2053         xpath[no].predicate = 0;
2054         xpath[no].part = nmem_malloc (mem, i+1);
2055         memcpy (xpath[no].part,  cp - i, i);
2056         xpath[no].part[i] = 0;
2057
2058         if (*cp == '[')
2059         {
2060             struct xpath_predicate *p = xpath[no].predicate =
2061                 nmem_malloc (mem, sizeof(struct xpath_predicate));
2062
2063             p->which = XPATH_PREDICATE_RELATION;
2064             cp++;
2065             while (*cp == ' ')
2066                 cp++;
2067
2068             for (i = 0; *cp && !strchr("><=] ", *cp); i++)
2069                 cp++;
2070             p->u.relation.name = nmem_malloc (mem, i+1);
2071             memcpy (p->u.relation.name, cp - i, i);
2072             p->u.relation.name[i] = 0;
2073             while (*cp == ' ')
2074                 cp++;
2075             if (*cp != ']')
2076             {
2077                 for (i = 0; *cp && strchr(">=<!", *cp); i++)
2078                     cp++;
2079
2080                 p->u.relation.op = nmem_malloc (mem, i+1);
2081                 if (i)
2082                     memcpy (p->u.relation.op, cp - i, i);
2083                 p->u.relation.op[i] = 0;
2084                 
2085                 while (*cp == ' ')
2086                     cp++;
2087                 
2088                 if (strchr("\"'", *cp))
2089                 {
2090                     cp++;
2091                     for (i = 0; *cp && !strchr("\"'", *cp); i++)
2092                         cp++;
2093
2094                     p->u.relation.value = nmem_malloc (mem, i+1);
2095                     if (i)
2096                         memcpy (p->u.relation.value, cp - i, i);
2097                     p->u.relation.value[i] = 0;
2098                     yaz_log (LOG_LOG, "value=%s", p->u.relation.value);
2099
2100                     cp++;
2101                 }                           
2102                 else
2103                 {
2104                     for (i = 0; *cp && !strchr(" ]", *cp); i++)
2105                         cp++;
2106                     p->u.relation.value = nmem_malloc (mem, i+1);
2107                     if (i)
2108                         memcpy (p->u.relation.value, cp - i, i);
2109                     p->u.relation.value[i] = 0;
2110                 }
2111                 while (*cp == ' ')
2112                     cp++;
2113             }
2114             if (*cp == ']')
2115                 cp++;
2116         } /* end of ] predicate */
2117         no++;
2118         if (*cp != '/')
2119             break;
2120         cp++;
2121     }
2122     return no;
2123 }
2124                 
2125
2126 static RSET xpath_trunc(ZebraHandle zh, NMEM stream,
2127                         int reg_type, const char *term, int use,
2128                         oid_value curAttributeSet)
2129 {
2130     RSET rset;
2131     struct grep_info grep_info;
2132     char term_dict[2048];
2133     char ord_buf[32];
2134     int prefix_len = 0;
2135     int ord = zebraExplain_lookupSU (zh->reg->zei, curAttributeSet, use);
2136     int ord_len, i, r, max_pos;
2137     int term_type = Z_Term_characterString;
2138     const char *flags = "void";
2139
2140     if (grep_info_prepare (zh, 0 /* zapt */, &grep_info, '0', stream))
2141     {
2142         rset_null_parms parms;
2143         
2144         parms.rset_term = rset_term_create (term, strlen(term),
2145                                             flags, term_type);
2146         parms.rset_term->nn = 0;
2147         return rset_create (rset_kind_null, &parms);
2148     }
2149
2150     if (ord < 0)
2151     {
2152         rset_null_parms parms;
2153         
2154         parms.rset_term = rset_term_create (term, strlen(term),
2155                                             flags, term_type);
2156         parms.rset_term->nn = 0;
2157         return rset_create (rset_kind_null, &parms);
2158     }
2159     if (prefix_len)
2160         term_dict[prefix_len++] = '|';
2161     else
2162         term_dict[prefix_len++] = '(';
2163     
2164     ord_len = key_SU_encode (ord, ord_buf);
2165     for (i = 0; i<ord_len; i++)
2166     {
2167         term_dict[prefix_len++] = 1;
2168         term_dict[prefix_len++] = ord_buf[i];
2169     }
2170     term_dict[prefix_len++] = ')';
2171     term_dict[prefix_len++] = 1;
2172     term_dict[prefix_len++] = reg_type;
2173     
2174     strcpy (term_dict+prefix_len, term);
2175     
2176     grep_info.isam_p_indx = 0;
2177     r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
2178                           &grep_info, &max_pos, 0, grep_handle);
2179     yaz_log (LOG_LOG, "%s %d positions", term,
2180              grep_info.isam_p_indx);
2181     rset = rset_trunc (zh, grep_info.isam_p_buf,
2182                        grep_info.isam_p_indx, term, strlen(term),
2183                        flags, 1, term_type);
2184     grep_info_delete (&grep_info);
2185     return rset;
2186 }
2187
2188 static RSET rpn_search_xpath (ZebraHandle zh,
2189                               oid_value attributeSet,
2190                               int num_bases, char **basenames,
2191                               NMEM stream, const char *rank_type, RSET rset,
2192                               int xpath_len, struct xpath_location_step *xpath)
2193 {
2194     oid_value curAttributeSet = attributeSet;
2195     int base_no;
2196     int i;
2197
2198     if (xpath_len < 0)
2199         return rset;
2200
2201     yaz_log (LOG_LOG, "len=%d", xpath_len);
2202     for (i = 0; i<xpath_len; i++)
2203     {
2204         yaz_log (LOG_LOG, "XPATH %d %s", i, xpath[i].part);
2205
2206     }
2207
2208     curAttributeSet = VAL_IDXPATH;
2209
2210     /*
2211       //a    ->    a/.*
2212       //a/b  ->    b/a/.*
2213       /a     ->    a/
2214       /a/b   ->    b/a/
2215
2216       /      ->    none
2217
2218    a[@attr=value]/b[@other=othervalue]
2219
2220  /e/@a val      range(e/,range(@a,freetext(w,1015,val),@a),e/)
2221  /a/b val       range(b/a/,freetext(w,1016,val),b/a/)
2222  /a/b/@c val    range(b/a/,range(@c,freetext(w,1016,val),@c),b/a/)
2223  /a/b[@c=y] val range(b/a/,freetext(w,1016,val),b/a/,@c=y)
2224  /a[@c=y]/b val range(a/,range(b/a/,freetext(w,1016,val),b/a/),a/,@c=y)
2225  /a[@c=x]/b[@c=y] range(a/,range(b/a/,freetext(w,1016,val),b/a/,@c=y),a/,@c=x)
2226       
2227     */
2228
2229     dict_grep_cmap (zh->reg->dict, 0, 0);
2230
2231     for (base_no = 0; base_no < num_bases; base_no++)
2232     {
2233         int level = xpath_len;
2234         int first_path = 1;
2235         
2236         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2237         {
2238             zh->errCode = 109; /* Database unavailable */
2239             zh->errString = basenames[base_no];
2240             return rset;
2241         }
2242         while (--level >= 0)
2243         {
2244             char xpath_rev[128];
2245             int i, len;
2246             rset_between_parms parms;
2247             RSET rset_start_tag = 0, rset_end_tag = 0, rset_attr = 0;
2248
2249             *xpath_rev = 0;
2250             len = 0;
2251             for (i = level; i >= 1; --i)
2252             {
2253                 const char *cp = xpath[i].part;
2254                 if (*cp)
2255                 {
2256                     for (;*cp; cp++)
2257                         if (*cp == '*')
2258                         {
2259                             memcpy (xpath_rev + len, "[^/]*", 5);
2260                             len += 5;
2261                         }
2262                         else if (*cp == ' ')
2263                         {
2264
2265                             xpath_rev[len++] = 1;
2266                             xpath_rev[len++] = ' ';
2267                         }
2268
2269                         else
2270                             xpath_rev[len++] = *cp;
2271                     xpath_rev[len++] = '/';
2272                 }
2273                 else if (i == 1)  /* // case */
2274                 {
2275                     xpath_rev[len++] = '.';
2276                     xpath_rev[len++] = '*';
2277                 }
2278             }
2279             xpath_rev[len] = 0;
2280
2281             if (xpath[level].predicate &&
2282                 xpath[level].predicate->which == XPATH_PREDICATE_RELATION &&
2283                 xpath[level].predicate->u.relation.name[0])
2284             {
2285                 char predicate_str[128];
2286
2287                 strcpy (predicate_str,
2288                         xpath[level].predicate->u.relation.name+1);
2289                 if (xpath[level].predicate->u.relation.value)
2290                 {
2291                     strcat (predicate_str, "=");
2292                     strcat (predicate_str,
2293                             xpath[level].predicate->u.relation.value);
2294                 }
2295                 rset_attr = xpath_trunc (
2296                     zh, stream, '0', predicate_str, 3, curAttributeSet);
2297             } 
2298             else 
2299             {
2300                 if (!first_path)
2301                     continue;
2302             }
2303             yaz_log (LOG_LOG, "xpath_rev (%d) = %s", level, xpath_rev);
2304             if (strlen(xpath_rev))
2305             {
2306                 rset_start_tag = xpath_trunc(zh, stream, 
2307                                          '0', xpath_rev, 1, curAttributeSet);
2308             
2309                 rset_end_tag = xpath_trunc(zh, stream,
2310                                        '0', xpath_rev, 2, curAttributeSet);
2311
2312                 parms.key_size = sizeof(struct it_key);
2313                 parms.cmp = key_compare_it;
2314                 parms.rset_l = rset_start_tag;
2315                 parms.rset_m = rset;
2316                 parms.rset_r = rset_end_tag;
2317                 parms.rset_attr = rset_attr;
2318                 parms.printer = key_print_it;
2319                 rset = rset_create (rset_kind_between, &parms);
2320             }
2321             first_path = 0;
2322         }
2323     }
2324
2325     return rset;
2326 }
2327
2328
2329
2330 static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
2331                             oid_value attributeSet, NMEM stream,
2332                             Z_SortKeySpecList *sort_sequence,
2333                             int num_bases, char **basenames)
2334 {
2335     unsigned reg_id;
2336     char *search_type = NULL;
2337     char rank_type[128];
2338     int complete_flag;
2339     int sort_flag;
2340     char termz[IT_MAX_WORD+1];
2341     RSET rset = 0;
2342     int xpath_len;
2343     int xpath_use = 0;
2344     struct xpath_location_step xpath[10];
2345
2346     zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2347                      rank_type, &complete_flag, &sort_flag);
2348     
2349     logf (LOG_DEBUG, "reg_id=%c", reg_id);
2350     logf (LOG_DEBUG, "complete_flag=%d", complete_flag);
2351     logf (LOG_DEBUG, "search_type=%s", search_type);
2352     logf (LOG_DEBUG, "rank_type=%s", rank_type);
2353
2354     if (trans_term (zh, zapt, termz))
2355         return 0;
2356
2357     if (sort_flag)
2358         return rpn_sort_spec (zh, zapt, attributeSet, stream, sort_sequence,
2359                               rank_type);
2360     xpath_len = parse_xpath(zh, zapt, attributeSet, xpath, stream);
2361     if (xpath_len >= 0)
2362     {
2363         xpath_use = 1016;
2364         if (xpath[xpath_len-1].part[0] == '@')
2365             xpath_use = 1015;
2366     }
2367
2368     if (!strcmp (search_type, "phrase"))
2369     {
2370         rset = rpn_search_APT_phrase (zh, zapt, termz, attributeSet, stream,
2371                                       reg_id, complete_flag, rank_type,
2372                                       xpath_use,
2373                                       num_bases, basenames);
2374     }
2375     else if (!strcmp (search_type, "and-list"))
2376     {
2377         rset = rpn_search_APT_and_list (zh, zapt, termz, attributeSet, stream,
2378                                         reg_id, complete_flag, rank_type,
2379                                         xpath_use,
2380                                         num_bases, basenames);
2381     }
2382     else if (!strcmp (search_type, "or-list"))
2383     {
2384         rset = rpn_search_APT_or_list (zh, zapt, termz, attributeSet, stream,
2385                                        reg_id, complete_flag, rank_type,
2386                                        xpath_use,
2387                                        num_bases, basenames);
2388     }
2389     else if (!strcmp (search_type, "local"))
2390     {
2391         rset = rpn_search_APT_local (zh, zapt, termz, attributeSet, stream,
2392                                      rank_type);
2393     }
2394     else if (!strcmp (search_type, "numeric"))
2395     {
2396         rset = rpn_search_APT_numeric (zh, zapt, termz, attributeSet, stream,
2397                                        reg_id, complete_flag, rank_type,
2398                                        num_bases, basenames);
2399     }
2400     else if (!strcmp (search_type, "always"))
2401     {
2402         rset = 0;
2403     }
2404     else
2405         zh->errCode = 118;
2406     return rpn_search_xpath (zh, attributeSet, num_bases, basenames,
2407                              stream, rank_type, rset, xpath_len, xpath);
2408 }
2409
2410 static RSET rpn_search_structure (ZebraHandle zh, Z_RPNStructure *zs,
2411                                   oid_value attributeSet, NMEM stream,
2412                                   Z_SortKeySpecList *sort_sequence,
2413                                   int num_bases, char **basenames)
2414 {
2415     RSET r = NULL;
2416     if (zs->which == Z_RPNStructure_complex)
2417     {
2418         Z_Operator *zop = zs->u.complex->roperator;
2419         rset_bool_parms bool_parms;
2420
2421         bool_parms.rset_l = rpn_search_structure (zh, zs->u.complex->s1,
2422                                                   attributeSet, stream,
2423                                                   sort_sequence,
2424                                                   num_bases, basenames);
2425         if (bool_parms.rset_l == NULL)
2426             return NULL;
2427         bool_parms.rset_r = rpn_search_structure (zh, zs->u.complex->s2,
2428                                                   attributeSet, stream,
2429                                                   sort_sequence,
2430                                                   num_bases, basenames);
2431         if (bool_parms.rset_r == NULL)
2432         {
2433             rset_delete (bool_parms.rset_l);
2434             return NULL;
2435         }
2436         bool_parms.key_size = sizeof(struct it_key);
2437         bool_parms.cmp = key_compare_it;
2438
2439         switch (zop->which)
2440         {
2441         case Z_Operator_and:
2442             r = rset_create (rset_kind_and, &bool_parms);
2443             break;
2444         case Z_Operator_or:
2445             r = rset_create (rset_kind_or, &bool_parms);
2446             break;
2447         case Z_Operator_and_not:
2448             r = rset_create (rset_kind_not, &bool_parms);
2449             break;
2450         case Z_Operator_prox:
2451 #ifdef ASN_COMPILED
2452             if (zop->u.prox->which != Z_ProximityOperator_known)
2453             {
2454                 zh->errCode = 132;
2455                 return NULL;
2456             }
2457 #else
2458             if (zop->u.prox->which != Z_ProxCode_known)
2459             {
2460                 zh->errCode = 132;
2461                 return NULL;
2462             }
2463 #endif
2464
2465 #ifdef ASN_COMPILED
2466             if (*zop->u.prox->u.known != Z_ProxUnit_word)
2467             {
2468                 char *val = (char *) nmem_malloc (stream, 16);
2469                 zh->errCode = 132;
2470                 zh->errString = val;
2471                 sprintf (val, "%d", *zop->u.prox->u.known);
2472                 return NULL;
2473             }
2474 #else
2475             if (*zop->u.prox->proximityUnitCode != Z_ProxUnit_word)
2476             {
2477                 char *val = (char *) nmem_malloc (stream, 16);
2478                 zh->errCode = 132;
2479                 zh->errString = val;
2480                 sprintf (val, "%d", *zop->u.prox->proximityUnitCode);
2481                 return NULL;
2482             }
2483 #endif
2484             else
2485             {
2486                 RSET rsets[2];
2487
2488                 rsets[0] = bool_parms.rset_l;
2489                 rsets[1] = bool_parms.rset_r;
2490                 
2491                 r = rpn_prox (zh, rsets, 2, 
2492                               *zop->u.prox->ordered,
2493                               (!zop->u.prox->exclusion ? 0 :
2494                                *zop->u.prox->exclusion),
2495                               *zop->u.prox->relationType,
2496                               *zop->u.prox->distance);
2497                 rset_delete (rsets[0]);
2498                 rset_delete (rsets[1]);
2499             }
2500             break;
2501         default:
2502             zh->errCode = 110;
2503             return NULL;
2504         }
2505     }
2506     else if (zs->which == Z_RPNStructure_simple)
2507     {
2508         if (zs->u.simple->which == Z_Operand_APT)
2509         {
2510             logf (LOG_DEBUG, "rpn_search_APT");
2511             r = rpn_search_APT (zh, zs->u.simple->u.attributesPlusTerm,
2512                                 attributeSet, stream, sort_sequence,
2513                                 num_bases, basenames);
2514         }
2515         else if (zs->u.simple->which == Z_Operand_resultSetId)
2516         {
2517             logf (LOG_DEBUG, "rpn_search_ref");
2518             r = resultSetRef (zh, zs->u.simple->u.resultSetId);
2519             if (!r)
2520             {
2521                 r = rset_create (rset_kind_null, NULL);
2522                 zh->errCode = 30;
2523                 zh->errString =
2524                     nmem_strdup (stream, zs->u.simple->u.resultSetId);
2525                 return 0;
2526             }
2527         }
2528         else
2529         {
2530             zh->errCode = 3;
2531             return 0;
2532         }
2533     }
2534     else
2535     {
2536         zh->errCode = 3;
2537         return 0;
2538     }
2539     return r;
2540 }
2541
2542
2543 RSET rpn_search (ZebraHandle zh, NMEM nmem,
2544                  Z_RPNQuery *rpn, int num_bases, char **basenames, 
2545                  const char *setname,
2546                  ZebraSet sset)
2547 {
2548     RSET rset;
2549     oident *attrset;
2550     oid_value attributeSet;
2551     Z_SortKeySpecList *sort_sequence;
2552     int sort_status, i;
2553
2554     zh->errCode = 0;
2555     zh->errString = NULL;
2556     zh->hits = 0;
2557
2558     sort_sequence = (Z_SortKeySpecList *)
2559         nmem_malloc (nmem, sizeof(*sort_sequence));
2560     sort_sequence->num_specs = 10;
2561     sort_sequence->specs = (Z_SortKeySpec **)
2562         nmem_malloc (nmem, sort_sequence->num_specs *
2563                      sizeof(*sort_sequence->specs));
2564     for (i = 0; i<sort_sequence->num_specs; i++)
2565         sort_sequence->specs[i] = 0;
2566     
2567     attrset = oid_getentbyoid (rpn->attributeSetId);
2568     attributeSet = attrset->value;
2569     rset = rpn_search_structure (zh, rpn->RPNStructure, attributeSet,
2570                                  nmem, sort_sequence, num_bases, basenames);
2571     if (!rset)
2572         return 0;
2573
2574     if (zh->errCode)
2575         logf (LOG_DEBUG, "search error: %d", zh->errCode);
2576     
2577     for (i = 0; sort_sequence->specs[i]; i++)
2578         ;
2579     sort_sequence->num_specs = i;
2580     if (!i)
2581         resultSetRank (zh, sset, rset);
2582     else
2583     {
2584         logf (LOG_DEBUG, "resultSetSortSingle in rpn_search");
2585         resultSetSortSingle (zh, nmem, sset, rset,
2586                              sort_sequence, &sort_status);
2587         if (zh->errCode)
2588         {
2589             logf (LOG_DEBUG, "resultSetSortSingle status = %d", zh->errCode);
2590         }
2591     }
2592     return rset;
2593 }
2594
2595 struct scan_info_entry {
2596     char *term;
2597     ISAMS_P isam_p;
2598 };
2599
2600 struct scan_info {
2601     struct scan_info_entry *list;
2602     ODR odr;
2603     int before, after;
2604     char prefix[20];
2605 };
2606
2607 static int scan_handle (char *name, const char *info, int pos, void *client)
2608 {
2609     int len_prefix, idx;
2610     struct scan_info *scan_info = (struct scan_info *) client;
2611
2612     len_prefix = strlen(scan_info->prefix);
2613     if (memcmp (name, scan_info->prefix, len_prefix))
2614         return 1;
2615     if (pos > 0)        idx = scan_info->after - pos + scan_info->before;
2616     else
2617         idx = - pos - 1;
2618     scan_info->list[idx].term = (char *)
2619         odr_malloc (scan_info->odr, strlen(name + len_prefix)+1);
2620     strcpy (scan_info->list[idx].term, name + len_prefix);
2621     assert (*info == sizeof(ISAMS_P));
2622     memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAMS_P));
2623     return 0;
2624 }
2625
2626 static void scan_term_untrans (ZebraHandle zh, NMEM stream, int reg_type,
2627                                char **dst, const char *src)
2628 {
2629     char term_dst[1024];
2630     
2631     term_untrans (zh, reg_type, term_dst, src);
2632     
2633     *dst = (char *) nmem_malloc (stream, strlen(term_dst)+1);
2634     strcpy (*dst, term_dst);
2635 }
2636
2637 static void count_set (RSET r, int *count)
2638 {
2639     int psysno = 0;
2640     int kno = 0;
2641     struct it_key key;
2642     RSFD rfd;
2643     int term_index;
2644
2645     logf (LOG_DEBUG, "count_set");
2646
2647     *count = 0;
2648     rfd = rset_open (r, RSETF_READ);
2649     while (rset_read (r, rfd, &key, &term_index))
2650     {
2651         if (key.sysno != psysno)
2652         {
2653             psysno = key.sysno;
2654             (*count)++;
2655         }
2656         kno++;
2657     }
2658     rset_close (r, rfd);
2659     logf (LOG_DEBUG, "%d keys, %d records", kno, *count);
2660 }
2661
2662 void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
2663                oid_value attributeset,
2664                int num_bases, char **basenames,
2665                int *position, int *num_entries, ZebraScanEntry **list,
2666                int *is_partial)
2667 {
2668     int i;
2669     int pos = *position;
2670     int num = *num_entries;
2671     int before;
2672     int after;
2673     int base_no;
2674     char termz[IT_MAX_WORD+20];
2675     AttrType use;
2676     int use_value;
2677     struct scan_info *scan_info_array;
2678     ZebraScanEntry *glist;
2679     int ords[32], ord_no = 0;
2680     int ptr[32];
2681
2682     unsigned reg_id;
2683     char *search_type = NULL;
2684     char rank_type[128];
2685     int complete_flag;
2686     int sort_flag;
2687     *list = 0;
2688
2689     if (attributeset == VAL_NONE)
2690         attributeset = VAL_BIB1;
2691
2692     yaz_log (LOG_DEBUG, "position = %d, num = %d set=%d",
2693              pos, num, attributeset);
2694         
2695     attr_init (&use, zapt, 1);
2696     use_value = attr_find (&use, &attributeset);
2697
2698     if (zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2699                          rank_type, &complete_flag, &sort_flag))
2700     {
2701         *num_entries = 0;
2702         zh->errCode = 113;
2703         return ;
2704     }
2705     yaz_log (LOG_DEBUG, "use_value = %d", use_value);
2706
2707     if (use_value == -1)
2708         use_value = 1016;
2709     for (base_no = 0; base_no < num_bases && ord_no < 32; base_no++)
2710     {
2711         int r;
2712         attent attp;
2713         data1_local_attribute *local_attr;
2714
2715         if ((r=att_getentbyatt (zh, &attp, attributeset, use_value)))
2716         {
2717             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d",
2718                   attributeset, use_value);
2719             if (r == -1)
2720                 zh->errCode = 114;
2721             else
2722                 zh->errCode = 121;
2723             *num_entries = 0;
2724             return;
2725         }
2726         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2727         {
2728             zh->errString = basenames[base_no];
2729             zh->errCode = 109; /* Database unavailable */
2730             *num_entries = 0;
2731             return;
2732         }
2733         for (local_attr = attp.local_attributes; local_attr && ord_no < 32;
2734              local_attr = local_attr->next)
2735         {
2736             int ord;
2737
2738             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
2739                                          local_attr->local);
2740             if (ord > 0)
2741                 ords[ord_no++] = ord;
2742         }
2743     }
2744     if (ord_no == 0)
2745     {
2746         *num_entries = 0;
2747         zh->errCode = 113;
2748         return;
2749     }
2750     /* prepare dictionary scanning */
2751     before = pos-1;
2752     after = 1+num-pos;
2753     scan_info_array = (struct scan_info *)
2754         odr_malloc (stream, ord_no * sizeof(*scan_info_array));
2755     for (i = 0; i < ord_no; i++)
2756     {
2757         int j, prefix_len = 0;
2758         int before_tmp = before, after_tmp = after;
2759         struct scan_info *scan_info = scan_info_array + i;
2760         struct rpn_char_map_info rcmi;
2761
2762         rpn_char_map_prepare (zh->reg, reg_id, &rcmi);
2763
2764         scan_info->before = before;
2765         scan_info->after = after;
2766         scan_info->odr = stream;
2767
2768         scan_info->list = (struct scan_info_entry *)
2769             odr_malloc (stream, (before+after) * sizeof(*scan_info->list));
2770         for (j = 0; j<before+after; j++)
2771             scan_info->list[j].term = NULL;
2772
2773         prefix_len += key_SU_encode (ords[i], termz + prefix_len);
2774         termz[prefix_len++] = reg_id;
2775         termz[prefix_len] = 0;
2776         strcpy (scan_info->prefix, termz);
2777
2778         trans_scan_term (zh, zapt, termz+prefix_len, reg_id);
2779                     
2780         dict_scan (zh->reg->dict, termz, &before_tmp, &after_tmp,
2781                    scan_info, scan_handle);
2782     }
2783     glist = (ZebraScanEntry *)
2784         odr_malloc (stream, (before+after)*sizeof(*glist));
2785
2786     /* consider terms after main term */
2787     for (i = 0; i < ord_no; i++)
2788         ptr[i] = before;
2789     
2790     *is_partial = 0;
2791     for (i = 0; i<after; i++)
2792     {
2793         int j, j0 = -1;
2794         const char *mterm = NULL;
2795         const char *tst;
2796         RSET rset;
2797         
2798         for (j = 0; j < ord_no; j++)
2799         {
2800             if (ptr[j] < before+after &&
2801                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2802                 (!mterm || strcmp (tst, mterm) < 0))
2803             {
2804                 j0 = j;
2805                 mterm = tst;
2806             }
2807         }
2808         if (j0 == -1)
2809             break;
2810         scan_term_untrans (zh, stream->mem, reg_id,
2811                            &glist[i+before].term, mterm);
2812         rset = rset_trunc (zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
2813                            glist[i+before].term, strlen(glist[i+before].term),
2814                            NULL, 0, zapt->term->which);
2815
2816         ptr[j0]++;
2817         for (j = j0+1; j<ord_no; j++)
2818         {
2819             if (ptr[j] < before+after &&
2820                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2821                 !strcmp (tst, mterm))
2822             {
2823                 rset_bool_parms bool_parms;
2824                 RSET rset2;
2825
2826                 rset2 =
2827                    rset_trunc (zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
2828                                glist[i+before].term,
2829                                strlen(glist[i+before].term), NULL, 0,
2830                                zapt->term->which);
2831
2832                 bool_parms.key_size = sizeof(struct it_key);
2833                 bool_parms.cmp = key_compare_it;
2834                 bool_parms.rset_l = rset;
2835                 bool_parms.rset_r = rset2;
2836               
2837                 rset = rset_create (rset_kind_or, &bool_parms);
2838
2839                 ptr[j]++;
2840             }
2841         }
2842         count_set (rset, &glist[i+before].occurrences);
2843         rset_delete (rset);
2844     }
2845     if (i < after)
2846     {
2847         *num_entries -= (after-i);
2848         *is_partial = 1;
2849     }
2850
2851     /* consider terms before main term */
2852     for (i = 0; i<ord_no; i++)
2853         ptr[i] = 0;
2854
2855     for (i = 0; i<before; i++)
2856     {
2857         int j, j0 = -1;
2858         const char *mterm = NULL;
2859         const char *tst;
2860         RSET rset;
2861         
2862         for (j = 0; j <ord_no; j++)
2863         {
2864             if (ptr[j] < before &&
2865                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2866                 (!mterm || strcmp (tst, mterm) > 0))
2867             {
2868                 j0 = j;
2869                 mterm = tst;
2870             }
2871         }
2872         if (j0 == -1)
2873             break;
2874
2875         scan_term_untrans (zh, stream->mem, reg_id,
2876                            &glist[before-1-i].term, mterm);
2877
2878         rset = rset_trunc
2879                (zh, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1,
2880                 glist[before-1-i].term, strlen(glist[before-1-i].term),
2881                 NULL, 0, zapt->term->which);
2882
2883         ptr[j0]++;
2884
2885         for (j = j0+1; j<ord_no; j++)
2886         {
2887             if (ptr[j] < before &&
2888                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2889                 !strcmp (tst, mterm))
2890             {
2891                 rset_bool_parms bool_parms;
2892                 RSET rset2;
2893
2894                 rset2 = rset_trunc (zh,
2895                          &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1,
2896                                     glist[before-1-i].term,
2897                                     strlen(glist[before-1-i].term), NULL, 0,
2898                                     zapt->term->which);
2899
2900                 bool_parms.key_size = sizeof(struct it_key);
2901                 bool_parms.cmp = key_compare_it;
2902                 bool_parms.rset_l = rset;
2903                 bool_parms.rset_r = rset2;
2904               
2905                 rset = rset_create (rset_kind_or, &bool_parms);
2906
2907                 ptr[j]++;
2908             }
2909         }
2910         count_set (rset, &glist[before-1-i].occurrences);
2911         rset_delete (rset);
2912     }
2913     i = before-i;
2914     if (i)
2915     {
2916         *is_partial = 1;
2917         *position -= i;
2918         *num_entries -= i;
2919     }
2920     *list = glist + i;               /* list is set to first 'real' entry */
2921     
2922     logf (LOG_DEBUG, "position = %d, num_entries = %d",
2923           *position, *num_entries);
2924     if (zh->errCode)
2925         logf (LOG_DEBUG, "scan error: %d", zh->errCode);
2926 }
2927