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