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