Hits per term. Returned in SearchResult-1
[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.110 2002-03-20 20:24:29 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.cmp = key_compare_it;
1140         parms.key_size = sizeof (struct it_key);
1141         parms.temp_path = res_get (zh->service->res, "setTmpDir");
1142         result = rset_create (rset_kind_temp, &parms);
1143         rsfd_result = rset_open (result, RSETF_WRITE);
1144         
1145         while (*more)
1146         {
1147             for (i = 1; i<rset_no; i++)
1148             {
1149                 int cmp;
1150                 
1151                 if (!more[i])
1152                 {
1153                     *more = 0;
1154                     break;
1155                 }
1156                 cmp = key_compare_it (buf[i], buf[i-1]);
1157                 if (cmp > 1)
1158                 {
1159                     more[i-1] = rset_read (rset[i-1], rsfd[i-1],
1160                                            buf[i-1], &term_index);
1161                     break;
1162                 }
1163                 else if (cmp == 1)
1164                 {
1165                     if (buf[i-1]->seqno+1 != buf[i]->seqno)
1166                     {
1167                         more[i-1] = rset_read (rset[i-1], rsfd[i-1],
1168                                                buf[i-1], &term_index);
1169                         break;
1170                     }
1171                 }
1172                 else
1173                 {
1174                     more[i] = rset_read (rset[i], rsfd[i], buf[i],
1175                                          &term_index);
1176                     break;
1177                 }
1178             }
1179             if (i == rset_no)
1180             {
1181                 rset_write (result, rsfd_result, buf[0]);
1182                 more[0] = rset_read (*rset, *rsfd, *buf, &term_index);
1183             }
1184         }
1185         rset_close (result, rsfd_result);
1186     }
1187     else if (rset_no == 2)
1188     {
1189         /* generic proximity case (two input sets only) ... */
1190         rset_temp_parms parms;
1191         RSFD rsfd_result;
1192
1193         logf (LOG_LOG, "generic prox, dist = %d, relation = %d, ordered =%d, exclusion=%d",
1194               distance, relation, ordered, exclusion);
1195         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1196                                             flags);
1197         parms.rset_term->nn = min_nn;
1198         parms.cmp = key_compare_it;
1199         parms.key_size = sizeof (struct it_key);
1200         parms.temp_path = res_get (zh->service->res, "setTmpDir");
1201         result = rset_create (rset_kind_temp, &parms);
1202         rsfd_result = rset_open (result, RSETF_WRITE);
1203
1204         while (more[0] && more[1]) 
1205         {
1206             int cmp = key_compare_it (buf[0], buf[1]);
1207             if (cmp < -1)
1208                 more[0] = rset_read (rset[0], rsfd[0], buf[0], &term_index);
1209             else if (cmp > 1)
1210                 more[1] = rset_read (rset[1], rsfd[1], buf[1], &term_index);
1211             else
1212             {
1213                 int sysno = buf[0]->sysno;
1214                 int seqno[500];
1215                 int n = 0;
1216                 
1217                 seqno[n++] = buf[0]->seqno;
1218                 while ((more[0] = rset_read (rset[0], rsfd[0], buf[0],
1219                                              &term_index)) &&
1220                        sysno == buf[0]->sysno)
1221                     if (n < 500)
1222                         seqno[n++] = buf[0]->seqno;
1223                 do
1224                 {
1225                     for (i = 0; i<n; i++)
1226                     {
1227                         int diff = buf[1]->seqno - seqno[i];
1228                         int excl = exclusion;
1229                         if (!ordered && diff < 0)
1230                             diff = -diff;
1231                         switch (relation)
1232                         {
1233                         case 1:      /* < */
1234                             if (diff < distance && diff >= 0)
1235                                 excl = !excl;
1236                             break;
1237                         case 2:      /* <= */
1238                             if (diff <= distance && diff >= 0)
1239                                 excl = !excl;
1240                             break;
1241                         case 3:      /* == */
1242                             if (diff == distance && diff >= 0)
1243                                 excl = !excl;
1244                             break;
1245                         case 4:      /* >= */
1246                             if (diff >= distance && diff >= 0)
1247                                 excl = !excl;
1248                             break;
1249                         case 5:      /* > */
1250                             if (diff > distance && diff >= 0)
1251                                 excl = !excl;
1252                             break;
1253                         case 6:      /* != */
1254                             if (diff != distance && diff >= 0)
1255                                 excl = !excl;
1256                             break;
1257                         }
1258                         if (excl)
1259                         {
1260                             rset_write (result, rsfd_result, buf[1]);
1261                             break;
1262                         }
1263                     }
1264                 } while ((more[1] = rset_read (rset[1], rsfd[1], buf[1],
1265                                                &term_index)) &&
1266                          sysno == buf[1]->sysno);
1267             }
1268         }
1269         rset_close (result, rsfd_result);
1270     }
1271     else
1272     {
1273         rset_null_parms parms;
1274         
1275         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1276                                             flags);
1277         parms.rset_term->nn = 0;
1278         result = rset_create (rset_kind_null, &parms);
1279     }
1280     for (i = 0; i<rset_no; i++)
1281     {
1282         if (rsfd[i])
1283             rset_close (rset[i], rsfd[i]);
1284         xfree (buf[i]);
1285     }
1286     xfree (buf);
1287     xfree (more);
1288     xfree (rsfd);
1289     return result;
1290 }
1291
1292
1293 char *normalize_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1294                      const char *termz, NMEM stream, unsigned reg_id)
1295 {
1296     WRBUF wrbuf = 0;
1297     AttrType truncation;
1298     int truncation_value;
1299     char *ex_list = 0;
1300
1301     attr_init (&truncation, zapt, 5);
1302     truncation_value = attr_find (&truncation, NULL);
1303
1304     switch (truncation_value)
1305     {
1306     default:
1307         ex_list = "";
1308         break;
1309     case 101:
1310         ex_list = "#";
1311         break;
1312     case 102:
1313     case 103:
1314         ex_list = 0;
1315         break;
1316     case 104:
1317         ex_list = "!#";
1318         break;
1319     case 105:
1320         ex_list = "!*";
1321         break;
1322     }
1323     if (ex_list)
1324         wrbuf = zebra_replace(zh->service->zebra_maps, reg_id, ex_list,
1325                               termz, strlen(termz));
1326     if (!wrbuf)
1327         return nmem_strdup(stream, termz);
1328     else
1329     {
1330         char *buf = (char*) nmem_malloc (stream, wrbuf_len(wrbuf)+1);
1331         memcpy (buf, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
1332         buf[wrbuf_len(wrbuf)] = '\0';
1333         return buf;
1334     }
1335 }
1336
1337 static int grep_info_prepare (ZebraHandle zh,
1338                               Z_AttributesPlusTerm *zapt,
1339                               struct grep_info *grep_info,
1340                               int reg_type,
1341                               NMEM stream)
1342 {
1343     AttrType termset;
1344     int termset_value_numeric;
1345     const char *termset_value_string;
1346
1347 #ifdef TERM_COUNT
1348     grep_info->term_no = 0;
1349 #endif
1350     grep_info->isam_p_size = 0;
1351     grep_info->isam_p_buf = NULL;
1352     grep_info->zh = zh;
1353     grep_info->reg_type = reg_type;
1354     grep_info->termset = 0;
1355
1356     attr_init (&termset, zapt, 8);
1357     termset_value_numeric =
1358         attr_find_ex (&termset, NULL, &termset_value_string);
1359     if (termset_value_numeric != -1)
1360     {
1361         char resname[32];
1362         const char *termset_name = 0;
1363         if (termset_value_numeric != -2)
1364         {
1365     
1366             sprintf (resname, "%d", termset_value_numeric);
1367             termset_name = resname;
1368         }
1369         else
1370             termset_name = termset_value_string;
1371         logf (LOG_LOG, "creating termset set %s", termset_name);
1372         grep_info->termset = resultSetAdd (zh, termset_name, 1);
1373         if (!grep_info->termset)
1374         {
1375             zh->errCode = 128;
1376             zh->errString = nmem_strdup (stream, termset_name);
1377             return -1;
1378         }
1379     }
1380     return 0;
1381 }
1382                                
1383
1384 static RSET rpn_search_APT_phrase (ZebraHandle zh,
1385                                    Z_AttributesPlusTerm *zapt,
1386                                    const char *termz_org,
1387                                    oid_value attributeSet,
1388                                    NMEM stream,
1389                                    int reg_type, int complete_flag,
1390                                    const char *rank_type,
1391                                    int num_bases, char **basenames)
1392 {
1393     char term_dst[IT_MAX_WORD+1];
1394     RSET rset[60], result;
1395     int i, r, rset_no = 0;
1396     struct grep_info grep_info;
1397     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1398     const char *termp = termz;
1399
1400     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1401         return 0;
1402     while (1)
1403     { 
1404         logf (LOG_DEBUG, "APT_phrase termp=%s", termp);
1405         grep_info.isam_p_indx = 0;
1406         r = string_term (zh, zapt, &termp, attributeSet, stream, &grep_info,
1407                         reg_type, complete_flag, num_bases, basenames,
1408                         term_dst);
1409         if (r < 1)
1410             break;
1411         logf (LOG_DEBUG, "term: %s", term_dst);
1412         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
1413                                     grep_info.isam_p_indx, term_dst,
1414                                     strlen(term_dst), rank_type);
1415         assert (rset[rset_no]);
1416         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1417             break;
1418     }
1419 #ifdef TERM_COUNT
1420     xfree(grep_info.term_no);
1421 #endif
1422     xfree (grep_info.isam_p_buf);
1423     if (rset_no == 0)
1424     {
1425         rset_null_parms parms;
1426         
1427         parms.rset_term = rset_term_create (term_dst, -1, rank_type);
1428         return rset_create (rset_kind_null, &parms);
1429     }
1430     else if (rset_no == 1)
1431         return (rset[0]);
1432     result = rpn_prox (zh, rset, rset_no, 1, 0, 3, 1);
1433     for (i = 0; i<rset_no; i++)
1434         rset_delete (rset[i]);
1435     return result;
1436 }
1437
1438 static RSET rpn_search_APT_or_list (ZebraHandle zh,
1439                                     Z_AttributesPlusTerm *zapt,
1440                                     const char *termz_org,
1441                                     oid_value attributeSet,
1442                                     NMEM stream,
1443                                     int reg_type, int complete_flag,
1444                                     const char *rank_type,
1445                                     int num_bases, char **basenames)
1446 {
1447     char term_dst[IT_MAX_WORD+1];
1448     RSET rset[60], result;
1449     int i, r, rset_no = 0;
1450     struct grep_info grep_info;
1451     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1452     const char *termp = termz;
1453
1454     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1455         return 0;
1456     while (1)
1457     { 
1458         logf (LOG_DEBUG, "APT_or_list termp=%s", termp);
1459         grep_info.isam_p_indx = 0;
1460         r = string_term (zh, zapt, &termp, attributeSet, stream, &grep_info,
1461                         reg_type, complete_flag, num_bases, basenames,
1462                         term_dst);
1463         if (r < 1)
1464             break;
1465         logf (LOG_DEBUG, "term: %s", term_dst);
1466         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
1467                                     grep_info.isam_p_indx, term_dst,
1468                                     strlen(term_dst), rank_type);
1469         assert (rset[rset_no]);
1470         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1471             break;
1472     }
1473 #ifdef TERM_COUNT
1474     xfree(grep_info.term_no);
1475 #endif
1476     xfree (grep_info.isam_p_buf);
1477     if (rset_no == 0)
1478     {
1479         rset_null_parms parms;
1480         
1481         parms.rset_term = rset_term_create (term_dst, -1, rank_type);
1482         return rset_create (rset_kind_null, &parms);
1483     }
1484     result = rset[0];
1485     for (i = 1; i<rset_no; i++)
1486     {
1487         rset_bool_parms bool_parms;
1488
1489         bool_parms.rset_l = result;
1490         bool_parms.rset_r = rset[i];
1491         bool_parms.key_size = sizeof(struct it_key);
1492         bool_parms.cmp = key_compare_it;
1493         result = rset_create (rset_kind_or, &bool_parms);
1494     }
1495     return result;
1496 }
1497
1498 static RSET rpn_search_APT_and_list (ZebraHandle zh,
1499                                      Z_AttributesPlusTerm *zapt,
1500                                      const char *termz_org,
1501                                      oid_value attributeSet,
1502                                      NMEM stream,
1503                                      int reg_type, int complete_flag,
1504                                      const char *rank_type,
1505                                      int num_bases, char **basenames)
1506 {
1507     char term_dst[IT_MAX_WORD+1];
1508     RSET rset[60], result;
1509     int i, r, rset_no = 0;
1510     struct grep_info grep_info;
1511     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1512     const char *termp = termz;
1513
1514     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1515         return 0;
1516     while (1)
1517     { 
1518         logf (LOG_DEBUG, "APT_and_list termp=%s", termp);
1519         grep_info.isam_p_indx = 0;
1520         r = string_term (zh, zapt, &termp, attributeSet, stream, &grep_info,
1521                         reg_type, complete_flag, num_bases, basenames,
1522                         term_dst);
1523         if (r < 1)
1524             break;
1525         logf (LOG_DEBUG, "term: %s", term_dst);
1526         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
1527                                     grep_info.isam_p_indx, term_dst,
1528                                     strlen(term_dst), rank_type);
1529         assert (rset[rset_no]);
1530         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1531             break;
1532     }
1533 #ifdef TERM_COUNT
1534     xfree(grep_info.term_no);
1535 #endif
1536     xfree (grep_info.isam_p_buf);
1537     if (rset_no == 0)
1538     {
1539         rset_null_parms parms;
1540         
1541         parms.rset_term = rset_term_create (term_dst, -1, rank_type);
1542         return rset_create (rset_kind_null, &parms);
1543     }
1544     result = rset[0];
1545     for (i = 1; i<rset_no; i++)
1546     {
1547         rset_bool_parms bool_parms;
1548
1549         bool_parms.rset_l = result;
1550         bool_parms.rset_r = rset[i];
1551         bool_parms.key_size = sizeof(struct it_key);
1552         bool_parms.cmp = key_compare_it;
1553         result = rset_create (rset_kind_and, &bool_parms);
1554     }
1555     return result;
1556 }
1557
1558 static int numeric_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1559                              const char **term_sub,
1560                              char *term_dict,
1561                              oid_value attributeSet,
1562                              struct grep_info *grep_info,
1563                              int *max_pos,
1564                              int reg_type,
1565                              char *term_dst)
1566 {
1567     AttrType relation;
1568     int relation_value;
1569     int term_value;
1570     int r;
1571     char *term_tmp = term_dict + strlen(term_dict);
1572
1573     attr_init (&relation, zapt, 2);
1574     relation_value = attr_find (&relation, NULL);
1575
1576     logf (LOG_DEBUG, "numeric relation value=%d", relation_value);
1577
1578     if (!term_100 (zh->service->zebra_maps, reg_type, term_sub, term_tmp, 1,
1579                    term_dst))
1580         return 0;
1581     term_value = atoi (term_tmp);
1582     switch (relation_value)
1583     {
1584     case 1:
1585         logf (LOG_DEBUG, "Relation <");
1586         gen_regular_rel (term_tmp, term_value-1, 1);
1587         break;
1588     case 2:
1589         logf (LOG_DEBUG, "Relation <=");
1590         gen_regular_rel (term_tmp, term_value, 1);
1591         break;
1592     case 4:
1593         logf (LOG_DEBUG, "Relation >=");
1594         gen_regular_rel (term_tmp, term_value, 0);
1595         break;
1596     case 5:
1597         logf (LOG_DEBUG, "Relation >");
1598         gen_regular_rel (term_tmp, term_value+1, 0);
1599         break;
1600     case 3:
1601     default:
1602         logf (LOG_DEBUG, "Relation =");
1603         sprintf (term_tmp, "(0*%d)", term_value);
1604     }
1605     logf (LOG_DEBUG, "dict_lookup_grep: %s", term_tmp);
1606     r = dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info, max_pos,
1607                           0, grep_handle);
1608     if (r)
1609         logf (LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
1610     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1611     return 1;
1612 }
1613
1614 static int numeric_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1615                          const char **term_sub, 
1616                          oid_value attributeSet, struct grep_info *grep_info,
1617                          int reg_type, int complete_flag,
1618                          int num_bases, char **basenames,
1619                          char *term_dst)
1620 {
1621     char term_dict[2*IT_MAX_WORD+2];
1622     int r, base_no;
1623     AttrType use;
1624     int use_value;
1625     oid_value curAttributeSet = attributeSet;
1626     const char *termp;
1627     struct rpn_char_map_info rcmi;
1628
1629     rpn_char_map_prepare (zh, reg_type, &rcmi);
1630     attr_init (&use, zapt, 1);
1631     use_value = attr_find (&use, &curAttributeSet);
1632     logf (LOG_DEBUG, "numeric_term, use value %d", use_value);
1633
1634     if (use_value == -1)
1635         use_value = 1016;
1636
1637     for (base_no = 0; base_no < num_bases; base_no++)
1638     {
1639         attent attp;
1640         data1_local_attribute *local_attr;
1641         int max_pos, prefix_len = 0;
1642
1643         termp = *term_sub;
1644         if ((r=att_getentbyatt (zh, &attp, curAttributeSet, use_value)))
1645         {
1646             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
1647                   curAttributeSet, use_value, r);
1648             if (r == -1)
1649                 zh->errCode = 114;
1650             else
1651                 zh->errCode = 121;
1652             return -1;
1653         }
1654         if (zebraExplain_curDatabase (zh->service->zei, basenames[base_no]))
1655         {
1656             zh->errCode = 109; /* Database unavailable */
1657             zh->errString = basenames[base_no];
1658             return -1;
1659         }
1660         for (local_attr = attp.local_attributes; local_attr;
1661              local_attr = local_attr->next)
1662         {
1663             int ord;
1664             char ord_buf[32];
1665             int i, ord_len;
1666
1667             ord = zebraExplain_lookupSU (zh->service->zei, attp.attset_ordinal,
1668                                           local_attr->local);
1669             if (ord < 0)
1670                 continue;
1671             if (prefix_len)
1672                 term_dict[prefix_len++] = '|';
1673             else
1674                 term_dict[prefix_len++] = '(';
1675
1676             ord_len = key_SU_encode (ord, ord_buf);
1677             for (i = 0; i<ord_len; i++)
1678             {
1679                 term_dict[prefix_len++] = 1;
1680                 term_dict[prefix_len++] = ord_buf[i];
1681             }
1682         }
1683         if (!prefix_len)
1684         {
1685             zh->errCode = 114;
1686             return -1;
1687         }
1688         term_dict[prefix_len++] = ')';        
1689         term_dict[prefix_len++] = 1;
1690         term_dict[prefix_len++] = reg_type;
1691         logf (LOG_DEBUG, "reg_type = %d", term_dict[prefix_len-1]);
1692         term_dict[prefix_len] = '\0';
1693         if (!numeric_relation (zh, zapt, &termp, term_dict,
1694                                attributeSet, grep_info, &max_pos, reg_type,
1695                                term_dst))
1696             return 0;
1697     }
1698     *term_sub = termp;
1699     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1700     return 1;
1701 }
1702
1703 static RSET rpn_search_APT_numeric (ZebraHandle zh,
1704                                     Z_AttributesPlusTerm *zapt,
1705                                     const char *termz,
1706                                     oid_value attributeSet,
1707                                     NMEM stream,
1708                                     int reg_type, int complete_flag,
1709                                     const char *rank_type,
1710                                     int num_bases, char **basenames)
1711 {
1712     char term_dst[IT_MAX_WORD+1];
1713     const char *termp = termz;
1714     RSET rset[60], result;
1715     int i, r, rset_no = 0;
1716     struct grep_info grep_info;
1717
1718     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1719         return 0;
1720     while (1)
1721     { 
1722         logf (LOG_DEBUG, "APT_numeric termp=%s", termp);
1723         grep_info.isam_p_indx = 0;
1724         r = numeric_term (zh, zapt, &termp, attributeSet, &grep_info,
1725                           reg_type, complete_flag, num_bases, basenames,
1726                           term_dst);
1727         if (r < 1)
1728             break;
1729         logf (LOG_DEBUG, "term: %s", term_dst);
1730         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
1731                                     grep_info.isam_p_indx, term_dst,
1732                                     strlen(term_dst), rank_type);
1733         assert (rset[rset_no]);
1734         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1735             break;
1736     }
1737 #ifdef TERM_COUNT
1738     xfree(grep_info.term_no);
1739 #endif
1740     xfree (grep_info.isam_p_buf);
1741     if (rset_no == 0)
1742     {
1743         rset_null_parms parms;
1744         
1745         parms.rset_term = rset_term_create (term_dst, -1, rank_type);
1746         return rset_create (rset_kind_null, &parms);
1747     }
1748     result = rset[0];
1749     for (i = 1; i<rset_no; i++)
1750     {
1751         rset_bool_parms bool_parms;
1752
1753         bool_parms.rset_l = result;
1754         bool_parms.rset_r = rset[i];
1755         bool_parms.key_size = sizeof(struct it_key);
1756         bool_parms.cmp = key_compare_it;
1757         result = rset_create (rset_kind_and, &bool_parms);
1758     }
1759     return result;
1760 }
1761
1762 static RSET rpn_search_APT_local (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1763                                   const char *termz,
1764                                   oid_value attributeSet,
1765                                   NMEM stream,
1766                                   const char *rank_type)
1767 {
1768     RSET result;
1769     RSFD rsfd;
1770     struct it_key key;
1771     rset_temp_parms parms;
1772
1773     parms.rset_term = rset_term_create (termz, -1, rank_type);
1774     parms.cmp = key_compare_it;
1775     parms.key_size = sizeof (struct it_key);
1776     parms.temp_path = res_get (zh->service->res, "setTmpDir");
1777     result = rset_create (rset_kind_temp, &parms);
1778     rsfd = rset_open (result, RSETF_WRITE);
1779
1780     key.sysno = atoi (termz);
1781     key.seqno = 1;
1782     if (key.sysno <= 0)
1783         key.sysno = 1;
1784     rset_write (result, rsfd, &key);
1785     rset_close (result, rsfd);
1786     return result;
1787 }
1788
1789 static RSET rpn_sort_spec (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1790                            oid_value attributeSet, NMEM stream,
1791                            Z_SortKeySpecList *sort_sequence,
1792                            const char *rank_type)
1793 {
1794     rset_null_parms parms;    
1795     int i;
1796     int sort_relation_value;
1797     AttrType sort_relation_type;
1798     int use_value;
1799     AttrType use_type;
1800     Z_SortKeySpec *sks;
1801     Z_SortKey *sk;
1802     Z_AttributeElement *ae;
1803     int oid[OID_SIZE];
1804     oident oe;
1805     
1806     attr_init (&sort_relation_type, zapt, 7);
1807     sort_relation_value = attr_find (&sort_relation_type, &attributeSet);
1808
1809     attr_init (&use_type, zapt, 1);
1810     use_value = attr_find (&use_type, &attributeSet);
1811
1812     if (!sort_sequence->specs)
1813     {
1814         sort_sequence->num_specs = 10;
1815         sort_sequence->specs = (Z_SortKeySpec **)
1816             nmem_malloc (stream, sort_sequence->num_specs *
1817                          sizeof(*sort_sequence->specs));
1818         for (i = 0; i<sort_sequence->num_specs; i++)
1819             sort_sequence->specs[i] = 0;
1820     }
1821     if (zapt->term->which != Z_Term_general)
1822         i = 0;
1823     else
1824         i = atoi_n ((char *) zapt->term->u.general->buf,
1825                     zapt->term->u.general->len);
1826     if (i >= sort_sequence->num_specs)
1827         i = 0;
1828
1829     oe.proto = PROTO_Z3950;
1830     oe.oclass = CLASS_ATTSET;
1831     oe.value = attributeSet;
1832     if (!oid_ent_to_oid (&oe, oid))
1833         return 0;
1834
1835     sks = (Z_SortKeySpec *) nmem_malloc (stream, sizeof(*sks));
1836     sks->sortElement = (Z_SortElement *)
1837         nmem_malloc (stream, sizeof(*sks->sortElement));
1838     sks->sortElement->which = Z_SortElement_generic;
1839     sk = sks->sortElement->u.generic = (Z_SortKey *)
1840         nmem_malloc (stream, sizeof(*sk));
1841     sk->which = Z_SortKey_sortAttributes;
1842     sk->u.sortAttributes = (Z_SortAttributes *)
1843         nmem_malloc (stream, sizeof(*sk->u.sortAttributes));
1844
1845     sk->u.sortAttributes->id = oid;
1846     sk->u.sortAttributes->list = (Z_AttributeList *)
1847         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list));
1848     sk->u.sortAttributes->list->num_attributes = 1;
1849     sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
1850         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list->attributes));
1851     ae = *sk->u.sortAttributes->list->attributes = (Z_AttributeElement *)
1852         nmem_malloc (stream, sizeof(**sk->u.sortAttributes->list->attributes));
1853     ae->attributeSet = 0;
1854     ae->attributeType = (int *)
1855         nmem_malloc (stream, sizeof(*ae->attributeType));
1856     *ae->attributeType = 1;
1857     ae->which = Z_AttributeValue_numeric;
1858     ae->value.numeric = (int *)
1859         nmem_malloc (stream, sizeof(*ae->value.numeric));
1860     *ae->value.numeric = use_value;
1861
1862     sks->sortRelation = (int *)
1863         nmem_malloc (stream, sizeof(*sks->sortRelation));
1864     if (sort_relation_value == 1)
1865         *sks->sortRelation = Z_SortRelation_ascending;
1866     else if (sort_relation_value == 2)
1867         *sks->sortRelation = Z_SortRelation_descending;
1868     else 
1869         *sks->sortRelation = Z_SortRelation_ascending;
1870
1871     sks->caseSensitivity = (int *)
1872         nmem_malloc (stream, sizeof(*sks->caseSensitivity));
1873     *sks->caseSensitivity = 0;
1874
1875 #ifdef ASN_COMPILED
1876     sks->which = Z_SortKeySpec_null;
1877     sks->u.null = odr_nullval ();
1878 #else
1879     sks->missingValueAction = 0;
1880 #endif
1881
1882     sort_sequence->specs[i] = sks;
1883
1884     parms.rset_term = rset_term_create ("", -1, rank_type);
1885     return rset_create (rset_kind_null, &parms);
1886 }
1887
1888
1889 static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1890                             oid_value attributeSet, NMEM stream,
1891                             Z_SortKeySpecList *sort_sequence,
1892                             int num_bases, char **basenames)
1893 {
1894     unsigned reg_id;
1895     char *search_type = NULL;
1896     char rank_type[128];
1897     int complete_flag;
1898     int sort_flag;
1899     char termz[IT_MAX_WORD+1];
1900
1901     zebra_maps_attr (zh->service->zebra_maps, zapt, &reg_id, &search_type,
1902                      rank_type, &complete_flag, &sort_flag);
1903     
1904     logf (LOG_DEBUG, "reg_id=%c", reg_id);
1905     logf (LOG_DEBUG, "complete_flag=%d", complete_flag);
1906     logf (LOG_DEBUG, "search_type=%s", search_type);
1907     logf (LOG_DEBUG, "rank_type=%s", rank_type);
1908
1909     if (zapt->term->which != Z_Term_general)
1910     {
1911         zh->errCode = 124;
1912         return NULL;
1913     }
1914     trans_term (zh, zapt, termz);
1915
1916     if (sort_flag)
1917         return rpn_sort_spec (zh, zapt, attributeSet, stream, sort_sequence,
1918                               rank_type);
1919
1920     if (!strcmp (search_type, "phrase"))
1921     {
1922         return rpn_search_APT_phrase (zh, zapt, termz, attributeSet, stream,
1923                                       reg_id, complete_flag, rank_type,
1924                                       num_bases, basenames);
1925     }
1926     else if (!strcmp (search_type, "and-list"))
1927     {
1928         return rpn_search_APT_and_list (zh, zapt, termz, attributeSet, stream,
1929                                         reg_id, complete_flag, rank_type,
1930                                         num_bases, basenames);
1931     }
1932     else if (!strcmp (search_type, "or-list"))
1933     {
1934         return rpn_search_APT_or_list (zh, zapt, termz, attributeSet, stream,
1935                                        reg_id, complete_flag, rank_type,
1936                                        num_bases, basenames);
1937     }
1938     else if (!strcmp (search_type, "local"))
1939     {
1940         return rpn_search_APT_local (zh, zapt, termz, attributeSet, stream,
1941                                      rank_type);
1942     }
1943     else if (!strcmp (search_type, "numeric"))
1944     {
1945         return rpn_search_APT_numeric (zh, zapt, termz, attributeSet, stream,
1946                                        reg_id, complete_flag, rank_type,
1947                                        num_bases, basenames);
1948     }
1949     zh->errCode = 118;
1950     return NULL;
1951 }
1952
1953 static RSET rpn_search_structure (ZebraHandle zh, Z_RPNStructure *zs,
1954                                   oid_value attributeSet, NMEM stream,
1955                                   Z_SortKeySpecList *sort_sequence,
1956                                   int num_bases, char **basenames)
1957 {
1958     RSET r = NULL;
1959     if (zs->which == Z_RPNStructure_complex)
1960     {
1961         Z_Operator *zop = zs->u.complex->roperator;
1962         rset_bool_parms bool_parms;
1963
1964         bool_parms.rset_l = rpn_search_structure (zh, zs->u.complex->s1,
1965                                                   attributeSet, stream,
1966                                                   sort_sequence,
1967                                                   num_bases, basenames);
1968         if (bool_parms.rset_l == NULL)
1969             return NULL;
1970         bool_parms.rset_r = rpn_search_structure (zh, zs->u.complex->s2,
1971                                                   attributeSet, stream,
1972                                                   sort_sequence,
1973                                                   num_bases, basenames);
1974         if (bool_parms.rset_r == NULL)
1975         {
1976             rset_delete (bool_parms.rset_l);
1977             return NULL;
1978         }
1979         bool_parms.key_size = sizeof(struct it_key);
1980         bool_parms.cmp = key_compare_it;
1981
1982         switch (zop->which)
1983         {
1984         case Z_Operator_and:
1985             r = rset_create (rset_kind_and, &bool_parms);
1986             break;
1987         case Z_Operator_or:
1988             r = rset_create (rset_kind_or, &bool_parms);
1989             break;
1990         case Z_Operator_and_not:
1991             r = rset_create (rset_kind_not, &bool_parms);
1992             break;
1993         case Z_Operator_prox:
1994 #ifdef ASN_COMPILED
1995             if (zop->u.prox->which != Z_ProximityOperator_known)
1996             {
1997                 zh->errCode = 132;
1998                 return NULL;
1999             }
2000 #else
2001             if (zop->u.prox->which != Z_ProxCode_known)
2002             {
2003                 zh->errCode = 132;
2004                 return NULL;
2005             }
2006 #endif
2007
2008 #ifdef ASN_COMPILED
2009             if (*zop->u.prox->u.known != Z_ProxUnit_word)
2010             {
2011                 char *val = (char *) nmem_malloc (stream, 16);
2012                 zh->errCode = 132;
2013                 zh->errString = val;
2014                 sprintf (val, "%d", *zop->u.prox->u.known);
2015                 return NULL;
2016             }
2017 #else
2018             if (*zop->u.prox->proximityUnitCode != Z_ProxUnit_word)
2019             {
2020                 char *val = (char *) nmem_malloc (stream, 16);
2021                 zh->errCode = 132;
2022                 zh->errString = val;
2023                 sprintf (val, "%d", *zop->u.prox->proximityUnitCode);
2024                 return NULL;
2025             }
2026 #endif
2027             else
2028             {
2029                 RSET rsets[2];
2030
2031                 rsets[0] = bool_parms.rset_l;
2032                 rsets[1] = bool_parms.rset_r;
2033                 
2034                 r = rpn_prox (zh, rsets, 2, 
2035                               *zop->u.prox->ordered,
2036                               (!zop->u.prox->exclusion ? 0 :
2037                                *zop->u.prox->exclusion),
2038                               *zop->u.prox->relationType,
2039                               *zop->u.prox->distance);
2040                 rset_delete (rsets[0]);
2041                 rset_delete (rsets[1]);
2042             }
2043             break;
2044         default:
2045             zh->errCode = 110;
2046             return NULL;
2047         }
2048     }
2049     else if (zs->which == Z_RPNStructure_simple)
2050     {
2051         if (zs->u.simple->which == Z_Operand_APT)
2052         {
2053             logf (LOG_DEBUG, "rpn_search_APT");
2054             r = rpn_search_APT (zh, zs->u.simple->u.attributesPlusTerm,
2055                                 attributeSet, stream, sort_sequence,
2056                                 num_bases, basenames);
2057         }
2058         else if (zs->u.simple->which == Z_Operand_resultSetId)
2059         {
2060             logf (LOG_DEBUG, "rpn_search_ref");
2061             r = resultSetRef (zh, zs->u.simple->u.resultSetId);
2062             if (!r)
2063             {
2064                 r = rset_create (rset_kind_null, NULL);
2065                 zh->errCode = 30;
2066                 zh->errString =
2067                     nmem_strdup (stream, zs->u.simple->u.resultSetId);
2068                 return 0;
2069             }
2070         }
2071         else
2072         {
2073             zh->errCode = 3;
2074             return 0;
2075         }
2076     }
2077     else
2078     {
2079         zh->errCode = 3;
2080         return 0;
2081     }
2082     return r;
2083 }
2084
2085
2086 RSET rpn_search (ZebraHandle zh, NMEM nmem,
2087                  Z_RPNQuery *rpn, int num_bases, char **basenames, 
2088                  const char *setname,
2089                  ZebraSet sset)
2090 {
2091     RSET rset;
2092     oident *attrset;
2093     oid_value attributeSet;
2094     Z_SortKeySpecList *sort_sequence;
2095     int sort_status, i;
2096
2097     zh->errCode = 0;
2098     zh->errString = NULL;
2099     zh->hits = 0;
2100
2101     sort_sequence = (Z_SortKeySpecList *)
2102         nmem_malloc (nmem, sizeof(*sort_sequence));
2103     sort_sequence->num_specs = 10;
2104     sort_sequence->specs = (Z_SortKeySpec **)
2105         nmem_malloc (nmem, sort_sequence->num_specs *
2106                      sizeof(*sort_sequence->specs));
2107     for (i = 0; i<sort_sequence->num_specs; i++)
2108         sort_sequence->specs[i] = 0;
2109     
2110     attrset = oid_getentbyoid (rpn->attributeSetId);
2111     attributeSet = attrset->value;
2112     rset = rpn_search_structure (zh, rpn->RPNStructure, attributeSet,
2113                                  nmem, sort_sequence, num_bases, basenames);
2114     if (!rset)
2115         return 0;
2116
2117     if (zh->errCode)
2118         logf (LOG_DEBUG, "search error: %d", zh->errCode);
2119     
2120     for (i = 0; sort_sequence->specs[i]; i++)
2121         ;
2122     sort_sequence->num_specs = i;
2123     if (!i)
2124         resultSetRank (zh, sset, rset);
2125     else
2126     {
2127         logf (LOG_DEBUG, "resultSetSortSingle in rpn_search");
2128         resultSetSortSingle (zh, nmem, sset, rset,
2129                              sort_sequence, &sort_status);
2130         if (zh->errCode)
2131         {
2132             logf (LOG_DEBUG, "resultSetSortSingle status = %d", zh->errCode);
2133         }
2134     }
2135     return rset;
2136 }
2137
2138 struct scan_info_entry {
2139     char *term;
2140     ISAMS_P isam_p;
2141 };
2142
2143 struct scan_info {
2144     struct scan_info_entry *list;
2145     ODR odr;
2146     int before, after;
2147     char prefix[20];
2148 };
2149
2150 static int scan_handle (char *name, const char *info, int pos, void *client)
2151 {
2152     int len_prefix, idx;
2153     struct scan_info *scan_info = (struct scan_info *) client;
2154
2155     len_prefix = strlen(scan_info->prefix);
2156     if (memcmp (name, scan_info->prefix, len_prefix))
2157         return 1;
2158     if (pos > 0)        idx = scan_info->after - pos + scan_info->before;
2159     else
2160         idx = - pos - 1;
2161     scan_info->list[idx].term = (char *)
2162         odr_malloc (scan_info->odr, strlen(name + len_prefix)+1);
2163     strcpy (scan_info->list[idx].term, name + len_prefix);
2164     assert (*info == sizeof(ISAMS_P));
2165     memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAMS_P));
2166     return 0;
2167 }
2168
2169 static void scan_term_untrans (ZebraHandle zh, NMEM stream, int reg_type,
2170                                char **dst, const char *src)
2171 {
2172     char term_dst[1024];
2173     
2174     term_untrans (zh, reg_type, term_dst, src);
2175     
2176     *dst = (char *) nmem_malloc (stream, strlen(term_dst)+1);
2177     strcpy (*dst, term_dst);
2178 }
2179
2180 static void count_set (RSET r, int *count)
2181 {
2182     int psysno = 0;
2183     int kno = 0;
2184     struct it_key key;
2185     RSFD rfd;
2186     int term_index;
2187
2188     logf (LOG_DEBUG, "count_set");
2189
2190     *count = 0;
2191     rfd = rset_open (r, RSETF_READ);
2192     while (rset_read (r, rfd, &key, &term_index))
2193     {
2194         if (key.sysno != psysno)
2195         {
2196             psysno = key.sysno;
2197             (*count)++;
2198         }
2199         kno++;
2200     }
2201     rset_close (r, rfd);
2202     logf (LOG_DEBUG, "%d keys, %d records", kno, *count);
2203 }
2204
2205 void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
2206                oid_value attributeset,
2207                int num_bases, char **basenames,
2208                int *position, int *num_entries, ZebraScanEntry **list,
2209                int *is_partial)
2210 {
2211     int i;
2212     int pos = *position;
2213     int num = *num_entries;
2214     int before;
2215     int after;
2216     int base_no;
2217     char termz[IT_MAX_WORD+20];
2218     AttrType use;
2219     int use_value;
2220     struct scan_info *scan_info_array;
2221     ZebraScanEntry *glist;
2222     int ords[32], ord_no = 0;
2223     int ptr[32];
2224
2225     unsigned reg_id;
2226     char *search_type = NULL;
2227     char rank_type[128];
2228     int complete_flag;
2229     int sort_flag;
2230     *list = 0;
2231
2232     if (attributeset == VAL_NONE)
2233         attributeset = VAL_BIB1;
2234
2235     yaz_log (LOG_DEBUG, "position = %d, num = %d set=%d",
2236              pos, num, attributeset);
2237         
2238     attr_init (&use, zapt, 1);
2239     use_value = attr_find (&use, &attributeset);
2240
2241     if (zebra_maps_attr (zh->service->zebra_maps, zapt, &reg_id, &search_type,
2242                          rank_type, &complete_flag, &sort_flag))
2243     {
2244         *num_entries = 0;
2245         zh->errCode = 113;
2246         return ;
2247     }
2248     yaz_log (LOG_DEBUG, "use_value = %d", use_value);
2249
2250     if (use_value == -1)
2251         use_value = 1016;
2252     for (base_no = 0; base_no < num_bases && ord_no < 32; base_no++)
2253     {
2254         int r;
2255         attent attp;
2256         data1_local_attribute *local_attr;
2257
2258         if ((r=att_getentbyatt (zh, &attp, attributeset, use_value)))
2259         {
2260             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d",
2261                   attributeset, use_value);
2262             if (r == -1)
2263                 zh->errCode = 114;
2264             else
2265                 zh->errCode = 121;
2266             *num_entries = 0;
2267             return;
2268         }
2269         if (zebraExplain_curDatabase (zh->service->zei, basenames[base_no]))
2270         {
2271             zh->errString = basenames[base_no];
2272             zh->errCode = 109; /* Database unavailable */
2273             *num_entries = 0;
2274             return;
2275         }
2276         for (local_attr = attp.local_attributes; local_attr && ord_no < 32;
2277              local_attr = local_attr->next)
2278         {
2279             int ord;
2280
2281             ord = zebraExplain_lookupSU (zh->service->zei, attp.attset_ordinal,
2282                                          local_attr->local);
2283             if (ord > 0)
2284                 ords[ord_no++] = ord;
2285         }
2286     }
2287     if (ord_no == 0)
2288     {
2289         *num_entries = 0;
2290         zh->errCode = 113;
2291         return;
2292     }
2293     /* prepare dictionary scanning */
2294     before = pos-1;
2295     after = 1+num-pos;
2296     scan_info_array = (struct scan_info *)
2297         odr_malloc (stream, ord_no * sizeof(*scan_info_array));
2298     for (i = 0; i < ord_no; i++)
2299     {
2300         int j, prefix_len = 0;
2301         int before_tmp = before, after_tmp = after;
2302         struct scan_info *scan_info = scan_info_array + i;
2303         struct rpn_char_map_info rcmi;
2304
2305         rpn_char_map_prepare (zh, reg_id, &rcmi);
2306
2307         scan_info->before = before;
2308         scan_info->after = after;
2309         scan_info->odr = stream;
2310
2311         scan_info->list = (struct scan_info_entry *)
2312             odr_malloc (stream, (before+after) * sizeof(*scan_info->list));
2313         for (j = 0; j<before+after; j++)
2314             scan_info->list[j].term = NULL;
2315
2316         prefix_len += key_SU_encode (ords[i], termz + prefix_len);
2317         termz[prefix_len++] = reg_id;
2318         termz[prefix_len] = 0;
2319         strcpy (scan_info->prefix, termz);
2320
2321         trans_scan_term (zh, zapt, termz+prefix_len, reg_id);
2322                     
2323         dict_scan (zh->service->dict, termz, &before_tmp, &after_tmp,
2324                    scan_info, scan_handle);
2325     }
2326     glist = (ZebraScanEntry *)
2327         odr_malloc (stream, (before+after)*sizeof(*glist));
2328
2329     /* consider terms after main term */
2330     for (i = 0; i < ord_no; i++)
2331         ptr[i] = before;
2332     
2333     *is_partial = 0;
2334     for (i = 0; i<after; i++)
2335     {
2336         int j, j0 = -1;
2337         const char *mterm = NULL;
2338         const char *tst;
2339         RSET rset;
2340         
2341         for (j = 0; j < ord_no; j++)
2342         {
2343             if (ptr[j] < before+after &&
2344                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2345                 (!mterm || strcmp (tst, mterm) < 0))
2346             {
2347                 j0 = j;
2348                 mterm = tst;
2349             }
2350         }
2351         if (j0 == -1)
2352             break;
2353         scan_term_untrans (zh, stream->mem, reg_id,
2354                            &glist[i+before].term, mterm);
2355         rset = rset_trunc (zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
2356                            glist[i+before].term, strlen(glist[i+before].term),
2357                            NULL);
2358
2359         ptr[j0]++;
2360         for (j = j0+1; j<ord_no; j++)
2361         {
2362             if (ptr[j] < before+after &&
2363                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2364                 !strcmp (tst, mterm))
2365             {
2366                 rset_bool_parms bool_parms;
2367                 RSET rset2;
2368
2369                 rset2 =
2370                    rset_trunc (zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
2371                                glist[i+before].term,
2372                                strlen(glist[i+before].term), NULL);
2373
2374                 bool_parms.key_size = sizeof(struct it_key);
2375                 bool_parms.cmp = key_compare_it;
2376                 bool_parms.rset_l = rset;
2377                 bool_parms.rset_r = rset2;
2378               
2379                 rset = rset_create (rset_kind_or, &bool_parms);
2380
2381                 ptr[j]++;
2382             }
2383         }
2384         count_set (rset, &glist[i+before].occurrences);
2385         rset_delete (rset);
2386     }
2387     if (i < after)
2388     {
2389         *num_entries -= (after-i);
2390         *is_partial = 1;
2391     }
2392
2393     /* consider terms before main term */
2394     for (i = 0; i<ord_no; i++)
2395         ptr[i] = 0;
2396
2397     for (i = 0; i<before; i++)
2398     {
2399         int j, j0 = -1;
2400         const char *mterm = NULL;
2401         const char *tst;
2402         RSET rset;
2403         
2404         for (j = 0; j <ord_no; j++)
2405         {
2406             if (ptr[j] < before &&
2407                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2408                 (!mterm || strcmp (tst, mterm) > 0))
2409             {
2410                 j0 = j;
2411                 mterm = tst;
2412             }
2413         }
2414         if (j0 == -1)
2415             break;
2416
2417         scan_term_untrans (zh, stream->mem, reg_id,
2418                            &glist[before-1-i].term, mterm);
2419
2420         rset = rset_trunc
2421                (zh, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1,
2422                 glist[before-1-i].term, strlen(glist[before-1-i].term),
2423                 NULL);
2424
2425         ptr[j0]++;
2426
2427         for (j = j0+1; j<ord_no; j++)
2428         {
2429             if (ptr[j] < before &&
2430                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2431                 !strcmp (tst, mterm))
2432             {
2433                 rset_bool_parms bool_parms;
2434                 RSET rset2;
2435
2436                 rset2 = rset_trunc (zh,
2437                          &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1,
2438                                     glist[before-1-i].term,
2439                                     strlen(glist[before-1-i].term), NULL);
2440
2441                 bool_parms.key_size = sizeof(struct it_key);
2442                 bool_parms.cmp = key_compare_it;
2443                 bool_parms.rset_l = rset;
2444                 bool_parms.rset_r = rset2;
2445               
2446                 rset = rset_create (rset_kind_or, &bool_parms);
2447
2448                 ptr[j]++;
2449             }
2450         }
2451         count_set (rset, &glist[before-1-i].occurrences);
2452         rset_delete (rset);
2453     }
2454     i = before-i;
2455     if (i)
2456     {
2457         *is_partial = 1;
2458         *position -= i;
2459         *num_entries -= i;
2460     }
2461     *list = glist + i;               /* list is set to first 'real' entry */
2462     
2463     logf (LOG_DEBUG, "position = %d, num_entries = %d",
2464           *position, *num_entries);
2465     if (zh->errCode)
2466         logf (LOG_DEBUG, "scan error: %d", zh->errCode);
2467 }
2468