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