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