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