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