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