More XPATH work; common sequence numbers for extract keys
[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.115 2002-04-13 18:16:43 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                     char val_str[32];
895                     sprintf (val_str, "%d", use_value);
896                     zh->errCode = 114;
897                     zh->errString = nmem_strdup (stream, val_str);
898                 }
899                 else
900                 {
901                     int oid[OID_SIZE];
902                     struct oident oident;
903                     
904                     oident.proto = PROTO_Z3950;
905                     oident.oclass = CLASS_ATTSET;
906                     oident.value = curAttributeSet;
907                     oid_ent_to_oid (&oident, oid);
908                     
909                     zh->errCode = 121;
910                     zh->errString = nmem_strdup (stream, oident.desc);
911                 }
912                 return -1;
913             }
914         }
915         for (local_attr = attp.local_attributes; local_attr;
916              local_attr = local_attr->next)
917         {
918             int ord;
919             char ord_buf[32];
920             int i, ord_len;
921             
922             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
923                                          local_attr->local);
924             if (ord < 0)
925                 continue;
926             if (prefix_len)
927                 term_dict[prefix_len++] = '|';
928             else
929                 term_dict[prefix_len++] = '(';
930             
931             ord_len = key_SU_encode (ord, ord_buf);
932             for (i = 0; i<ord_len; i++)
933             {
934                 term_dict[prefix_len++] = 1;
935                 term_dict[prefix_len++] = ord_buf[i];
936             }
937         }
938         if (!prefix_len)
939         {
940             char val_str[32];
941             sprintf (val_str, "%d", use_value);
942             zh->errCode = 114;
943             zh->errString = nmem_strdup (stream, val_str);
944             return -1;
945         }
946         term_dict[prefix_len++] = ')';
947         term_dict[prefix_len++] = 1;
948         term_dict[prefix_len++] = reg_type;
949         logf (LOG_DEBUG, "reg_type = %d", term_dict[prefix_len-1]);
950         term_dict[prefix_len] = '\0';
951         j = prefix_len;
952         switch (truncation_value)
953         {
954         case -1:         /* not specified */
955         case 100:        /* do not truncate */
956             if (!string_relation (zh, zapt, &termp, term_dict,
957                                   attributeSet,
958                                   reg_type, space_split, term_dst))
959                 return 0;
960             logf (LOG_DEBUG, "dict_lookup_grep: %s", term_dict+prefix_len);
961             r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
962                                   grep_info, &max_pos, 0, grep_handle);
963             if (r)
964                 logf (LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
965             break;
966         case 1:          /* right truncation */
967             term_dict[j++] = '(';
968             if (!term_100 (zh->reg->zebra_maps, reg_type,
969                            &termp, term_dict + j, space_split, term_dst))
970                 return 0;
971             strcat (term_dict, ".*)");
972             dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
973                               &max_pos, 0, grep_handle);
974             break;
975         case 2:          /* keft truncation */
976             term_dict[j++] = '('; term_dict[j++] = '.'; term_dict[j++] = '*';
977             if (!term_100 (zh->reg->zebra_maps, reg_type,
978                            &termp, term_dict + j, space_split, term_dst))
979                 return 0;
980             strcat (term_dict, ")");
981             dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
982                               &max_pos, 0, grep_handle);
983             break;
984         case 3:          /* left&right truncation */
985             term_dict[j++] = '('; term_dict[j++] = '.'; term_dict[j++] = '*';
986             if (!term_100 (zh->reg->zebra_maps, reg_type,
987                            &termp, term_dict + j, space_split, term_dst))
988                 return 0;
989             strcat (term_dict, ".*)");
990             dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
991                               &max_pos, 0, grep_handle);
992             break;
993             zh->errCode = 120;
994             return -1;
995         case 101:        /* process # in term */
996             term_dict[j++] = '(';
997             if (!term_101 (zh->reg->zebra_maps, reg_type,
998                            &termp, term_dict + j, space_split, term_dst))
999                 return 0;
1000             strcat (term_dict, ")");
1001             r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
1002                                   &max_pos, 0, grep_handle);
1003             if (r)
1004                 logf (LOG_WARN, "dict_lookup_grep err, trunc=#: %d", r);
1005             break;
1006         case 102:        /* Regexp-1 */
1007             term_dict[j++] = '(';
1008             if (!term_102 (zh->reg->zebra_maps, reg_type,
1009                            &termp, term_dict + j, space_split, term_dst))
1010                 return 0;
1011             strcat (term_dict, ")");
1012             logf (LOG_DEBUG, "Regexp-1 tolerance=%d", r);
1013             r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
1014                                   &max_pos, 0, grep_handle);
1015             if (r)
1016                 logf (LOG_WARN, "dict_lookup_grep err, trunc=regular: %d",
1017                       r);
1018             break;
1019         case 103:       /* Regexp-2 */
1020             r = 1;
1021             term_dict[j++] = '(';
1022             if (!term_103 (zh->reg->zebra_maps, reg_type,
1023                            &termp, term_dict + j, &r, space_split, term_dst))
1024                 return 0;
1025             strcat (term_dict, ")");
1026             logf (LOG_DEBUG, "Regexp-2 tolerance=%d", r);
1027             r = dict_lookup_grep (zh->reg->dict, term_dict, r, grep_info,
1028                                   &max_pos, 2, grep_handle);
1029             if (r)
1030                 logf (LOG_WARN, "dict_lookup_grep err, trunc=eregular: %d",
1031                       r);
1032             break;
1033         case 104:        /* process # and ! in term */
1034             term_dict[j++] = '(';
1035             if (!term_104 (zh->reg->zebra_maps, reg_type,
1036                            &termp, term_dict + j, space_split, term_dst))
1037                 return 0;
1038             strcat (term_dict, ")");
1039             r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
1040                                   &max_pos, 0, grep_handle);
1041             if (r)
1042                 logf (LOG_WARN, "dict_lookup_grep err, trunc=#/!: %d", r);
1043             break;
1044         case 105:        /* process * and ! in term */
1045             term_dict[j++] = '(';
1046             if (!term_105 (zh->reg->zebra_maps, reg_type,
1047                            &termp, term_dict + j, space_split, term_dst, 1))
1048                 return 0;
1049             strcat (term_dict, ")");
1050             r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
1051                                   &max_pos, 0, grep_handle);
1052             if (r)
1053                 logf (LOG_WARN, "dict_lookup_grep err, trunc=*/!: %d", r);
1054             break;
1055         case 106:        /* process * and ! in term */
1056             term_dict[j++] = '(';
1057             if (!term_105 (zh->reg->zebra_maps, reg_type,
1058                            &termp, term_dict + j, space_split, term_dst, 0))
1059                 return 0;
1060             strcat (term_dict, ")");
1061             r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
1062                                   &max_pos, 0, grep_handle);
1063             if (r)
1064                 logf (LOG_WARN, "dict_lookup_grep err, trunc=*/!: %d", r);
1065             break;
1066         }
1067     }
1068     *term_sub = termp;
1069     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1070     return 1;
1071 }
1072
1073 static void trans_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1074                         char *termz)
1075 {
1076     size_t sizez;
1077     Z_Term *term = zapt->term;
1078
1079     sizez = term->u.general->len;
1080     if (sizez > IT_MAX_WORD-1)
1081         sizez = IT_MAX_WORD-1;
1082     memcpy (termz, term->u.general->buf, sizez);
1083     termz[sizez] = '\0';
1084 }
1085
1086 static void trans_scan_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1087                              char *termz, int reg_type)
1088 {
1089     Z_Term *term = zapt->term;
1090     const char **map;
1091     const char *cp = (const char *) term->u.general->buf;
1092     const char *cp_end = cp + term->u.general->len;
1093     const char *src;
1094     int i = 0;
1095     const char *space_map = NULL;
1096     int len;
1097     
1098     while ((len = (cp_end - cp)) > 0)
1099     {
1100         map = zebra_maps_input (zh->reg->zebra_maps, reg_type, &cp, len);
1101         if (**map == *CHR_SPACE)
1102             space_map = *map;
1103         else
1104         {
1105             if (i && space_map)
1106                 for (src = space_map; *src; src++)
1107                     termz[i++] = *src;
1108             space_map = NULL;
1109             for (src = *map; *src; src++)
1110                 termz[i++] = *src;
1111         }
1112     }
1113     termz[i] = '\0';
1114 }
1115
1116 static RSET rpn_prox (ZebraHandle zh, RSET *rset, int rset_no,
1117                       int ordered, int exclusion, int relation, int distance)
1118 {
1119     int i;
1120     RSFD *rsfd;
1121     int  *more;
1122     struct it_key **buf;
1123     RSET result;
1124     char prox_term[1024];
1125     int length_prox_term = 0;
1126     int min_nn = 10000000;
1127     int term_index;
1128     const char *flags = NULL;
1129     
1130     rsfd = (RSFD *) xmalloc (sizeof(*rsfd)*rset_no);
1131     more = (int *) xmalloc (sizeof(*more)*rset_no);
1132     buf = (struct it_key **) xmalloc (sizeof(*buf)*rset_no);
1133
1134     *prox_term = '\0';
1135     for (i = 0; i<rset_no; i++)
1136     {
1137         int j;
1138         for (j = 0; j<rset[i]->no_rset_terms; j++)
1139         {
1140             const char *nflags = rset[i]->rset_terms[j]->flags;
1141             char *term = rset[i]->rset_terms[j]->name;
1142             int lterm = strlen(term);
1143             if (lterm + length_prox_term < sizeof(prox_term)-1)
1144             {
1145                 if (length_prox_term)
1146                     prox_term[length_prox_term++] = ' ';
1147                 strcpy (prox_term + length_prox_term, term);
1148                 length_prox_term += lterm;
1149             }
1150             if (min_nn > rset[i]->rset_terms[j]->nn)
1151                 min_nn = rset[i]->rset_terms[j]->nn;
1152             flags = nflags;
1153         }
1154     }
1155     for (i = 0; i<rset_no; i++)
1156     {
1157         buf[i] = 0;
1158         rsfd[i] = 0;
1159     }
1160     for (i = 0; i<rset_no; i++)
1161     {
1162         buf[i] = (struct it_key *) xmalloc (sizeof(**buf));
1163         rsfd[i] = rset_open (rset[i], RSETF_READ);
1164         if (!(more[i] = rset_read (rset[i], rsfd[i], buf[i], &term_index)))
1165             break;
1166     }
1167     if (i != rset_no)
1168     {
1169         /* at least one is empty ... return null set */
1170         rset_null_parms parms;
1171         
1172         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1173                                             flags);
1174         parms.rset_term->nn = 0;
1175         result = rset_create (rset_kind_null, &parms);
1176     }
1177     else if (ordered && relation == 3 && exclusion == 0 && distance == 1)
1178     {
1179         /* special proximity case = phrase search ... */
1180         rset_temp_parms parms;
1181         RSFD rsfd_result;
1182
1183         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1184                                             flags);
1185         parms.rset_term->nn = min_nn;
1186         parms.cmp = key_compare_it;
1187         parms.key_size = sizeof (struct it_key);
1188         parms.temp_path = res_get (zh->res, "setTmpDir");
1189         result = rset_create (rset_kind_temp, &parms);
1190         rsfd_result = rset_open (result, RSETF_WRITE);
1191         
1192         while (*more)
1193         {
1194             for (i = 1; i<rset_no; i++)
1195             {
1196                 int cmp;
1197                 
1198                 if (!more[i])
1199                 {
1200                     *more = 0;
1201                     break;
1202                 }
1203                 cmp = key_compare_it (buf[i], buf[i-1]);
1204                 if (cmp > 1)
1205                 {
1206                     more[i-1] = rset_read (rset[i-1], rsfd[i-1],
1207                                            buf[i-1], &term_index);
1208                     break;
1209                 }
1210                 else if (cmp == 1)
1211                 {
1212                     if (buf[i-1]->seqno+1 != buf[i]->seqno)
1213                     {
1214                         more[i-1] = rset_read (rset[i-1], rsfd[i-1],
1215                                                buf[i-1], &term_index);
1216                         break;
1217                     }
1218                 }
1219                 else
1220                 {
1221                     more[i] = rset_read (rset[i], rsfd[i], buf[i],
1222                                          &term_index);
1223                     break;
1224                 }
1225             }
1226             if (i == rset_no)
1227             {
1228                 rset_write (result, rsfd_result, buf[0]);
1229                 more[0] = rset_read (*rset, *rsfd, *buf, &term_index);
1230             }
1231         }
1232         rset_close (result, rsfd_result);
1233     }
1234     else if (rset_no == 2)
1235     {
1236         /* generic proximity case (two input sets only) ... */
1237         rset_temp_parms parms;
1238         RSFD rsfd_result;
1239
1240         logf (LOG_LOG, "generic prox, dist = %d, relation = %d, ordered =%d, exclusion=%d",
1241               distance, relation, ordered, exclusion);
1242         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1243                                             flags);
1244         parms.rset_term->nn = min_nn;
1245         parms.cmp = key_compare_it;
1246         parms.key_size = sizeof (struct it_key);
1247         parms.temp_path = res_get (zh->res, "setTmpDir");
1248         result = rset_create (rset_kind_temp, &parms);
1249         rsfd_result = rset_open (result, RSETF_WRITE);
1250
1251         while (more[0] && more[1]) 
1252         {
1253             int cmp = key_compare_it (buf[0], buf[1]);
1254             if (cmp < -1)
1255                 more[0] = rset_read (rset[0], rsfd[0], buf[0], &term_index);
1256             else if (cmp > 1)
1257                 more[1] = rset_read (rset[1], rsfd[1], buf[1], &term_index);
1258             else
1259             {
1260                 int sysno = buf[0]->sysno;
1261                 int seqno[500];
1262                 int n = 0;
1263                 
1264                 seqno[n++] = buf[0]->seqno;
1265                 while ((more[0] = rset_read (rset[0], rsfd[0], buf[0],
1266                                              &term_index)) &&
1267                        sysno == buf[0]->sysno)
1268                     if (n < 500)
1269                         seqno[n++] = buf[0]->seqno;
1270                 do
1271                 {
1272                     for (i = 0; i<n; i++)
1273                     {
1274                         int diff = buf[1]->seqno - seqno[i];
1275                         int excl = exclusion;
1276                         if (!ordered && diff < 0)
1277                             diff = -diff;
1278                         switch (relation)
1279                         {
1280                         case 1:      /* < */
1281                             if (diff < distance && diff >= 0)
1282                                 excl = !excl;
1283                             break;
1284                         case 2:      /* <= */
1285                             if (diff <= distance && diff >= 0)
1286                                 excl = !excl;
1287                             break;
1288                         case 3:      /* == */
1289                             if (diff == distance && diff >= 0)
1290                                 excl = !excl;
1291                             break;
1292                         case 4:      /* >= */
1293                             if (diff >= distance && diff >= 0)
1294                                 excl = !excl;
1295                             break;
1296                         case 5:      /* > */
1297                             if (diff > distance && diff >= 0)
1298                                 excl = !excl;
1299                             break;
1300                         case 6:      /* != */
1301                             if (diff != distance && diff >= 0)
1302                                 excl = !excl;
1303                             break;
1304                         }
1305                         if (excl)
1306                         {
1307                             rset_write (result, rsfd_result, buf[1]);
1308                             break;
1309                         }
1310                     }
1311                 } while ((more[1] = rset_read (rset[1], rsfd[1], buf[1],
1312                                                &term_index)) &&
1313                          sysno == buf[1]->sysno);
1314             }
1315         }
1316         rset_close (result, rsfd_result);
1317     }
1318     else
1319     {
1320         rset_null_parms parms;
1321         
1322         parms.rset_term = rset_term_create (prox_term, length_prox_term,
1323                                             flags);
1324         parms.rset_term->nn = 0;
1325         result = rset_create (rset_kind_null, &parms);
1326     }
1327     for (i = 0; i<rset_no; i++)
1328     {
1329         if (rsfd[i])
1330             rset_close (rset[i], rsfd[i]);
1331         xfree (buf[i]);
1332     }
1333     xfree (buf);
1334     xfree (more);
1335     xfree (rsfd);
1336     return result;
1337 }
1338
1339
1340 char *normalize_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1341                      const char *termz, NMEM stream, unsigned reg_id)
1342 {
1343     WRBUF wrbuf = 0;
1344     AttrType truncation;
1345     int truncation_value;
1346     char *ex_list = 0;
1347
1348     attr_init (&truncation, zapt, 5);
1349     truncation_value = attr_find (&truncation, NULL);
1350
1351     switch (truncation_value)
1352     {
1353     default:
1354         ex_list = "";
1355         break;
1356     case 101:
1357         ex_list = "#";
1358         break;
1359     case 102:
1360     case 103:
1361         ex_list = 0;
1362         break;
1363     case 104:
1364         ex_list = "!#";
1365         break;
1366     case 105:
1367         ex_list = "!*";
1368         break;
1369     }
1370     if (ex_list)
1371         wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, ex_list,
1372                               termz, strlen(termz));
1373     if (!wrbuf)
1374         return nmem_strdup(stream, termz);
1375     else
1376     {
1377         char *buf = (char*) nmem_malloc (stream, wrbuf_len(wrbuf)+1);
1378         memcpy (buf, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
1379         buf[wrbuf_len(wrbuf)] = '\0';
1380         return buf;
1381     }
1382 }
1383
1384 static void grep_info_delete (struct grep_info *grep_info)
1385 {
1386 #ifdef TERM_COUNT
1387     xfree(grep_info->term_no);
1388 #endif
1389     xfree (grep_info->isam_p_buf);
1390 }
1391
1392 static int grep_info_prepare (ZebraHandle zh,
1393                               Z_AttributesPlusTerm *zapt,
1394                               struct grep_info *grep_info,
1395                               int reg_type,
1396                               NMEM stream)
1397 {
1398     AttrType termset;
1399     int termset_value_numeric;
1400     const char *termset_value_string;
1401
1402 #ifdef TERM_COUNT
1403     grep_info->term_no = 0;
1404 #endif
1405     grep_info->isam_p_size = 0;
1406     grep_info->isam_p_buf = NULL;
1407     grep_info->zh = zh;
1408     grep_info->reg_type = reg_type;
1409     grep_info->termset = 0;
1410
1411     attr_init (&termset, zapt, 8);
1412     termset_value_numeric =
1413         attr_find_ex (&termset, NULL, &termset_value_string);
1414     if (termset_value_numeric != -1)
1415     {
1416         char resname[32];
1417         const char *termset_name = 0;
1418         if (termset_value_numeric != -2)
1419         {
1420     
1421             sprintf (resname, "%d", termset_value_numeric);
1422             termset_name = resname;
1423         }
1424         else
1425             termset_name = termset_value_string;
1426         logf (LOG_LOG, "creating termset set %s", termset_name);
1427         grep_info->termset = resultSetAdd (zh, termset_name, 1);
1428         if (!grep_info->termset)
1429         {
1430             zh->errCode = 128;
1431             zh->errString = nmem_strdup (stream, termset_name);
1432             return -1;
1433         }
1434     }
1435     return 0;
1436 }
1437                                
1438
1439 static RSET rpn_search_APT_phrase (ZebraHandle zh,
1440                                    Z_AttributesPlusTerm *zapt,
1441                                    const char *termz_org,
1442                                    oid_value attributeSet,
1443                                    NMEM stream,
1444                                    int reg_type, int complete_flag,
1445                                    const char *rank_type,
1446                                    int num_bases, char **basenames)
1447 {
1448     char term_dst[IT_MAX_WORD+1];
1449     RSET rset[60], result;
1450     int i, rset_no = 0;
1451     struct grep_info grep_info;
1452     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1453     const char *termp = termz;
1454
1455     *term_dst = 0;
1456     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1457         return 0;
1458     while (1)
1459     { 
1460         logf (LOG_DEBUG, "APT_phrase termp=%s", termp);
1461         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1462                                     stream, &grep_info,
1463                                     reg_type, complete_flag,
1464                                     num_bases, basenames,
1465                                     term_dst, rank_type);
1466         if (!rset[rset_no])
1467             break;
1468         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1469             break;
1470     }
1471     grep_info_delete (&grep_info);
1472     if (rset_no == 0)
1473     {
1474         rset_null_parms parms;
1475         
1476         parms.rset_term = rset_term_create (termz, -1, rank_type);
1477         return rset_create (rset_kind_null, &parms);
1478     }
1479     else if (rset_no == 1)
1480         return (rset[0]);
1481     result = rpn_prox (zh, rset, rset_no, 1, 0, 3, 1);
1482     for (i = 0; i<rset_no; i++)
1483         rset_delete (rset[i]);
1484     return result;
1485 }
1486
1487 static RSET rpn_search_APT_or_list (ZebraHandle zh,
1488                                     Z_AttributesPlusTerm *zapt,
1489                                     const char *termz_org,
1490                                     oid_value attributeSet,
1491                                     NMEM stream,
1492                                     int reg_type, int complete_flag,
1493                                     const char *rank_type,
1494                                     int num_bases, char **basenames)
1495 {
1496     char term_dst[IT_MAX_WORD+1];
1497     RSET rset[60], result;
1498     int i, rset_no = 0;
1499     struct grep_info grep_info;
1500     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1501     const char *termp = termz;
1502
1503     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1504         return 0;
1505     while (1)
1506     { 
1507         logf (LOG_DEBUG, "APT_or_list termp=%s", termp);
1508         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1509                                     stream, &grep_info,
1510                                     reg_type, complete_flag,
1511                                     num_bases, basenames,
1512                                     term_dst, rank_type);
1513         if (!rset[rset_no])
1514             break;
1515         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1516             break;
1517     }
1518     grep_info_delete (&grep_info);
1519     if (rset_no == 0)
1520     {
1521         rset_null_parms parms;
1522         
1523         parms.rset_term = rset_term_create (termz, -1, rank_type);
1524         return rset_create (rset_kind_null, &parms);
1525     }
1526     result = rset[0];
1527     for (i = 1; i<rset_no; i++)
1528     {
1529         rset_bool_parms bool_parms;
1530
1531         bool_parms.rset_l = result;
1532         bool_parms.rset_r = rset[i];
1533         bool_parms.key_size = sizeof(struct it_key);
1534         bool_parms.cmp = key_compare_it;
1535         result = rset_create (rset_kind_or, &bool_parms);
1536     }
1537     return result;
1538 }
1539
1540 static RSET rpn_search_APT_and_list (ZebraHandle zh,
1541                                      Z_AttributesPlusTerm *zapt,
1542                                      const char *termz_org,
1543                                      oid_value attributeSet,
1544                                      NMEM stream,
1545                                      int reg_type, int complete_flag,
1546                                      const char *rank_type,
1547                                      int num_bases, char **basenames)
1548 {
1549     char term_dst[IT_MAX_WORD+1];
1550     RSET rset[60], result;
1551     int i, rset_no = 0;
1552     struct grep_info grep_info;
1553     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
1554     const char *termp = termz;
1555
1556     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1557         return 0;
1558     while (1)
1559     { 
1560         logf (LOG_DEBUG, "APT_and_list termp=%s", termp);
1561         rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
1562                                     stream, &grep_info,
1563                                     reg_type, complete_flag,
1564                                     num_bases, basenames,
1565                                     term_dst, rank_type);
1566         if (!rset[rset_no])
1567             break;
1568         assert (rset[rset_no]);
1569         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1570             break;
1571     }
1572     grep_info_delete (&grep_info);
1573     if (rset_no == 0)
1574     {
1575         rset_null_parms parms;
1576         
1577         parms.rset_term = rset_term_create (termz, -1, rank_type);
1578         return rset_create (rset_kind_null, &parms);
1579     }
1580     result = rset[0];
1581     for (i = 1; i<rset_no; i++)
1582     {
1583         rset_bool_parms bool_parms;
1584
1585         bool_parms.rset_l = result;
1586         bool_parms.rset_r = rset[i];
1587         bool_parms.key_size = sizeof(struct it_key);
1588         bool_parms.cmp = key_compare_it;
1589         result = rset_create (rset_kind_and, &bool_parms);
1590     }
1591     return result;
1592 }
1593
1594 static int numeric_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1595                              const char **term_sub,
1596                              char *term_dict,
1597                              oid_value attributeSet,
1598                              struct grep_info *grep_info,
1599                              int *max_pos,
1600                              int reg_type,
1601                              char *term_dst)
1602 {
1603     AttrType relation;
1604     int relation_value;
1605     int term_value;
1606     int r;
1607     char *term_tmp = term_dict + strlen(term_dict);
1608
1609     attr_init (&relation, zapt, 2);
1610     relation_value = attr_find (&relation, NULL);
1611
1612     logf (LOG_DEBUG, "numeric relation value=%d", relation_value);
1613
1614     if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub, term_tmp, 1,
1615                    term_dst))
1616         return 0;
1617     term_value = atoi (term_tmp);
1618     switch (relation_value)
1619     {
1620     case 1:
1621         logf (LOG_DEBUG, "Relation <");
1622         gen_regular_rel (term_tmp, term_value-1, 1);
1623         break;
1624     case 2:
1625         logf (LOG_DEBUG, "Relation <=");
1626         gen_regular_rel (term_tmp, term_value, 1);
1627         break;
1628     case 4:
1629         logf (LOG_DEBUG, "Relation >=");
1630         gen_regular_rel (term_tmp, term_value, 0);
1631         break;
1632     case 5:
1633         logf (LOG_DEBUG, "Relation >");
1634         gen_regular_rel (term_tmp, term_value+1, 0);
1635         break;
1636     case 3:
1637     default:
1638         logf (LOG_DEBUG, "Relation =");
1639         sprintf (term_tmp, "(0*%d)", term_value);
1640     }
1641     logf (LOG_DEBUG, "dict_lookup_grep: %s", term_tmp);
1642     r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info, max_pos,
1643                           0, grep_handle);
1644     if (r)
1645         logf (LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
1646     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1647     return 1;
1648 }
1649
1650 static int numeric_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1651                          const char **term_sub, 
1652                          oid_value attributeSet, struct grep_info *grep_info,
1653                          int reg_type, int complete_flag,
1654                          int num_bases, char **basenames,
1655                          char *term_dst)
1656 {
1657     char term_dict[2*IT_MAX_WORD+2];
1658     int r, base_no;
1659     AttrType use;
1660     int use_value;
1661     oid_value curAttributeSet = attributeSet;
1662     const char *termp;
1663     struct rpn_char_map_info rcmi;
1664
1665     rpn_char_map_prepare (zh->reg, reg_type, &rcmi);
1666     attr_init (&use, zapt, 1);
1667     use_value = attr_find (&use, &curAttributeSet);
1668     logf (LOG_DEBUG, "numeric_term, use value %d", use_value);
1669
1670     if (use_value == -1)
1671         use_value = 1016;
1672
1673     for (base_no = 0; base_no < num_bases; base_no++)
1674     {
1675         attent attp;
1676         data1_local_attribute *local_attr;
1677         int max_pos, prefix_len = 0;
1678
1679         termp = *term_sub;
1680         if ((r=att_getentbyatt (zh, &attp, curAttributeSet, use_value)))
1681         {
1682             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
1683                   curAttributeSet, use_value, r);
1684             if (r == -1)
1685                 zh->errCode = 114;
1686             else
1687                 zh->errCode = 121;
1688             return -1;
1689         }
1690         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
1691         {
1692             zh->errCode = 109; /* Database unavailable */
1693             zh->errString = basenames[base_no];
1694             return -1;
1695         }
1696         for (local_attr = attp.local_attributes; local_attr;
1697              local_attr = local_attr->next)
1698         {
1699             int ord;
1700             char ord_buf[32];
1701             int i, ord_len;
1702
1703             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
1704                                           local_attr->local);
1705             if (ord < 0)
1706                 continue;
1707             if (prefix_len)
1708                 term_dict[prefix_len++] = '|';
1709             else
1710                 term_dict[prefix_len++] = '(';
1711
1712             ord_len = key_SU_encode (ord, ord_buf);
1713             for (i = 0; i<ord_len; i++)
1714             {
1715                 term_dict[prefix_len++] = 1;
1716                 term_dict[prefix_len++] = ord_buf[i];
1717             }
1718         }
1719         if (!prefix_len)
1720         {
1721             zh->errCode = 114;
1722             return -1;
1723         }
1724         term_dict[prefix_len++] = ')';        
1725         term_dict[prefix_len++] = 1;
1726         term_dict[prefix_len++] = reg_type;
1727         logf (LOG_DEBUG, "reg_type = %d", term_dict[prefix_len-1]);
1728         term_dict[prefix_len] = '\0';
1729         if (!numeric_relation (zh, zapt, &termp, term_dict,
1730                                attributeSet, grep_info, &max_pos, reg_type,
1731                                term_dst))
1732             return 0;
1733     }
1734     *term_sub = termp;
1735     logf (LOG_DEBUG, "%d positions", grep_info->isam_p_indx);
1736     return 1;
1737 }
1738
1739 static RSET rpn_search_APT_numeric (ZebraHandle zh,
1740                                     Z_AttributesPlusTerm *zapt,
1741                                     const char *termz,
1742                                     oid_value attributeSet,
1743                                     NMEM stream,
1744                                     int reg_type, int complete_flag,
1745                                     const char *rank_type,
1746                                     int num_bases, char **basenames)
1747 {
1748     char term_dst[IT_MAX_WORD+1];
1749     const char *termp = termz;
1750     RSET rset[60], result;
1751     int i, r, rset_no = 0;
1752     struct grep_info grep_info;
1753
1754     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1755         return 0;
1756     while (1)
1757     { 
1758         logf (LOG_DEBUG, "APT_numeric termp=%s", termp);
1759         grep_info.isam_p_indx = 0;
1760         r = numeric_term (zh, zapt, &termp, attributeSet, &grep_info,
1761                           reg_type, complete_flag, num_bases, basenames,
1762                           term_dst);
1763         if (r < 1)
1764             break;
1765         logf (LOG_DEBUG, "term: %s", term_dst);
1766         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
1767                                     grep_info.isam_p_indx, term_dst,
1768                                     strlen(term_dst), rank_type,
1769                                     0 /* preserve position */);
1770         assert (rset[rset_no]);
1771         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
1772             break;
1773     }
1774     grep_info_delete (&grep_info);
1775     if (rset_no == 0)
1776     {
1777         rset_null_parms parms;
1778         
1779         parms.rset_term = rset_term_create (term_dst, -1, rank_type);
1780         return rset_create (rset_kind_null, &parms);
1781     }
1782     result = rset[0];
1783     for (i = 1; i<rset_no; i++)
1784     {
1785         rset_bool_parms bool_parms;
1786
1787         bool_parms.rset_l = result;
1788         bool_parms.rset_r = rset[i];
1789         bool_parms.key_size = sizeof(struct it_key);
1790         bool_parms.cmp = key_compare_it;
1791         result = rset_create (rset_kind_and, &bool_parms);
1792     }
1793     return result;
1794 }
1795
1796 static RSET rpn_search_APT_local (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1797                                   const char *termz,
1798                                   oid_value attributeSet,
1799                                   NMEM stream,
1800                                   const char *rank_type)
1801 {
1802     RSET result;
1803     RSFD rsfd;
1804     struct it_key key;
1805     rset_temp_parms parms;
1806
1807     parms.rset_term = rset_term_create (termz, -1, rank_type);
1808     parms.cmp = key_compare_it;
1809     parms.key_size = sizeof (struct it_key);
1810     parms.temp_path = res_get (zh->res, "setTmpDir");
1811     result = rset_create (rset_kind_temp, &parms);
1812     rsfd = rset_open (result, RSETF_WRITE);
1813
1814     key.sysno = atoi (termz);
1815     key.seqno = 1;
1816     if (key.sysno <= 0)
1817         key.sysno = 1;
1818     rset_write (result, rsfd, &key);
1819     rset_close (result, rsfd);
1820     return result;
1821 }
1822
1823 static RSET rpn_sort_spec (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1824                            oid_value attributeSet, NMEM stream,
1825                            Z_SortKeySpecList *sort_sequence,
1826                            const char *rank_type)
1827 {
1828     rset_null_parms parms;    
1829     int i;
1830     int sort_relation_value;
1831     AttrType sort_relation_type;
1832     int use_value;
1833     AttrType use_type;
1834     Z_SortKeySpec *sks;
1835     Z_SortKey *sk;
1836     Z_AttributeElement *ae;
1837     int oid[OID_SIZE];
1838     oident oe;
1839     char termz[20];
1840     
1841     attr_init (&sort_relation_type, zapt, 7);
1842     sort_relation_value = attr_find (&sort_relation_type, &attributeSet);
1843
1844     attr_init (&use_type, zapt, 1);
1845     use_value = attr_find (&use_type, &attributeSet);
1846
1847     if (!sort_sequence->specs)
1848     {
1849         sort_sequence->num_specs = 10;
1850         sort_sequence->specs = (Z_SortKeySpec **)
1851             nmem_malloc (stream, sort_sequence->num_specs *
1852                          sizeof(*sort_sequence->specs));
1853         for (i = 0; i<sort_sequence->num_specs; i++)
1854             sort_sequence->specs[i] = 0;
1855     }
1856     if (zapt->term->which != Z_Term_general)
1857         i = 0;
1858     else
1859         i = atoi_n ((char *) zapt->term->u.general->buf,
1860                     zapt->term->u.general->len);
1861     if (i >= sort_sequence->num_specs)
1862         i = 0;
1863     sprintf (termz, "%d", i);
1864
1865     oe.proto = PROTO_Z3950;
1866     oe.oclass = CLASS_ATTSET;
1867     oe.value = attributeSet;
1868     if (!oid_ent_to_oid (&oe, oid))
1869         return 0;
1870
1871     sks = (Z_SortKeySpec *) nmem_malloc (stream, sizeof(*sks));
1872     sks->sortElement = (Z_SortElement *)
1873         nmem_malloc (stream, sizeof(*sks->sortElement));
1874     sks->sortElement->which = Z_SortElement_generic;
1875     sk = sks->sortElement->u.generic = (Z_SortKey *)
1876         nmem_malloc (stream, sizeof(*sk));
1877     sk->which = Z_SortKey_sortAttributes;
1878     sk->u.sortAttributes = (Z_SortAttributes *)
1879         nmem_malloc (stream, sizeof(*sk->u.sortAttributes));
1880
1881     sk->u.sortAttributes->id = oid;
1882     sk->u.sortAttributes->list = (Z_AttributeList *)
1883         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list));
1884     sk->u.sortAttributes->list->num_attributes = 1;
1885     sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
1886         nmem_malloc (stream, sizeof(*sk->u.sortAttributes->list->attributes));
1887     ae = *sk->u.sortAttributes->list->attributes = (Z_AttributeElement *)
1888         nmem_malloc (stream, sizeof(**sk->u.sortAttributes->list->attributes));
1889     ae->attributeSet = 0;
1890     ae->attributeType = (int *)
1891         nmem_malloc (stream, sizeof(*ae->attributeType));
1892     *ae->attributeType = 1;
1893     ae->which = Z_AttributeValue_numeric;
1894     ae->value.numeric = (int *)
1895         nmem_malloc (stream, sizeof(*ae->value.numeric));
1896     *ae->value.numeric = use_value;
1897
1898     sks->sortRelation = (int *)
1899         nmem_malloc (stream, sizeof(*sks->sortRelation));
1900     if (sort_relation_value == 1)
1901         *sks->sortRelation = Z_SortRelation_ascending;
1902     else if (sort_relation_value == 2)
1903         *sks->sortRelation = Z_SortRelation_descending;
1904     else 
1905         *sks->sortRelation = Z_SortRelation_ascending;
1906
1907     sks->caseSensitivity = (int *)
1908         nmem_malloc (stream, sizeof(*sks->caseSensitivity));
1909     *sks->caseSensitivity = 0;
1910
1911 #ifdef ASN_COMPILED
1912     sks->which = Z_SortKeySpec_null;
1913     sks->u.null = odr_nullval ();
1914 #else
1915     sks->missingValueAction = 0;
1916 #endif
1917
1918     sort_sequence->specs[i] = sks;
1919
1920     parms.rset_term = rset_term_create (termz, -1, rank_type);
1921     return rset_create (rset_kind_null, &parms);
1922 }
1923
1924 static RSET rpn_search_xpath (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
1925                               oid_value attributeSet,
1926                               int num_bases, char **basenames,
1927                               NMEM stream, const char *rank_type, RSET rset)
1928 {
1929     AttrType use;
1930     const char *use_string = 0;
1931     oid_value curAttributeSet = attributeSet;
1932     char term_dict[2048];
1933     int base_no;
1934     int reg_type = '0';
1935     struct grep_info grep_info;
1936
1937     yaz_log (LOG_LOG, "rpn_search_xpath 1");
1938     attr_init (&use, zapt, 1);
1939     attr_find_ex (&use, &curAttributeSet, &use_string);
1940
1941     if (curAttributeSet != VAL_IDXPATH)
1942     {
1943         yaz_log (LOG_LOG, "rpn_search_xpath - not 1");
1944         return rset;
1945     }
1946     if (!use_string)
1947     {
1948         yaz_log (LOG_LOG, "rpn_search_xpath - not 2");
1949         return rset;
1950     }
1951
1952     dict_grep_cmap (zh->reg->dict, 0, 0);
1953     if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
1954         return 0;
1955
1956     yaz_log (LOG_LOG, "rpn_search_xpath 2");
1957     for (base_no = 0; base_no < num_bases; base_no++)
1958     {
1959         const char *termp = use_string;
1960         rset_between_parms parms;
1961         RSET rset_start_tag, rset_end_tag;
1962         int ord, ord_len, i, r, max_pos;
1963         int prefix_len ;
1964         char ord_buf[32];
1965         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
1966         {
1967             zh->errCode = 109; /* Database unavailable */
1968             zh->errString = basenames[base_no];
1969             return rset;
1970         }
1971
1972         prefix_len = 0;
1973         ord = zebraExplain_lookupSU (zh->reg->zei, curAttributeSet, 1);
1974         if (ord < 0)
1975             continue;
1976         if (prefix_len)
1977             term_dict[prefix_len++] = '|';
1978         else
1979             term_dict[prefix_len++] = '(';
1980         
1981         ord_len = key_SU_encode (ord, ord_buf);
1982         for (i = 0; i<ord_len; i++)
1983         {
1984             term_dict[prefix_len++] = 1;
1985             term_dict[prefix_len++] = ord_buf[i];
1986         }
1987         term_dict[prefix_len++] = ')';
1988         term_dict[prefix_len++] = 1;
1989         term_dict[prefix_len++] = reg_type;
1990
1991         termp = use_string;
1992         strcpy (term_dict+prefix_len, use_string);
1993         
1994         grep_info.isam_p_indx = 0;
1995         yaz_log (LOG_LOG, "rpn_search_xpath 3 %s", term_dict+prefix_len);
1996         r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
1997                               &grep_info, &max_pos, 0, grep_handle);
1998         yaz_log (LOG_LOG, "%s %d positions", use_string,
1999                  grep_info.isam_p_indx);
2000         rset_start_tag =
2001             rset_trunc (zh, grep_info.isam_p_buf,
2002                         grep_info.isam_p_indx, use_string, strlen(use_string),
2003                         rank_type, 1);
2004
2005         prefix_len = 0;
2006         ord = zebraExplain_lookupSU (zh->reg->zei, curAttributeSet, 2);
2007         if (ord < 0)
2008             continue;
2009         if (prefix_len)
2010             term_dict[prefix_len++] = '|';
2011         else
2012             term_dict[prefix_len++] = '(';
2013         
2014         ord_len = key_SU_encode (ord, ord_buf);
2015         for (i = 0; i<ord_len; i++)
2016         {
2017             term_dict[prefix_len++] = 1;
2018             term_dict[prefix_len++] = ord_buf[i];
2019         }
2020         term_dict[prefix_len++] = ')';
2021         term_dict[prefix_len++] = 1;
2022         term_dict[prefix_len++] = reg_type;
2023
2024         termp = use_string;
2025
2026         strcpy (term_dict+prefix_len, use_string);
2027
2028         grep_info.isam_p_indx = 0;
2029         r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
2030                               &grep_info, &max_pos, 0, grep_handle);
2031
2032         yaz_log (LOG_LOG, "%s %d positions", use_string,
2033                  grep_info.isam_p_indx);
2034         rset_end_tag =
2035             rset_trunc (zh, grep_info.isam_p_buf,
2036                         grep_info.isam_p_indx, use_string, strlen(use_string),
2037                         rank_type, 1);
2038
2039         parms.key_size = sizeof(struct it_key);
2040         parms.cmp = key_compare_it;
2041         parms.rset_l = rset_start_tag;
2042         parms.rset_m = rset;
2043         parms.rset_r = rset_end_tag;
2044         parms.printer = key_print_it;
2045         yaz_log (LOG_LOG, "rpn_search_xpath 4");
2046         rset = rset_create (rset_kind_between, &parms);
2047     }
2048     grep_info_delete (&grep_info);
2049
2050     return rset;
2051 }
2052
2053
2054
2055 static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
2056                             oid_value attributeSet, NMEM stream,
2057                             Z_SortKeySpecList *sort_sequence,
2058                             int num_bases, char **basenames)
2059 {
2060     unsigned reg_id;
2061     char *search_type = NULL;
2062     char rank_type[128];
2063     int complete_flag;
2064     int sort_flag;
2065     char termz[IT_MAX_WORD+1];
2066     RSET rset = 0;
2067
2068     zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2069                      rank_type, &complete_flag, &sort_flag);
2070     
2071     logf (LOG_DEBUG, "reg_id=%c", reg_id);
2072     logf (LOG_DEBUG, "complete_flag=%d", complete_flag);
2073     logf (LOG_DEBUG, "search_type=%s", search_type);
2074     logf (LOG_DEBUG, "rank_type=%s", rank_type);
2075
2076     if (zapt->term->which != Z_Term_general)
2077     {
2078         zh->errCode = 124;
2079         return NULL;
2080     }
2081     trans_term (zh, zapt, termz);
2082
2083     if (sort_flag)
2084         return rpn_sort_spec (zh, zapt, attributeSet, stream, sort_sequence,
2085                               rank_type);
2086
2087     if (!strcmp (search_type, "phrase"))
2088     {
2089         rset = rpn_search_APT_phrase (zh, zapt, termz, attributeSet, stream,
2090                                       reg_id, complete_flag, rank_type,
2091                                       num_bases, basenames);
2092     }
2093     else if (!strcmp (search_type, "and-list"))
2094     {
2095         rset = rpn_search_APT_and_list (zh, zapt, termz, attributeSet, stream,
2096                                         reg_id, complete_flag, rank_type,
2097                                         num_bases, basenames);
2098     }
2099     else if (!strcmp (search_type, "or-list"))
2100     {
2101         rset = rpn_search_APT_or_list (zh, zapt, termz, attributeSet, stream,
2102                                        reg_id, complete_flag, rank_type,
2103                                        num_bases, basenames);
2104     }
2105     else if (!strcmp (search_type, "local"))
2106     {
2107         rset = rpn_search_APT_local (zh, zapt, termz, attributeSet, stream,
2108                                      rank_type);
2109     }
2110     else if (!strcmp (search_type, "numeric"))
2111     {
2112         rset = rpn_search_APT_numeric (zh, zapt, termz, attributeSet, stream,
2113                                        reg_id, complete_flag, rank_type,
2114                                        num_bases, basenames);
2115     }
2116     else
2117         zh->errCode = 118;
2118     return rpn_search_xpath (zh, zapt, attributeSet, num_bases, basenames,
2119                              stream, rank_type, rset);
2120 }
2121
2122 static RSET rpn_search_structure (ZebraHandle zh, Z_RPNStructure *zs,
2123                                   oid_value attributeSet, NMEM stream,
2124                                   Z_SortKeySpecList *sort_sequence,
2125                                   int num_bases, char **basenames)
2126 {
2127     RSET r = NULL;
2128     if (zs->which == Z_RPNStructure_complex)
2129     {
2130         Z_Operator *zop = zs->u.complex->roperator;
2131         rset_bool_parms bool_parms;
2132
2133         bool_parms.rset_l = rpn_search_structure (zh, zs->u.complex->s1,
2134                                                   attributeSet, stream,
2135                                                   sort_sequence,
2136                                                   num_bases, basenames);
2137         if (bool_parms.rset_l == NULL)
2138             return NULL;
2139         bool_parms.rset_r = rpn_search_structure (zh, zs->u.complex->s2,
2140                                                   attributeSet, stream,
2141                                                   sort_sequence,
2142                                                   num_bases, basenames);
2143         if (bool_parms.rset_r == NULL)
2144         {
2145             rset_delete (bool_parms.rset_l);
2146             return NULL;
2147         }
2148         bool_parms.key_size = sizeof(struct it_key);
2149         bool_parms.cmp = key_compare_it;
2150
2151         switch (zop->which)
2152         {
2153         case Z_Operator_and:
2154             r = rset_create (rset_kind_and, &bool_parms);
2155             break;
2156         case Z_Operator_or:
2157             r = rset_create (rset_kind_or, &bool_parms);
2158             break;
2159         case Z_Operator_and_not:
2160             r = rset_create (rset_kind_not, &bool_parms);
2161             break;
2162         case Z_Operator_prox:
2163 #ifdef ASN_COMPILED
2164             if (zop->u.prox->which != Z_ProximityOperator_known)
2165             {
2166                 zh->errCode = 132;
2167                 return NULL;
2168             }
2169 #else
2170             if (zop->u.prox->which != Z_ProxCode_known)
2171             {
2172                 zh->errCode = 132;
2173                 return NULL;
2174             }
2175 #endif
2176
2177 #ifdef ASN_COMPILED
2178             if (*zop->u.prox->u.known != Z_ProxUnit_word)
2179             {
2180                 char *val = (char *) nmem_malloc (stream, 16);
2181                 zh->errCode = 132;
2182                 zh->errString = val;
2183                 sprintf (val, "%d", *zop->u.prox->u.known);
2184                 return NULL;
2185             }
2186 #else
2187             if (*zop->u.prox->proximityUnitCode != Z_ProxUnit_word)
2188             {
2189                 char *val = (char *) nmem_malloc (stream, 16);
2190                 zh->errCode = 132;
2191                 zh->errString = val;
2192                 sprintf (val, "%d", *zop->u.prox->proximityUnitCode);
2193                 return NULL;
2194             }
2195 #endif
2196             else
2197             {
2198                 RSET rsets[2];
2199
2200                 rsets[0] = bool_parms.rset_l;
2201                 rsets[1] = bool_parms.rset_r;
2202                 
2203                 r = rpn_prox (zh, rsets, 2, 
2204                               *zop->u.prox->ordered,
2205                               (!zop->u.prox->exclusion ? 0 :
2206                                *zop->u.prox->exclusion),
2207                               *zop->u.prox->relationType,
2208                               *zop->u.prox->distance);
2209                 rset_delete (rsets[0]);
2210                 rset_delete (rsets[1]);
2211             }
2212             break;
2213         default:
2214             zh->errCode = 110;
2215             return NULL;
2216         }
2217     }
2218     else if (zs->which == Z_RPNStructure_simple)
2219     {
2220         if (zs->u.simple->which == Z_Operand_APT)
2221         {
2222             logf (LOG_DEBUG, "rpn_search_APT");
2223             r = rpn_search_APT (zh, zs->u.simple->u.attributesPlusTerm,
2224                                 attributeSet, stream, sort_sequence,
2225                                 num_bases, basenames);
2226         }
2227         else if (zs->u.simple->which == Z_Operand_resultSetId)
2228         {
2229             logf (LOG_DEBUG, "rpn_search_ref");
2230             r = resultSetRef (zh, zs->u.simple->u.resultSetId);
2231             if (!r)
2232             {
2233                 r = rset_create (rset_kind_null, NULL);
2234                 zh->errCode = 30;
2235                 zh->errString =
2236                     nmem_strdup (stream, zs->u.simple->u.resultSetId);
2237                 return 0;
2238             }
2239         }
2240         else
2241         {
2242             zh->errCode = 3;
2243             return 0;
2244         }
2245     }
2246     else
2247     {
2248         zh->errCode = 3;
2249         return 0;
2250     }
2251     return r;
2252 }
2253
2254
2255 RSET rpn_search (ZebraHandle zh, NMEM nmem,
2256                  Z_RPNQuery *rpn, int num_bases, char **basenames, 
2257                  const char *setname,
2258                  ZebraSet sset)
2259 {
2260     RSET rset;
2261     oident *attrset;
2262     oid_value attributeSet;
2263     Z_SortKeySpecList *sort_sequence;
2264     int sort_status, i;
2265
2266     zh->errCode = 0;
2267     zh->errString = NULL;
2268     zh->hits = 0;
2269
2270     sort_sequence = (Z_SortKeySpecList *)
2271         nmem_malloc (nmem, sizeof(*sort_sequence));
2272     sort_sequence->num_specs = 10;
2273     sort_sequence->specs = (Z_SortKeySpec **)
2274         nmem_malloc (nmem, sort_sequence->num_specs *
2275                      sizeof(*sort_sequence->specs));
2276     for (i = 0; i<sort_sequence->num_specs; i++)
2277         sort_sequence->specs[i] = 0;
2278     
2279     attrset = oid_getentbyoid (rpn->attributeSetId);
2280     attributeSet = attrset->value;
2281     rset = rpn_search_structure (zh, rpn->RPNStructure, attributeSet,
2282                                  nmem, sort_sequence, num_bases, basenames);
2283     if (!rset)
2284         return 0;
2285
2286     if (zh->errCode)
2287         logf (LOG_DEBUG, "search error: %d", zh->errCode);
2288     
2289     for (i = 0; sort_sequence->specs[i]; i++)
2290         ;
2291     sort_sequence->num_specs = i;
2292     if (!i)
2293         resultSetRank (zh, sset, rset);
2294     else
2295     {
2296         logf (LOG_DEBUG, "resultSetSortSingle in rpn_search");
2297         resultSetSortSingle (zh, nmem, sset, rset,
2298                              sort_sequence, &sort_status);
2299         if (zh->errCode)
2300         {
2301             logf (LOG_DEBUG, "resultSetSortSingle status = %d", zh->errCode);
2302         }
2303     }
2304     return rset;
2305 }
2306
2307 struct scan_info_entry {
2308     char *term;
2309     ISAMS_P isam_p;
2310 };
2311
2312 struct scan_info {
2313     struct scan_info_entry *list;
2314     ODR odr;
2315     int before, after;
2316     char prefix[20];
2317 };
2318
2319 static int scan_handle (char *name, const char *info, int pos, void *client)
2320 {
2321     int len_prefix, idx;
2322     struct scan_info *scan_info = (struct scan_info *) client;
2323
2324     len_prefix = strlen(scan_info->prefix);
2325     if (memcmp (name, scan_info->prefix, len_prefix))
2326         return 1;
2327     if (pos > 0)        idx = scan_info->after - pos + scan_info->before;
2328     else
2329         idx = - pos - 1;
2330     scan_info->list[idx].term = (char *)
2331         odr_malloc (scan_info->odr, strlen(name + len_prefix)+1);
2332     strcpy (scan_info->list[idx].term, name + len_prefix);
2333     assert (*info == sizeof(ISAMS_P));
2334     memcpy (&scan_info->list[idx].isam_p, info+1, sizeof(ISAMS_P));
2335     return 0;
2336 }
2337
2338 static void scan_term_untrans (ZebraHandle zh, NMEM stream, int reg_type,
2339                                char **dst, const char *src)
2340 {
2341     char term_dst[1024];
2342     
2343     term_untrans (zh, reg_type, term_dst, src);
2344     
2345     *dst = (char *) nmem_malloc (stream, strlen(term_dst)+1);
2346     strcpy (*dst, term_dst);
2347 }
2348
2349 static void count_set (RSET r, int *count)
2350 {
2351     int psysno = 0;
2352     int kno = 0;
2353     struct it_key key;
2354     RSFD rfd;
2355     int term_index;
2356
2357     logf (LOG_DEBUG, "count_set");
2358
2359     *count = 0;
2360     rfd = rset_open (r, RSETF_READ);
2361     while (rset_read (r, rfd, &key, &term_index))
2362     {
2363         if (key.sysno != psysno)
2364         {
2365             psysno = key.sysno;
2366             (*count)++;
2367         }
2368         kno++;
2369     }
2370     rset_close (r, rfd);
2371     logf (LOG_DEBUG, "%d keys, %d records", kno, *count);
2372 }
2373
2374 void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
2375                oid_value attributeset,
2376                int num_bases, char **basenames,
2377                int *position, int *num_entries, ZebraScanEntry **list,
2378                int *is_partial)
2379 {
2380     int i;
2381     int pos = *position;
2382     int num = *num_entries;
2383     int before;
2384     int after;
2385     int base_no;
2386     char termz[IT_MAX_WORD+20];
2387     AttrType use;
2388     int use_value;
2389     struct scan_info *scan_info_array;
2390     ZebraScanEntry *glist;
2391     int ords[32], ord_no = 0;
2392     int ptr[32];
2393
2394     unsigned reg_id;
2395     char *search_type = NULL;
2396     char rank_type[128];
2397     int complete_flag;
2398     int sort_flag;
2399     *list = 0;
2400
2401     if (attributeset == VAL_NONE)
2402         attributeset = VAL_BIB1;
2403
2404     yaz_log (LOG_DEBUG, "position = %d, num = %d set=%d",
2405              pos, num, attributeset);
2406         
2407     attr_init (&use, zapt, 1);
2408     use_value = attr_find (&use, &attributeset);
2409
2410     if (zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
2411                          rank_type, &complete_flag, &sort_flag))
2412     {
2413         *num_entries = 0;
2414         zh->errCode = 113;
2415         return ;
2416     }
2417     yaz_log (LOG_DEBUG, "use_value = %d", use_value);
2418
2419     if (use_value == -1)
2420         use_value = 1016;
2421     for (base_no = 0; base_no < num_bases && ord_no < 32; base_no++)
2422     {
2423         int r;
2424         attent attp;
2425         data1_local_attribute *local_attr;
2426
2427         if ((r=att_getentbyatt (zh, &attp, attributeset, use_value)))
2428         {
2429             logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d",
2430                   attributeset, use_value);
2431             if (r == -1)
2432                 zh->errCode = 114;
2433             else
2434                 zh->errCode = 121;
2435             *num_entries = 0;
2436             return;
2437         }
2438         if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
2439         {
2440             zh->errString = basenames[base_no];
2441             zh->errCode = 109; /* Database unavailable */
2442             *num_entries = 0;
2443             return;
2444         }
2445         for (local_attr = attp.local_attributes; local_attr && ord_no < 32;
2446              local_attr = local_attr->next)
2447         {
2448             int ord;
2449
2450             ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
2451                                          local_attr->local);
2452             if (ord > 0)
2453                 ords[ord_no++] = ord;
2454         }
2455     }
2456     if (ord_no == 0)
2457     {
2458         *num_entries = 0;
2459         zh->errCode = 113;
2460         return;
2461     }
2462     /* prepare dictionary scanning */
2463     before = pos-1;
2464     after = 1+num-pos;
2465     scan_info_array = (struct scan_info *)
2466         odr_malloc (stream, ord_no * sizeof(*scan_info_array));
2467     for (i = 0; i < ord_no; i++)
2468     {
2469         int j, prefix_len = 0;
2470         int before_tmp = before, after_tmp = after;
2471         struct scan_info *scan_info = scan_info_array + i;
2472         struct rpn_char_map_info rcmi;
2473
2474         rpn_char_map_prepare (zh->reg, reg_id, &rcmi);
2475
2476         scan_info->before = before;
2477         scan_info->after = after;
2478         scan_info->odr = stream;
2479
2480         scan_info->list = (struct scan_info_entry *)
2481             odr_malloc (stream, (before+after) * sizeof(*scan_info->list));
2482         for (j = 0; j<before+after; j++)
2483             scan_info->list[j].term = NULL;
2484
2485         prefix_len += key_SU_encode (ords[i], termz + prefix_len);
2486         termz[prefix_len++] = reg_id;
2487         termz[prefix_len] = 0;
2488         strcpy (scan_info->prefix, termz);
2489
2490         trans_scan_term (zh, zapt, termz+prefix_len, reg_id);
2491                     
2492         dict_scan (zh->reg->dict, termz, &before_tmp, &after_tmp,
2493                    scan_info, scan_handle);
2494     }
2495     glist = (ZebraScanEntry *)
2496         odr_malloc (stream, (before+after)*sizeof(*glist));
2497
2498     /* consider terms after main term */
2499     for (i = 0; i < ord_no; i++)
2500         ptr[i] = before;
2501     
2502     *is_partial = 0;
2503     for (i = 0; i<after; i++)
2504     {
2505         int j, j0 = -1;
2506         const char *mterm = NULL;
2507         const char *tst;
2508         RSET rset;
2509         
2510         for (j = 0; j < ord_no; j++)
2511         {
2512             if (ptr[j] < before+after &&
2513                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2514                 (!mterm || strcmp (tst, mterm) < 0))
2515             {
2516                 j0 = j;
2517                 mterm = tst;
2518             }
2519         }
2520         if (j0 == -1)
2521             break;
2522         scan_term_untrans (zh, stream->mem, reg_id,
2523                            &glist[i+before].term, mterm);
2524         rset = rset_trunc (zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
2525                            glist[i+before].term, strlen(glist[i+before].term),
2526                            NULL, 0);
2527
2528         ptr[j0]++;
2529         for (j = j0+1; j<ord_no; j++)
2530         {
2531             if (ptr[j] < before+after &&
2532                 (tst=scan_info_array[j].list[ptr[j]].term) &&
2533                 !strcmp (tst, mterm))
2534             {
2535                 rset_bool_parms bool_parms;
2536                 RSET rset2;
2537
2538                 rset2 =
2539                    rset_trunc (zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
2540                                glist[i+before].term,
2541                                strlen(glist[i+before].term), NULL, 0);
2542
2543                 bool_parms.key_size = sizeof(struct it_key);
2544                 bool_parms.cmp = key_compare_it;
2545                 bool_parms.rset_l = rset;
2546                 bool_parms.rset_r = rset2;
2547               
2548                 rset = rset_create (rset_kind_or, &bool_parms);
2549
2550                 ptr[j]++;
2551             }
2552         }
2553         count_set (rset, &glist[i+before].occurrences);
2554         rset_delete (rset);
2555     }
2556     if (i < after)
2557     {
2558         *num_entries -= (after-i);
2559         *is_partial = 1;
2560     }
2561
2562     /* consider terms before main term */
2563     for (i = 0; i<ord_no; i++)
2564         ptr[i] = 0;
2565
2566     for (i = 0; i<before; i++)
2567     {
2568         int j, j0 = -1;
2569         const char *mterm = NULL;
2570         const char *tst;
2571         RSET rset;
2572         
2573         for (j = 0; j <ord_no; j++)
2574         {
2575             if (ptr[j] < before &&
2576                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2577                 (!mterm || strcmp (tst, mterm) > 0))
2578             {
2579                 j0 = j;
2580                 mterm = tst;
2581             }
2582         }
2583         if (j0 == -1)
2584             break;
2585
2586         scan_term_untrans (zh, stream->mem, reg_id,
2587                            &glist[before-1-i].term, mterm);
2588
2589         rset = rset_trunc
2590                (zh, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1,
2591                 glist[before-1-i].term, strlen(glist[before-1-i].term),
2592                 NULL, 0);
2593
2594         ptr[j0]++;
2595
2596         for (j = j0+1; j<ord_no; j++)
2597         {
2598             if (ptr[j] < before &&
2599                 (tst=scan_info_array[j].list[before-1-ptr[j]].term) &&
2600                 !strcmp (tst, mterm))
2601             {
2602                 rset_bool_parms bool_parms;
2603                 RSET rset2;
2604
2605                 rset2 = rset_trunc (zh,
2606                          &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1,
2607                                     glist[before-1-i].term,
2608                                     strlen(glist[before-1-i].term), NULL, 0);
2609
2610                 bool_parms.key_size = sizeof(struct it_key);
2611                 bool_parms.cmp = key_compare_it;
2612                 bool_parms.rset_l = rset;
2613                 bool_parms.rset_r = rset2;
2614               
2615                 rset = rset_create (rset_kind_or, &bool_parms);
2616
2617                 ptr[j]++;
2618             }
2619         }
2620         count_set (rset, &glist[before-1-i].occurrences);
2621         rset_delete (rset);
2622     }
2623     i = before-i;
2624     if (i)
2625     {
2626         *is_partial = 1;
2627         *position -= i;
2628         *num_entries -= i;
2629     }
2630     *list = glist + i;               /* list is set to first 'real' entry */
2631     
2632     logf (LOG_DEBUG, "position = %d, num_entries = %d",
2633           *position, *num_entries);
2634     if (zh->errCode)
2635         logf (LOG_DEBUG, "scan error: %d", zh->errCode);
2636 }
2637