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