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