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