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