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