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