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