adde9d40ea55bef7377d5e740bd0489f3b68ada2
[idzebra-moved-to-github.git] / index / zrpn.c
1 /* $Id: zrpn.c,v 1.141 2004-08-03 12:15:44 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     ISAMS_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         ISAMS_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 = (ISAMS_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         
1395         parms.rset_term = rset_term_create (termz, -1, rank_type,
1396                                             zapt->term->which);
1397         return rset_create (rset_kind_null, &parms);
1398     }
1399     else if (rset_no == 1)
1400         return (rset[0]);
1401     else
1402     {
1403         /* new / old prox */
1404         rset_prox_parms parms;
1405         
1406         parms.rset = rset;
1407         parms.rset_no = rset_no;
1408         parms.ordered = 1;
1409         parms.exclusion = 0;
1410         parms.relation = 3;
1411         parms.distance = 1;
1412         parms.key_size = sizeof(struct it_key);
1413         parms.cmp = key_compare_it;
1414         parms.getseq = key_get_seq;
1415         parms.log_item = key_logdump_txt;
1416         result = rset_create(rset_kind_prox, &parms);
1417     }
1418     return result;
1419 }
1420
1421 static RSET rpn_search_APT_or_list (ZebraHandle zh,
1422                                     Z_AttributesPlusTerm *zapt,
1423                                     const char *termz_org,
1424                                     oid_value attributeSet,
1425                                     NMEM stream,
1426                                     int reg_type, int complete_flag,
1427                                     const char *rank_type,
1428                                     int xpath_use,
1429                                     int num_bases, char **basenames)
1430 {
1431     char term_dst[IT_MAX_WORD+1];
1432     RSET rset[60], result;
1433     int i, rset_no = 0;
1434     struct grep_info grep_info;
1435     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1436     const char *termp = termz;
1437
1438     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1439         return 0;
1440     while (1)
1441     { 
1442         logf (LOG_DEBUG, "APT_or_list termp=%s", termp);
1443         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1444                                     stream, &grep_info,
1445                                     reg_type, complete_flag,
1446                                     num_bases, basenames,
1447                                     term_dst, rank_type,
1448                                     xpath_use);
1449         if (!rset[rset_no])
1450             break;
1451         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1452             break;
1453     }
1454     grep_info_delete (&grep_info);
1455     if (rset_no == 0)
1456     {
1457         rset_null_parms parms;
1458         
1459         parms.rset_term = rset_term_create (termz, -1, rank_type,
1460                                             zapt->term->which);
1461         return rset_create (rset_kind_null, &parms);
1462     }
1463     result = rset[0];
1464     for (i = 1; i<rset_no; i++)
1465     {
1466         rset_bool_parms bool_parms;
1467
1468         bool_parms.rset_l = result;
1469         bool_parms.rset_r = rset[i];
1470         bool_parms.key_size = sizeof(struct it_key);
1471         bool_parms.cmp = key_compare_it;
1472         bool_parms.log_item = key_logdump_txt;
1473         result = rset_create (rset_kind_or, &bool_parms);
1474     }
1475     return result;
1476 }
1477
1478 static RSET rpn_search_APT_and_list (ZebraHandle zh,
1479                                      Z_AttributesPlusTerm *zapt,
1480                                      const char *termz_org,
1481                                      oid_value attributeSet,
1482                                      NMEM stream,
1483                                      int reg_type, int complete_flag,
1484                                      const char *rank_type, 
1485                                      int xpath_use,
1486                                      int num_bases, char **basenames)
1487 {
1488     char term_dst[IT_MAX_WORD+1];
1489     RSET rset[60], result;
1490     int i, rset_no = 0;
1491     struct grep_info grep_info;
1492     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1493     const char *termp = termz;
1494
1495     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1496         return 0;
1497     while (1)
1498     { 
1499         logf (LOG_DEBUG, "APT_and_list termp=%s", termp);
1500         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1501                                     stream, &grep_info,
1502                                     reg_type, complete_flag,
1503                                     num_bases, basenames,
1504                                     term_dst, rank_type,
1505                                     xpath_use);
1506         if (!rset[rset_no])
1507             break;
1508         assert (rset[rset_no]);
1509         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1510             break;
1511     }
1512     grep_info_delete (&grep_info);
1513     if (rset_no == 0)
1514     {
1515         rset_null_parms parms;
1516         
1517         parms.rset_term = rset_term_create (termz, -1, rank_type,
1518                                             zapt->term->which);
1519         return rset_create (rset_kind_null, &parms);
1520     }
1521     result = rset[0];
1522     for (i = 1; i<rset_no; i++)
1523     {
1524         rset_bool_parms bool_parms;
1525
1526         bool_parms.rset_l = result;
1527         bool_parms.rset_r = rset[i];
1528         bool_parms.key_size = sizeof(struct it_key);
1529         bool_parms.cmp = key_compare_it;
1530         bool_parms.log_item = key_logdump_txt;
1531         result = rset_create (rset_kind_and, &bool_parms);
1532     }
1533     return result;
1534 }
1535
1536 static int numeric_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1537                              const char **term_sub,
1538                              char *term_dict,
1539                              oid_value attributeSet,
1540                              struct grep_info *grep_info,
1541                              int *max_pos,
1542                              int reg_type,
1543                              char *term_dst)
1544 {
1545     AttrType relation;
1546     int relation_value;
1547     int term_value;
1548     int r;
1549     char *term_tmp = term_dict + strlen(term_dict);
1550
1551     attr_init (&relation, zapt, 2);
1552     relation_value = attr_find (&relation, NULL);
1553
1554     logf (LOG_DEBUG, "numeric relation value=%d", relation_value);
1555
1556     if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub, term_tmp, 1,
1557                    term_dst))
1558         return 0;
1559     term_value = atoi (term_tmp);
1560     switch (relation_value)
1561     {
1562     case 1:
1563         logf (LOG_DEBUG, "Relation <");
1564         gen_regular_rel (term_tmp, term_value-1, 1);
1565         break;
1566     case 2:
1567         logf (LOG_DEBUG, "Relation <=");
1568         gen_regular_rel (term_tmp, term_value, 1);
1569         break;
1570     case 4:
1571         logf (LOG_DEBUG, "Relation >=");
1572         gen_regular_rel (term_tmp, term_value, 0);
1573         break;
1574     case 5:
1575         logf (LOG_DEBUG, "Relation >");
1576         gen_regular_rel (term_tmp, term_value+1, 0);
1577         break;
1578     case 3:
1579     default:
1580         logf (LOG_DEBUG, "Relation =");
1581         sprintf (term_tmp, "(0*%d)", term_value);
1582     }
1583     logf (LOG_DEBUG, "dict_lookup_grep: %s", term_tmp);
1584     r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info, max_pos,
1585                           0, grep_handle);
1586     if (r)
1587         logf (LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
1588     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1589     return 1;
1590 }
1591
1592 static int numeric_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1593                          const char **term_sub, 
1594                          oid_value attributeSet, struct grep_info *grep_info,
1595                          int reg_type, int complete_flag,
1596                          int num_bases, char **basenames,
1597                          char *term_dst, int xpath_use, NMEM stream)
1598 {
1599     char term_dict[2*IT_MAX_WORD+2];
1600     int r, base_no;
1601     AttrType use;
1602     int use_value;
1603     const char *use_string = 0;
1604     oid_value curAttributeSet = attributeSet;
1605     const char *termp;
1606     struct rpn_char_map_info rcmi;
1607
1608     int bases_ok = 0;     /* no of databases with OK attribute */
1609     int errCode = 0;      /* err code (if any is not OK) */
1610     char *errString = 0;  /* addinfo */
1611
1612     rpn_char_map_prepare (zh->reg, reg_type, &rcmi);
1613     attr_init (&use, zapt, 1);
1614     use_value = attr_find_ex (&use, &curAttributeSet, &use_string);
1615
1616     if (use_value == -1)
1617         use_value = 1016;
1618
1619     for (base_no = 0; base_no < num_bases; base_no++)
1620     {
1621         attent attp;
1622         data1_local_attribute id_xpath_attr;
1623         data1_local_attribute *local_attr;
1624         int max_pos, prefix_len = 0;
1625
1626         termp = *term_sub;
1627         if (use_value == -2)  /* string attribute (assume IDXPATH/any) */
1628         {
1629             use_value = xpath_use;
1630             attp.local_attributes = &id_xpath_attr;
1631             attp.attset_ordinal = VAL_IDXPATH;
1632             id_xpath_attr.next = 0;
1633             id_xpath_attr.local = use_value;
1634         }
1635         else if (curAttributeSet == VAL_IDXPATH)
1636         {
1637             attp.local_attributes = &id_xpath_attr;
1638             attp.attset_ordinal = VAL_IDXPATH;
1639             id_xpath_attr.next = 0;
1640             id_xpath_attr.local = use_value;
1641         }
1642         else
1643         {
1644             if ((r=att_getentbyatt (zh, &attp, curAttributeSet, use_value,
1645                                             use_string)))
1646             {
1647                 logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
1648                       curAttributeSet, use_value, r);
1649                 if (r == -1)
1650                 {
1651                     char val_str[32];
1652                     sprintf (val_str, "%d", use_value);
1653                     errString = nmem_strdup (stream, val_str);
1654                     errCode = 114;
1655                 }
1656                 else
1657                     errCode = 121;
1658                 continue;
1659             }
1660         }
1661         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
1662         {
1663             zh->errCode = 109; /* Database unavailable */
1664             zh->errString = basenames[base_no];
1665             return -1;
1666         }
1667         for (local_attr = attp.local_attributes; local_attr;
1668              local_attr = local_attr->next)
1669         {
1670             int ord;
1671             char ord_buf[32];
1672             int i, ord_len;
1673
1674             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
1675                                           local_attr->local);
1676             if (ord < 0)
1677                 continue;
1678             if (prefix_len)
1679                 term_dict[prefix_len++] = '|';
1680             else
1681                 term_dict[prefix_len++] = '(';
1682
1683             ord_len = key_SU_encode (ord, ord_buf);
1684             for (i = 0; i<ord_len; i++)
1685             {
1686                 term_dict[prefix_len++] = 1;
1687                 term_dict[prefix_len++] = ord_buf[i];
1688             }
1689         }
1690         if (!prefix_len)
1691         {
1692             char val_str[32];
1693             sprintf (val_str, "%d", use_value);
1694             errCode = 114;
1695             errString = nmem_strdup (stream, val_str);
1696             continue;
1697         }
1698         bases_ok++;
1699         term_dict[prefix_len++] = ')';        
1700         term_dict[prefix_len++] = 1;
1701         term_dict[prefix_len++] = reg_type;
1702         logf (LOG_DEBUG, "reg_type = %d", term_dict[prefix_len-1]);
1703         term_dict[prefix_len] = '\0';
1704         if (!numeric_relation (zh, zapt, &termp, term_dict,
1705                                attributeSet, grep_info, &max_pos, reg_type,
1706                                term_dst))
1707             return 0;
1708     }
1709     if (!bases_ok)
1710     {
1711         zh->errCode = errCode;
1712         zh->errString = errString;
1713         return -1;
1714     }
1715     *term_sub = termp;
1716     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1717     return 1;
1718 }
1719
1720 static RSET rpn_search_APT_numeric (ZebraHandle zh,
1721                                     Z_AttributesPlusTerm *zapt,
1722                                     const char *termz,
1723                                     oid_value attributeSet,
1724                                     NMEM stream,
1725                                     int reg_type, int complete_flag,
1726                                     const char *rank_type, int xpath_use,
1727                                     int num_bases, char **basenames)
1728 {
1729     char term_dst[IT_MAX_WORD+1];
1730     const char *termp = termz;
1731     RSET rset[60], result;
1732     int i, r, rset_no = 0;
1733     struct grep_info grep_info;
1734
1735     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1736         return 0;
1737     while (1)
1738     { 
1739         logf (LOG_DEBUG, "APT_numeric termp=%s", termp);
1740         grep_info.isam_p_indx = 0;
1741         r = numeric_term (zh, zapt, &termp, attributeSet, &grep_info,
1742                           reg_type, complete_flag, num_bases, basenames,
1743                           term_dst, xpath_use,
1744                           stream);
1745         if (r < 1)
1746             break;
1747         logf (LOG_DEBUG, "term: %s", term_dst);
1748         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
1749                                     grep_info.isam_p_indx, term_dst,
1750                                     strlen(term_dst), rank_type,
1751                                     0 /* preserve position */,
1752                                     zapt->term->which);
1753         assert (rset[rset_no]);
1754         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1755             break;
1756     }
1757     grep_info_delete (&grep_info);
1758     if (rset_no == 0)
1759     {
1760         rset_null_parms parms;
1761         
1762         parms.rset_term = rset_term_create (term_dst, -1, rank_type,
1763                                             zapt->term->which);
1764         return rset_create (rset_kind_null, &parms);
1765     }
1766     result = rset[0];
1767     for (i = 1; i<rset_no; i++)
1768     {
1769         rset_bool_parms bool_parms;
1770
1771         bool_parms.rset_l = result;
1772         bool_parms.rset_r = rset[i];
1773         bool_parms.key_size = sizeof(struct it_key);
1774         bool_parms.cmp = key_compare_it;
1775         bool_parms.log_item = key_logdump_txt;
1776         result = rset_create (rset_kind_and, &bool_parms);
1777     }
1778     return result;
1779 }
1780
1781 static RSET rpn_search_APT_local (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1782                                   const char *termz,
1783                                   oid_value attributeSet,
1784                                   NMEM stream,
1785                                   const char *rank_type)
1786 {
1787     RSET result;
1788     RSFD rsfd;
1789     struct it_key key;
1790     rset_temp_parms parms;
1791
1792     parms.rset_term = rset_term_create (termz, -1, rank_type,
1793                                         zapt->term->which);
1794     parms.cmp = key_compare_it;
1795     parms.key_size = sizeof (struct it_key);
1796     parms.temp_path = res_get (zh->res, "setTmpDir");
1797     result = rset_create (rset_kind_temp, &parms);
1798     rsfd = rset_open (result, RSETF_WRITE);
1799
1800     key.sysno = atoi (termz);
1801     key.seqno = 1;
1802     if (key.sysno <= 0)
1803         key.sysno = 1;
1804     rset_write (result, rsfd, &key);
1805     rset_close (result, rsfd);
1806     return result;
1807 }
1808
1809 static RSET rpn_sort_spec (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1810                            oid_value attributeSet, NMEM stream,
1811                            Z_SortKeySpecList *sort_sequence,
1812                            const char *rank_type)
1813 {
1814     rset_null_parms parms;    
1815     int i;
1816     int sort_relation_value;
1817     AttrType sort_relation_type;
1818     int use_value;
1819     AttrType use_type;
1820     Z_SortKeySpec *sks;
1821     Z_SortKey *sk;
1822     Z_AttributeElement *ae;
1823     int oid[OID_SIZE];
1824     oident oe;
1825     char termz[20];
1826     
1827     attr_init (&sort_relation_type, zapt, 7);
1828     sort_relation_value = attr_find (&sort_relation_type, &attributeSet);
1829
1830     attr_init (&use_type, zapt, 1);
1831     use_value = attr_find (&use_type, &attributeSet);
1832
1833     if (!sort_sequence->specs)
1834     {
1835         sort_sequence->num_specs = 10;
1836         sort_sequence->specs = (Z_SortKeySpec **)
1837             nmem_malloc (stream, sort_sequence->num_specs *
1838                          sizeof(*sort_sequence->specs));
1839         for (i = 0; i<sort_sequence->num_specs; i++)
1840             sort_sequence->specs[i] = 0;
1841     }
1842     if (zapt->term->which != Z_Term_general)
1843         i = 0;
1844     else
1845         i = atoi_n ((char *) zapt->term->u.general->buf,
1846                     zapt->term->u.general->len);
1847     if (i >= sort_sequence->num_specs)
1848         i = 0;
1849     sprintf (termz, "%d", i);
1850
1851     oe.proto = PROTO_Z3950;
1852     oe.oclass = CLASS_ATTSET;
1853     oe.value = attributeSet;
1854     if (!oid_ent_to_oid (&oe, oid))
1855         return 0;
1856
1857     sks = (Z_SortKeySpec *) nmem_malloc (stream, sizeof(*sks));
1858     sks->sortElement = (Z_SortElement *)
1859         nmem_malloc (stream, sizeof(*sks->sortElement));
1860     sks->sortElement->which = Z_SortElement_generic;
1861     sk = sks->sortElement->u.generic = (Z_SortKey *)
1862         nmem_malloc (stream, sizeof(*sk));
1863     sk->which = Z_SortKey_sortAttributes;
1864     sk->u.sortAttributes = (Z_SortAttributes *)
1865         nmem_malloc (stream, sizeof(*sk->u.sortAttributes));
1866
1867     sk->u.sortAttributes->id = oid;
1868     sk->u.sortAttributes->list = (Z_AttributeList *)
1869         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list));
1870     sk->u.sortAttributes->list->num_attributes = 1;
1871     sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
1872         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list->attributes));
1873     ae = *sk->u.sortAttributes->list->attributes = (Z_AttributeElement *)
1874         nmem_malloc (stream, sizeof(**sk->u.sortAttributes->list->attributes));
1875     ae->attributeSet = 0;
1876     ae->attributeType = (int *)
1877         nmem_malloc (stream, sizeof(*ae->attributeType));
1878     *ae->attributeType = 1;
1879     ae->which = Z_AttributeValue_numeric;
1880     ae->value.numeric = (int *)
1881         nmem_malloc (stream, sizeof(*ae->value.numeric));
1882     *ae->value.numeric = use_value;
1883
1884     sks->sortRelation = (int *)
1885         nmem_malloc (stream, sizeof(*sks->sortRelation));
1886     if (sort_relation_value == 1)
1887         *sks->sortRelation = Z_SortKeySpec_ascending;
1888     else if (sort_relation_value == 2)
1889         *sks->sortRelation = Z_SortKeySpec_descending;
1890     else 
1891         *sks->sortRelation = Z_SortKeySpec_ascending;
1892
1893     sks->caseSensitivity = (int *)
1894         nmem_malloc (stream, sizeof(*sks->caseSensitivity));
1895     *sks->caseSensitivity = 0;
1896
1897     sks->which = Z_SortKeySpec_null;
1898     sks->u.null = odr_nullval ();
1899     sort_sequence->specs[i] = sks;
1900
1901     parms.rset_term = rset_term_create (termz, -1, rank_type,
1902                                         zapt->term->which);
1903     return rset_create (rset_kind_null, &parms);
1904 }
1905
1906
1907 static int parse_xpath(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1908                        oid_value attributeSet,
1909                        struct xpath_location_step *xpath, int max, NMEM mem)
1910 {
1911     oid_value curAttributeSet = attributeSet;
1912     AttrType use;
1913     const char *use_string = 0;
1914     
1915     attr_init (&use, zapt, 1);
1916     attr_find_ex (&use, &curAttributeSet, &use_string);
1917
1918     if (!use_string || *use_string != '/')
1919         return -1;
1920
1921     return zebra_parse_xpath_str(use_string, xpath, max, mem);
1922 }
1923  
1924                
1925
1926 static RSET xpath_trunc(ZebraHandle zh, NMEM stream,
1927                         int reg_type, const char *term, int use,
1928                         oid_value curAttributeSet)
1929 {
1930     RSET rset;
1931     struct grep_info grep_info;
1932     char term_dict[2048];
1933     char ord_buf[32];
1934     int prefix_len = 0;
1935     int ord = zebraExplain_lookupSU (zh->reg->zei, curAttributeSet, use);
1936     int ord_len, i, r, max_pos;
1937     int term_type = Z_Term_characterString;
1938     const char *flags = "void";
1939
1940     if (grep_info_prepare (zh, 0 /* zapt */, &grep_info, '0', stream))
1941     {
1942         rset_null_parms parms;
1943         
1944         parms.rset_term = rset_term_create (term, strlen(term),
1945                                             flags, term_type);
1946         parms.rset_term->nn = 0;
1947         return rset_create (rset_kind_null, &parms);
1948     }
1949
1950     if (ord < 0)
1951     {
1952         rset_null_parms parms;
1953         
1954         parms.rset_term = rset_term_create (term, strlen(term),
1955                                             flags, term_type);
1956         parms.rset_term->nn = 0;
1957         return rset_create (rset_kind_null, &parms);
1958     }
1959     if (prefix_len)
1960         term_dict[prefix_len++] = '|';
1961     else
1962         term_dict[prefix_len++] = '(';
1963     
1964     ord_len = key_SU_encode (ord, ord_buf);
1965     for (i = 0; i<ord_len; i++)
1966     {
1967         term_dict[prefix_len++] = 1;
1968         term_dict[prefix_len++] = ord_buf[i];
1969     }
1970     term_dict[prefix_len++] = ')';
1971     term_dict[prefix_len++] = 1;
1972     term_dict[prefix_len++] = reg_type;
1973     
1974     strcpy (term_dict+prefix_len, term);
1975     
1976     grep_info.isam_p_indx = 0;
1977     r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
1978                           &grep_info, &max_pos, 0, grep_handle);
1979     yaz_log (LOG_LOG, "%s %d positions", term,
1980              grep_info.isam_p_indx);
1981     rset = rset_trunc (zh, grep_info.isam_p_buf,
1982                        grep_info.isam_p_indx, term, strlen(term),
1983                        flags, 1, term_type);
1984     grep_info_delete (&grep_info);
1985     return rset;
1986 }
1987
1988 static RSET rpn_search_xpath (ZebraHandle zh,
1989                               oid_value attributeSet,
1990                               int num_bases, char **basenames,
1991                               NMEM stream, const char *rank_type, RSET rset,
1992                               int xpath_len, struct xpath_location_step *xpath)
1993 {
1994     oid_value curAttributeSet = attributeSet;
1995     int base_no;
1996     int i;
1997
1998     if (xpath_len < 0)
1999         return rset;
2000
2001     yaz_log (LOG_LOG, "len=%d", xpath_len);
2002     for (i = 0; i<xpath_len; i++)
2003     {
2004         yaz_log (LOG_LOG, "XPATH %d %s", i, xpath[i].part);
2005
2006     }
2007
2008     curAttributeSet = VAL_IDXPATH;
2009
2010     /*
2011       //a    ->    a/.*
2012       //a/b  ->    b/a/.*
2013       /a     ->    a/
2014       /a/b   ->    b/a/
2015
2016       /      ->    none
2017
2018    a[@attr=value]/b[@other=othervalue]
2019
2020  /e/@a val      range(e/,range(@a,freetext(w,1015,val),@a),e/)
2021  /a/b val       range(b/a/,freetext(w,1016,val),b/a/)
2022  /a/b/@c val    range(b/a/,range(@c,freetext(w,1016,val),@c),b/a/)
2023  /a/b[@c=y] val range(b/a/,freetext(w,1016,val),b/a/,@c=y)
2024  /a[@c=y]/b val range(a/,range(b/a/,freetext(w,1016,val),b/a/),a/,@c=y)
2025  /a[@c=x]/b[@c=y] range(a/,range(b/a/,freetext(w,1016,val),b/a/,@c=y),a/,@c=x)
2026       
2027     */
2028
2029     dict_grep_cmap (zh->reg->dict, 0, 0);
2030
2031     for (base_no = 0; base_no < num_bases; base_no++)
2032     {
2033         int level = xpath_len;
2034         int first_path = 1;
2035         
2036         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2037         {
2038             zh->errCode = 109; /* Database unavailable */
2039             zh->errString = basenames[base_no];
2040             return rset;
2041         }
2042         while (--level >= 0)
2043         {
2044             char xpath_rev[128];
2045             int i, len;
2046             rset_between_parms parms;
2047             RSET rset_start_tag = 0, rset_end_tag = 0, rset_attr = 0;
2048
2049             *xpath_rev = 0;
2050             len = 0;
2051             for (i = level; i >= 1; --i)
2052             {
2053                 const char *cp = xpath[i].part;
2054                 if (*cp)
2055                 {
2056                     for (;*cp; cp++)
2057                         if (*cp == '*')
2058                         {
2059                             memcpy (xpath_rev + len, "[^/]*", 5);
2060                             len += 5;
2061                         }
2062                         else if (*cp == ' ')
2063                         {
2064
2065                             xpath_rev[len++] = 1;
2066                             xpath_rev[len++] = ' ';
2067                         }
2068
2069                         else
2070                             xpath_rev[len++] = *cp;
2071                     xpath_rev[len++] = '/';
2072                 }
2073                 else if (i == 1)  /* // case */
2074                 {
2075                     xpath_rev[len++] = '.';
2076                     xpath_rev[len++] = '*';
2077                 }
2078             }
2079             xpath_rev[len] = 0;
2080
2081             if (xpath[level].predicate &&
2082                 xpath[level].predicate->which == XPATH_PREDICATE_RELATION &&
2083                 xpath[level].predicate->u.relation.name[0])
2084             {
2085                 WRBUF wbuf = wrbuf_alloc();
2086                 wrbuf_puts(wbuf, xpath[level].predicate->u.relation.name+1);
2087                 if (xpath[level].predicate->u.relation.value)
2088                 {
2089                     const char *cp = xpath[level].predicate->u.relation.value;
2090                     wrbuf_putc(wbuf, '=');
2091                     
2092                     while (*cp)
2093                     {
2094                         if (strchr(REGEX_CHARS, *cp))
2095                             wrbuf_putc(wbuf, '\\');
2096                         wrbuf_putc(wbuf, *cp);
2097                         cp++;
2098                     }
2099                 }
2100                 wrbuf_puts(wbuf, "");
2101                 rset_attr = xpath_trunc (
2102                     zh, stream, '0', wrbuf_buf(wbuf), 3, curAttributeSet);
2103                 wrbuf_free(wbuf, 1);
2104             } 
2105             else 
2106             {
2107                 if (!first_path)
2108                     continue;
2109             }
2110             yaz_log (LOG_LOG, "xpath_rev (%d) = %s", level, xpath_rev);
2111             if (strlen(xpath_rev))
2112             {
2113                 rset_start_tag = xpath_trunc(zh, stream, 
2114                                          '0', xpath_rev, 1, curAttributeSet);
2115             
2116                 rset_end_tag = xpath_trunc(zh, stream,
2117                                        '0', xpath_rev, 2, curAttributeSet);
2118
2119                 parms.key_size = sizeof(struct it_key);
2120                 parms.cmp = key_compare_it;
2121                 parms.rset_l = rset_start_tag;
2122                 parms.rset_m = rset;
2123                 parms.rset_r = rset_end_tag;
2124                 parms.rset_attr = rset_attr;
2125                 parms.printer = key_print_it;
2126                 rset = rset_create (rset_kind_between, &parms);
2127             }
2128             first_path = 0;
2129         }
2130     }
2131
2132     return rset;
2133 }
2134
2135
2136
2137 static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
2138                             oid_value attributeSet, NMEM stream,
2139                             Z_SortKeySpecList *sort_sequence,
2140                             int num_bases, char **basenames)
2141 {
2142     unsigned reg_id;
2143     char *search_type = NULL;
2144     char rank_type[128];
2145     int complete_flag;
2146     int sort_flag;
2147     char termz[IT_MAX_WORD+1];
2148     RSET rset = 0;
2149     int xpath_len;
2150     int xpath_use = 0;
2151     struct xpath_location_step xpath[10];
2152
2153     zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2154                      rank_type, &complete_flag, &sort_flag);
2155     
2156     logf (LOG_DEBUG, "reg_id=%c", reg_id);
2157     logf (LOG_DEBUG, "complete_flag=%d", complete_flag);
2158     logf (LOG_DEBUG, "search_type=%s", search_type);
2159     logf (LOG_DEBUG, "rank_type=%s", rank_type);
2160
2161     if (zapt_term_to_utf8(zh, zapt, termz))
2162         return 0;
2163
2164     if (sort_flag)
2165         return rpn_sort_spec (zh, zapt, attributeSet, stream, sort_sequence,
2166                               rank_type);
2167     xpath_len = parse_xpath(zh, zapt, attributeSet, xpath, 10, stream);
2168     if (xpath_len >= 0)
2169     {
2170         xpath_use = 1016;
2171         if (xpath[xpath_len-1].part[0] == '@')
2172             xpath_use = 1015;
2173     }
2174
2175     if (!strcmp (search_type, "phrase"))
2176     {
2177         rset = rpn_search_APT_phrase (zh, zapt, termz, attributeSet, stream,
2178                                       reg_id, complete_flag, rank_type,
2179                                       xpath_use,
2180                                       num_bases, basenames);
2181     }
2182     else if (!strcmp (search_type, "and-list"))
2183     {
2184         rset = rpn_search_APT_and_list (zh, zapt, termz, attributeSet, stream,
2185                                         reg_id, complete_flag, rank_type,
2186                                         xpath_use,
2187                                         num_bases, basenames);
2188     }
2189     else if (!strcmp (search_type, "or-list"))
2190     {
2191         rset = rpn_search_APT_or_list (zh, zapt, termz, attributeSet, stream,
2192                                        reg_id, complete_flag, rank_type,
2193                                        xpath_use,
2194                                        num_bases, basenames);
2195     }
2196     else if (!strcmp (search_type, "local"))
2197     {
2198         rset = rpn_search_APT_local (zh, zapt, termz, attributeSet, stream,
2199                                      rank_type);
2200     }
2201     else if (!strcmp (search_type, "numeric"))
2202     {
2203         rset = rpn_search_APT_numeric (zh, zapt, termz, attributeSet, stream,
2204                                        reg_id, complete_flag, rank_type,
2205                                        xpath_use,
2206                                        num_bases, basenames);
2207     }
2208     else if (!strcmp (search_type, "always"))
2209     {
2210         rset = 0;
2211     }
2212     else
2213         zh->errCode = 118;
2214     return rpn_search_xpath (zh, attributeSet, num_bases, basenames,
2215                              stream, rank_type, rset, xpath_len, xpath);
2216 }
2217
2218 static RSET rpn_search_structure (ZebraHandle zh, Z_RPNStructure *zs,
2219                                   oid_value attributeSet, NMEM stream,
2220                                   Z_SortKeySpecList *sort_sequence,
2221                                   int num_bases, char **basenames)
2222 {
2223     RSET r = NULL;
2224     if (zs->which == Z_RPNStructure_complex)
2225     {
2226         Z_Operator *zop = zs->u.complex->roperator;
2227         rset_bool_parms bool_parms;
2228
2229         bool_parms.rset_l = rpn_search_structure (zh, zs->u.complex->s1,
2230                                                   attributeSet, stream,
2231                                                   sort_sequence,
2232                                                   num_bases, basenames);
2233         if (bool_parms.rset_l == NULL)
2234             return NULL;
2235         bool_parms.rset_r = rpn_search_structure (zh, zs->u.complex->s2,
2236                                                   attributeSet, stream,
2237                                                   sort_sequence,
2238                                                   num_bases, basenames);
2239         if (bool_parms.rset_r == NULL)
2240         {
2241             rset_delete (bool_parms.rset_l);
2242             return NULL;
2243         }
2244         bool_parms.key_size = sizeof(struct it_key);
2245         bool_parms.cmp = key_compare_it;
2246         bool_parms.log_item = key_logdump_txt;
2247
2248         switch (zop->which)
2249         {
2250         case Z_Operator_and:
2251             r = rset_create (rset_kind_and, &bool_parms);
2252             break;
2253         case Z_Operator_or:
2254             r = rset_create (rset_kind_or, &bool_parms);
2255             break;
2256         case Z_Operator_and_not:
2257             r = rset_create (rset_kind_not, &bool_parms);
2258             break;
2259         case Z_Operator_prox:
2260             if (zop->u.prox->which != Z_ProximityOperator_known)
2261             {
2262                 zh->errCode = 132;
2263                 return NULL;
2264             }
2265             if (*zop->u.prox->u.known != Z_ProxUnit_word)
2266             {
2267                 char *val = (char *) nmem_malloc (stream, 16);
2268                 zh->errCode = 132;
2269                 zh->errString = val;
2270                 sprintf (val, "%d", *zop->u.prox->u.known);
2271                 return NULL;
2272             }
2273             else
2274             {
2275                 /* new / old prox */
2276                 rset_prox_parms parms;
2277                 RSET twosets[2];
2278                 
2279                 twosets[0] = bool_parms.rset_l;
2280                 twosets[1] = bool_parms.rset_r;
2281                 parms.rset = twosets;
2282                 parms.rset_no = 2;
2283                 parms.ordered = *zop->u.prox->ordered;
2284                 parms.exclusion = (!zop->u.prox->exclusion ? 0 :
2285                                    *zop->u.prox->exclusion);
2286                 parms.relation = *zop->u.prox->relationType;
2287                 parms.distance = *zop->u.prox->distance;
2288                 parms.key_size = sizeof(struct it_key);
2289                 parms.cmp = key_compare_it;
2290                 parms.getseq = key_get_seq;
2291                 parms.log_item = key_logdump_txt;
2292                 r = rset_create(rset_kind_prox, &parms);
2293             }
2294             break;
2295         default:
2296             zh->errCode = 110;
2297             return NULL;
2298         }
2299     }
2300     else if (zs->which == Z_RPNStructure_simple)
2301     {
2302         if (zs->u.simple->which == Z_Operand_APT)
2303         {
2304             logf (LOG_DEBUG, "rpn_search_APT");
2305             r = rpn_search_APT (zh, zs->u.simple->u.attributesPlusTerm,
2306                                 attributeSet, stream, sort_sequence,
2307                                 num_bases, basenames);
2308         }
2309         else if (zs->u.simple->which == Z_Operand_resultSetId)
2310         {
2311             logf (LOG_DEBUG, "rpn_search_ref");
2312             r = resultSetRef (zh, zs->u.simple->u.resultSetId);
2313             if (!r)
2314             {
2315                 r = rset_create (rset_kind_null, NULL);
2316                 zh->errCode = 30;
2317                 zh->errString =
2318                     nmem_strdup (stream, zs->u.simple->u.resultSetId);
2319                 return 0;
2320             }
2321             else
2322                 rset_dup(r);
2323         }
2324         else
2325         {
2326             zh->errCode = 3;
2327             return 0;
2328         }
2329     }
2330     else
2331     {
2332         zh->errCode = 3;
2333         return 0;
2334     }
2335     return r;
2336 }
2337
2338
2339 RSET rpn_search (ZebraHandle zh, NMEM nmem,
2340                  Z_RPNQuery *rpn, int num_bases, char **basenames, 
2341                  const char *setname,
2342                  ZebraSet sset)
2343 {
2344     RSET rset;
2345     oident *attrset;
2346     oid_value attributeSet;
2347     Z_SortKeySpecList *sort_sequence;
2348     int sort_status, i;
2349
2350     zh->errCode = 0;
2351     zh->errString = NULL;
2352     zh->hits = 0;
2353
2354     sort_sequence = (Z_SortKeySpecList *)
2355         nmem_malloc (nmem, sizeof(*sort_sequence));
2356     sort_sequence->num_specs = 10;
2357     sort_sequence->specs = (Z_SortKeySpec **)
2358         nmem_malloc (nmem, sort_sequence->num_specs *
2359                      sizeof(*sort_sequence->specs));
2360     for (i = 0; i<sort_sequence->num_specs; i++)
2361         sort_sequence->specs[i] = 0;
2362     
2363     attrset = oid_getentbyoid (rpn->attributeSetId);
2364     attributeSet = attrset->value;
2365     rset = rpn_search_structure (zh, rpn->RPNStructure, attributeSet,
2366                                  nmem, sort_sequence, num_bases, basenames);
2367     if (!rset)
2368         return 0;
2369
2370     if (zh->errCode)
2371         logf (LOG_DEBUG, "search error: %d", zh->errCode);
2372     
2373     for (i = 0; sort_sequence->specs[i]; i++)
2374         ;
2375     sort_sequence->num_specs = i;
2376     if (!i)
2377         resultSetRank (zh, sset, rset);
2378     else
2379     {
2380         logf (LOG_DEBUG, "resultSetSortSingle in rpn_search");
2381         resultSetSortSingle (zh, nmem, sset, rset,
2382                              sort_sequence, &sort_status);
2383         if (zh->errCode)
2384         {
2385             logf (LOG_DEBUG, "resultSetSortSingle status = %d", zh->errCode);
2386         }
2387     }
2388     return rset;
2389 }
2390
2391 struct scan_info_entry {
2392     char *term;
2393     ISAMS_P isam_p;
2394 };
2395
2396 struct scan_info {
2397     struct scan_info_entry *list;
2398     ODR odr;
2399     int before, after;
2400     char prefix[20];
2401 };
2402
2403 static int scan_handle (char *name, const char *info, int pos, void *client)
2404 {
2405     int len_prefix, idx;
2406     struct scan_info *scan_info = (struct scan_info *) client;
2407
2408     len_prefix = strlen(scan_info->prefix);
2409     if (memcmp (name, scan_info->prefix, len_prefix))
2410         return 1;
2411     if (pos > 0)        idx = scan_info->after - pos + scan_info->before;
2412     else
2413         idx = - pos - 1;
2414     scan_info->list[idx].term = (char *)
2415         odr_malloc (scan_info->odr, strlen(name + len_prefix)+1);
2416     strcpy (scan_info->list[idx].term, name + len_prefix);
2417     assert (*info == sizeof(ISAMS_P));
2418     memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAMS_P));
2419     return 0;
2420 }
2421
2422 static void scan_term_untrans (ZebraHandle zh, NMEM stream, int reg_type,
2423                                char **dst, const char *src)
2424 {
2425     char term_src[IT_MAX_WORD];
2426     char term_dst[IT_MAX_WORD];
2427     
2428     term_untrans (zh, reg_type, term_src, src);
2429
2430     if (zh->iconv_from_utf8 != 0)
2431     {
2432         int len;
2433         char *inbuf = term_src;
2434         size_t inleft = strlen(term_src);
2435         char *outbuf = term_dst;
2436         size_t outleft = sizeof(term_dst)-1;
2437         size_t ret;
2438         
2439         ret = yaz_iconv (zh->iconv_from_utf8, &inbuf, &inleft,
2440                          &outbuf, &outleft);
2441         if (ret == (size_t)(-1))
2442             len = 0;
2443         else
2444             len = outbuf - term_dst;
2445         *dst = nmem_malloc (stream, len + 1);
2446         if (len > 0)
2447             memcpy (*dst, term_dst, len);
2448         (*dst)[len] = '\0';
2449     }
2450     else
2451         *dst = nmem_strdup (stream, term_src);
2452 }
2453
2454 static void count_set (RSET r, int *count)
2455 {
2456     int psysno = 0;
2457     int kno = 0;
2458     struct it_key key;
2459     RSFD rfd;
2460     int term_index;
2461
2462     logf (LOG_DEBUG, "count_set");
2463
2464     *count = 0;
2465     rfd = rset_open (r, RSETF_READ);
2466     while (rset_read (r, rfd, &key, &term_index))
2467     {
2468         if (key.sysno != psysno)
2469         {
2470             psysno = key.sysno;
2471             (*count)++;
2472         }
2473         kno++;
2474     }
2475     rset_close (r, rfd);
2476     logf (LOG_DEBUG, "%d keys, %d records", kno, *count);
2477 }
2478
2479 void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
2480                oid_value attributeset,
2481                int num_bases, char **basenames,
2482                int *position, int *num_entries, ZebraScanEntry **list,
2483                int *is_partial, RSET limit_set, int return_zero)
2484 {
2485     int i;
2486     int pos = *position;
2487     int num = *num_entries;
2488     int before;
2489     int after;
2490     int base_no;
2491     char termz[IT_MAX_WORD+20];
2492     AttrType use;
2493     int use_value;
2494     const char *use_string = 0;
2495     struct scan_info *scan_info_array;
2496     ZebraScanEntry *glist;
2497     int ords[32], ord_no = 0;
2498     int ptr[32];
2499
2500     int bases_ok = 0;     /* no of databases with OK attribute */
2501     int errCode = 0;      /* err code (if any is not OK) */
2502     char *errString = 0;  /* addinfo */
2503
2504     unsigned reg_id;
2505     char *search_type = NULL;
2506     char rank_type[128];
2507     int complete_flag;
2508     int sort_flag;
2509
2510     *list = 0;
2511
2512     if (attributeset == VAL_NONE)
2513         attributeset = VAL_BIB1;
2514
2515     if (!limit_set)
2516     {
2517         AttrType termset;
2518         int termset_value_numeric;
2519         const char *termset_value_string;
2520         attr_init (&termset, zapt, 8);
2521         termset_value_numeric =
2522             attr_find_ex (&termset, NULL, &termset_value_string);
2523         if (termset_value_numeric != -1)
2524         {
2525             char resname[32];
2526             const char *termset_name = 0;
2527             
2528             if (termset_value_numeric != -2)
2529             {
2530                 
2531                 sprintf (resname, "%d", termset_value_numeric);
2532                 termset_name = resname;
2533             }
2534             else
2535                 termset_name = termset_value_string;
2536             
2537             limit_set = resultSetRef (zh, termset_name);
2538         }
2539     }
2540         
2541     yaz_log (LOG_DEBUG, "position = %d, num = %d set=%d",
2542              pos, num, attributeset);
2543         
2544     attr_init (&use, zapt, 1);
2545     use_value = attr_find_ex (&use, &attributeset, &use_string);
2546
2547     if (zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2548                          rank_type, &complete_flag, &sort_flag))
2549     {
2550         *num_entries = 0;
2551         zh->errCode = 113;
2552         return ;
2553     }
2554     yaz_log (LOG_DEBUG, "use_value = %d", use_value);
2555
2556     if (use_value == -1)
2557         use_value = 1016;
2558     for (base_no = 0; base_no < num_bases && ord_no < 32; base_no++)
2559     {
2560         int r;
2561         attent attp;
2562         data1_local_attribute *local_attr;
2563
2564         if ((r=att_getentbyatt (zh, &attp, attributeset, use_value,
2565                                 use_string)))
2566         {
2567             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d",
2568                   attributeset, use_value);
2569             if (r == -1)
2570             {
2571                 char val_str[32];
2572                 sprintf (val_str, "%d", use_value);
2573                 errCode = 114;
2574                 errString = odr_strdup (stream, val_str);
2575             }   
2576             else
2577                 errCode = 121;
2578             continue;
2579         }
2580         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2581         {
2582             zh->errString = basenames[base_no];
2583             zh->errCode = 109; /* Database unavailable */
2584             *num_entries = 0;
2585             return;
2586         }
2587         bases_ok++;
2588         for (local_attr = attp.local_attributes; local_attr && ord_no < 32;
2589              local_attr = local_attr->next)
2590         {
2591             int ord;
2592
2593             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
2594                                          local_attr->local);
2595             if (ord > 0)
2596                 ords[ord_no++] = ord;
2597         }
2598     }
2599     if (!bases_ok && errCode)
2600     {
2601         zh->errCode = errCode;
2602         zh->errString = errString;
2603         *num_entries = 0;
2604     }
2605     if (ord_no == 0)
2606     {
2607         char val_str[32];
2608         sprintf (val_str, "%d", use_value);
2609         zh->errCode = 114;
2610         zh->errString = odr_strdup (stream, val_str);
2611
2612         *num_entries = 0;
2613         return;
2614     }
2615     /* prepare dictionary scanning */
2616     before = pos-1;
2617     after = 1+num-pos;
2618     scan_info_array = (struct scan_info *)
2619         odr_malloc (stream, ord_no * sizeof(*scan_info_array));
2620     for (i = 0; i < ord_no; i++)
2621     {
2622         int j, prefix_len = 0;
2623         int before_tmp = before, after_tmp = after;
2624         struct scan_info *scan_info = scan_info_array + i;
2625         struct rpn_char_map_info rcmi;
2626
2627         rpn_char_map_prepare (zh->reg, reg_id, &rcmi);
2628
2629         scan_info->before = before;
2630         scan_info->after = after;
2631         scan_info->odr = stream;
2632
2633         scan_info->list = (struct scan_info_entry *)
2634             odr_malloc (stream, (before+after) * sizeof(*scan_info->list));
2635         for (j = 0; j<before+after; j++)
2636             scan_info->list[j].term = NULL;
2637
2638         prefix_len += key_SU_encode (ords[i], termz + prefix_len);
2639         termz[prefix_len++] = reg_id;
2640         termz[prefix_len] = 0;
2641         strcpy (scan_info->prefix, termz);
2642
2643         if (trans_scan_term (zh, zapt, termz+prefix_len, reg_id))
2644             return ;
2645                     
2646         dict_scan (zh->reg->dict, termz, &before_tmp, &after_tmp,
2647                    scan_info, scan_handle);
2648     }
2649     glist = (ZebraScanEntry *)
2650         odr_malloc (stream, (before+after)*sizeof(*glist));
2651
2652     /* consider terms after main term */
2653     for (i = 0; i < ord_no; i++)
2654         ptr[i] = before;
2655     
2656     *is_partial = 0;
2657     for (i = 0; i<after; i++)
2658     {
2659         int j, j0 = -1;
2660         const char *mterm = NULL;
2661         const char *tst;
2662         RSET rset;
2663         
2664         for (j = 0; j < ord_no; j++)
2665         {
2666             if (ptr[j] < before+after &&
2667                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2668                 (!mterm || strcmp (tst, mterm) < 0))
2669             {
2670                 j0 = j;
2671                 mterm = tst;
2672             }
2673         }
2674         if (j0 == -1)
2675             break;
2676         scan_term_untrans (zh, stream->mem, reg_id,
2677                            &glist[i+before].term, mterm);
2678         rset = rset_trunc (zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
2679                            glist[i+before].term, strlen(glist[i+before].term),
2680                            NULL, 0, zapt->term->which);
2681
2682         ptr[j0]++;
2683         for (j = j0+1; j<ord_no; j++)
2684         {
2685             if (ptr[j] < before+after &&
2686                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2687                 !strcmp (tst, mterm))
2688             {
2689                 rset_bool_parms bool_parms;
2690                 RSET rset2;
2691
2692                 rset2 =
2693                    rset_trunc (zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
2694                                glist[i+before].term,
2695                                strlen(glist[i+before].term), NULL, 0,
2696                                zapt->term->which);
2697
2698                 bool_parms.key_size = sizeof(struct it_key);
2699                 bool_parms.cmp = key_compare_it;
2700                 bool_parms.log_item = key_logdump_txt;
2701                 bool_parms.rset_l = rset;
2702                 bool_parms.rset_r = rset2;
2703               
2704                 rset = rset_create (rset_kind_or, &bool_parms);
2705
2706                 ptr[j]++;
2707             }
2708         }
2709         if (limit_set)
2710         {
2711             rset_bool_parms bool_parms;
2712
2713             bool_parms.key_size = sizeof(struct it_key);
2714             bool_parms.cmp = key_compare_it;
2715             bool_parms.log_item = key_logdump_txt;
2716             bool_parms.rset_l = rset;
2717             bool_parms.rset_r = rset_dup(limit_set);
2718
2719             rset = rset_create (rset_kind_and, &bool_parms);
2720         }
2721         count_set (rset, &glist[i+before].occurrences);
2722         rset_delete (rset);
2723     }
2724     if (i < after)
2725     {
2726         *num_entries -= (after-i);
2727         *is_partial = 1;
2728     }
2729
2730     /* consider terms before main term */
2731     for (i = 0; i<ord_no; i++)
2732         ptr[i] = 0;
2733
2734     for (i = 0; i<before; i++)
2735     {
2736         int j, j0 = -1;
2737         const char *mterm = NULL;
2738         const char *tst;
2739         RSET rset;
2740         
2741         for (j = 0; j <ord_no; j++)
2742         {
2743             if (ptr[j] < before &&
2744                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2745                 (!mterm || strcmp (tst, mterm) > 0))
2746             {
2747                 j0 = j;
2748                 mterm = tst;
2749             }
2750         }
2751         if (j0 == -1)
2752             break;
2753
2754         scan_term_untrans (zh, stream->mem, reg_id,
2755                            &glist[before-1-i].term, mterm);
2756
2757         rset = rset_trunc
2758                (zh, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1,
2759                 glist[before-1-i].term, strlen(glist[before-1-i].term),
2760                 NULL, 0, zapt->term->which);
2761
2762         ptr[j0]++;
2763
2764         for (j = j0+1; j<ord_no; j++)
2765         {
2766             if (ptr[j] < before &&
2767                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2768                 !strcmp (tst, mterm))
2769             {
2770                 rset_bool_parms bool_parms;
2771                 RSET rset2;
2772
2773                 rset2 = rset_trunc (zh,
2774                          &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1,
2775                                     glist[before-1-i].term,
2776                                     strlen(glist[before-1-i].term), NULL, 0,
2777                                     zapt->term->which);
2778
2779                 bool_parms.key_size = sizeof(struct it_key);
2780                 bool_parms.cmp = key_compare_it;
2781                 bool_parms.log_item = key_logdump_txt;
2782                 bool_parms.rset_l = rset;
2783                 bool_parms.rset_r = rset2;
2784               
2785                 rset = rset_create (rset_kind_or, &bool_parms);
2786
2787                 ptr[j]++;
2788             }
2789         }
2790         if (limit_set)
2791         {
2792             rset_bool_parms bool_parms;
2793
2794             bool_parms.key_size = sizeof(struct it_key);
2795             bool_parms.cmp = key_compare_it;
2796             bool_parms.log_item = key_logdump_txt;
2797             bool_parms.rset_l = rset;
2798             bool_parms.rset_r = rset_dup(limit_set);
2799
2800             rset = rset_create (rset_kind_and, &bool_parms);
2801         }
2802         count_set (rset, &glist[before-1-i].occurrences);
2803         rset_delete (rset);
2804     }
2805     i = before-i;
2806     if (i)
2807     {
2808         *is_partial = 1;
2809         *position -= i;
2810         *num_entries -= i;
2811     }
2812     *list = glist + i;               /* list is set to first 'real' entry */
2813     
2814     logf (LOG_DEBUG, "position = %d, num_entries = %d",
2815           *position, *num_entries);
2816     if (zh->errCode)
2817         logf (LOG_DEBUG, "scan error: %d", zh->errCode);
2818 }
2819