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