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