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