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