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