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