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