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