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