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