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