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