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