Make equivalent work with trunc=104, 105. Added test for it.
[idzebra-moved-to-github.git] / index / zrpn.c
index e05e3a8..4788742 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: zrpn.c,v 1.180 2005-04-29 10:36:13 adam Exp $
+/* $Id: zrpn.c,v 1.188 2005-05-03 14:04:31 adam Exp $
    Copyright (C) 1995-2005
    Index Data ApS
 
@@ -36,18 +36,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include <charmap.h>
 #include <rset.h>
 
-static const struct key_control it_ctrl =
-{ 
-    sizeof(struct it_key),
-    2, /* we have sysnos and seqnos in this key, nothing more */
-    key_compare_it, 
-    key_logdump_txt,   /* FIXME  - clean up these functions */
-    key_get_seq,
-};
-
-
-const struct key_control *key_it_ctrl = &it_ctrl;
-
 struct rpn_char_map_info
 {
     ZebraMaps zm;
@@ -534,7 +522,7 @@ static int term_104(ZebraMaps zebra_maps, int reg_type,
                    const char **src, char *dst, int space_split,
                    char *dst_term)
 {
-    const char *s0, *s1;
+    const char *s0;
     const char **map;
     int i = 0;
     int j = 0;
@@ -582,17 +570,33 @@ static int term_104(ZebraMaps zebra_maps, int reg_type,
         }
        else
         {
-            s1 = s0;
-            map = zebra_maps_input(zebra_maps, reg_type, &s0, strlen(s0), 0);
+           const char *s1 = s0;
+           int q_map_match = 0;
+           map = zebra_maps_search(zebra_maps, reg_type, &s0, strlen(s0), 
+                                   &q_map_match);
             if (space_split && **map == *CHR_SPACE)
                 break;
-            while (s1 < s0)
-            {
-                if (strchr(REGEX_CHARS, *s1))
-                    dst[i++] = '\\';
-                dst_term[j++] = *s1;
-                dst[i++] = *s1++;
-            }
+
+           /* add non-space char */
+           memcpy(dst_term+j, s1, s0 - s1);
+           j += (s0 - s1);
+           if (!q_map_match)
+           {
+               while (s1 < s0)
+               {
+                   if (strchr(REGEX_CHARS, *s1))
+                       dst[i++] = '\\';
+                   dst[i++] = *s1++;
+               }
+           }
+           else
+           {
+               char tmpbuf[80];
+               esc_str(tmpbuf, sizeof(tmpbuf), map[0], strlen(map[0]));
+               
+               strcpy(dst + i, map[0]);
+               i += strlen(map[0]);
+           }
         }
     }
     dst[i] = '\0';
@@ -606,7 +610,7 @@ static int term_105(ZebraMaps zebra_maps, int reg_type,
                    const char **src, char *dst, int space_split,
                    char *dst_term, int right_truncate)
 {
-    const char *s0, *s1;
+    const char *s0;
     const char **map;
     int i = 0;
     int j = 0;
@@ -629,17 +633,33 @@ static int term_105(ZebraMaps zebra_maps, int reg_type,
         }
        else
         {
-            s1 = s0;
-            map = zebra_maps_input(zebra_maps, reg_type, &s0, strlen(s0), 0);
+           const char *s1 = s0;
+           int q_map_match = 0;
+           map = zebra_maps_search(zebra_maps, reg_type, &s0, strlen(s0), 
+                                   &q_map_match);
             if (space_split && **map == *CHR_SPACE)
                 break;
-            while (s1 < s0)
-            {
-                if (strchr(REGEX_CHARS, *s1))
-                    dst[i++] = '\\';
-                dst_term[j++] = *s1;
-                dst[i++] = *s1++;
-            }
+
+           /* add non-space char */
+           memcpy(dst_term+j, s1, s0 - s1);
+           j += (s0 - s1);
+           if (!q_map_match)
+           {
+               while (s1 < s0)
+               {
+                   if (strchr(REGEX_CHARS, *s1))
+                       dst[i++] = '\\';
+                   dst[i++] = *s1++;
+               }
+           }
+           else
+           {
+               char tmpbuf[80];
+               esc_str(tmpbuf, sizeof(tmpbuf), map[0], strlen(map[0]));
+               
+               strcpy(dst + i, map[0]);
+               i += strlen(map[0]);
+           }
         }
     }
     if (right_truncate)
@@ -969,7 +989,8 @@ static ZEBRA_RES string_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                             int num_bases, char **basenames,
                             char *term_dst, int xpath_use);
 
-static ZEBRA_RES term_trunc(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
+static ZEBRA_RES term_trunc(ZebraHandle zh,
+                           Z_AttributesPlusTerm *zapt,
                            const char **term_sub, 
                            oid_value attributeSet, NMEM stream,
                            struct grep_info *grep_info,
@@ -978,7 +999,8 @@ static ZEBRA_RES term_trunc(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                            char *term_dst,
                            const char *rank_type, int xpath_use,
                            NMEM rset_nmem,
-                           RSET *rset)
+                           RSET *rset,
+                           struct rset_key_control *kc)
 {
     ZEBRA_RES res;
     *rset = 0;
@@ -995,7 +1017,7 @@ static ZEBRA_RES term_trunc(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                       grep_info->isam_p_indx, term_dst,
                       strlen(term_dst), rank_type, 1 /* preserve pos */,
                       zapt->term->which, rset_nmem,
-                      key_it_ctrl, key_it_ctrl->scope);
+                      kc, kc->scope);
     if (!*rset)
        return ZEBRA_FAIL;
     return ZEBRA_OK;
@@ -1236,7 +1258,7 @@ static ZEBRA_RES string_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
             strcat(term_dict, ")");
             break;
         case 103:       /* Regexp-2 */
-            r = 1;
+            regex_range = 1;
             term_dict[j++] = '(';
            init_pos = 2;
             if (!term_103(zh->reg->zebra_maps, reg_type,
@@ -1247,6 +1269,7 @@ static ZEBRA_RES string_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                 return ZEBRA_OK;
            }
             strcat(term_dict, ")");
+           break;
         case 104:        /* process # and ! in term */
             term_dict[j++] = '(';
             if (!term_104(zh->reg->zebra_maps, reg_type,
@@ -1510,7 +1533,8 @@ static ZEBRA_RES term_list_trunc(ZebraHandle zh,
                                 const char *rank_type, int xpath_use,
                                 int num_bases, char **basenames, 
                                 NMEM rset_nmem,
-                                RSET **result_sets, int *num_result_sets)
+                                RSET **result_sets, int *num_result_sets,
+                                struct rset_key_control *kc)
 {
     char term_dst[IT_MAX_WORD+1];
     struct grep_info grep_info;
@@ -1542,7 +1566,8 @@ static ZEBRA_RES term_list_trunc(ZebraHandle zh,
                         num_bases, basenames,
                         term_dst, rank_type,
                         xpath_use, rset_nmem,
-                        &(*result_sets)[*num_result_sets]);
+                        &(*result_sets)[*num_result_sets],
+                        kc);
        if (res != ZEBRA_OK)
        {
            int i;
@@ -1568,7 +1593,8 @@ static ZEBRA_RES rpn_search_APT_phrase(ZebraHandle zh,
                                       const char *rank_type, int xpath_use,
                                       int num_bases, char **basenames, 
                                       NMEM rset_nmem,
-                                      RSET *rset)
+                                      RSET *rset,
+                                      struct rset_key_control *kc)
 {
     RSET *result_sets = 0;
     int num_result_sets = 0;
@@ -1578,15 +1604,15 @@ static ZEBRA_RES rpn_search_APT_phrase(ZebraHandle zh,
                        rank_type, xpath_use,
                        num_bases, basenames,
                        rset_nmem,
-                       &result_sets, &num_result_sets);
+                       &result_sets, &num_result_sets, kc);
     if (res != ZEBRA_OK)
        return res;
     if (num_result_sets == 0)
-       *rset = rsnull_create (rset_nmem, key_it_ctrl); 
+       *rset = rsnull_create (rset_nmem, kc); 
     else if (num_result_sets == 1)
        *rset = result_sets[0];
     else
-       *rset = rsprox_create(rset_nmem, key_it_ctrl, key_it_ctrl->scope,
+       *rset = rsprox_create(rset_nmem, kc, kc->scope,
                              num_result_sets, result_sets,
                              1 /* ordered */, 0 /* exclusion */,
                              3 /* relation */, 1 /* distance */);
@@ -1605,7 +1631,8 @@ static ZEBRA_RES rpn_search_APT_or_list(ZebraHandle zh,
                                        int xpath_use,
                                        int num_bases, char **basenames,
                                        NMEM rset_nmem,
-                                       RSET *rset)
+                                       RSET *rset,
+                                       struct rset_key_control *kc)
 {
     RSET *result_sets = 0;
     int num_result_sets = 0;
@@ -1615,15 +1642,15 @@ static ZEBRA_RES rpn_search_APT_or_list(ZebraHandle zh,
                        rank_type, xpath_use,
                        num_bases, basenames,
                        rset_nmem,
-                       &result_sets, &num_result_sets);
+                       &result_sets, &num_result_sets, kc);
     if (res != ZEBRA_OK)
        return res;
     if (num_result_sets == 0)
-       *rset = rsnull_create (rset_nmem, key_it_ctrl); 
+       *rset = rsnull_create (rset_nmem, kc); 
     else if (num_result_sets == 1)
        *rset = result_sets[0];
     else
-       *rset = rsmulti_or_create(rset_nmem, key_it_ctrl, key_it_ctrl->scope,
+       *rset = rsmulti_or_create(rset_nmem, kc, kc->scope,
                                  num_result_sets, result_sets);
     if (!*rset)
        return ZEBRA_FAIL;
@@ -1640,7 +1667,8 @@ static ZEBRA_RES rpn_search_APT_and_list(ZebraHandle zh,
                                         int xpath_use,
                                         int num_bases, char **basenames,
                                         NMEM rset_nmem,
-                                        RSET *rset)
+                                        RSET *rset,
+                                        struct rset_key_control *kc)
 {
     RSET *result_sets = 0;
     int num_result_sets = 0;
@@ -1650,15 +1678,16 @@ static ZEBRA_RES rpn_search_APT_and_list(ZebraHandle zh,
                        rank_type, xpath_use,
                        num_bases, basenames,
                        rset_nmem,
-                       &result_sets, &num_result_sets);
+                       &result_sets, &num_result_sets,
+                       kc);
     if (res != ZEBRA_OK)
        return res;
     if (num_result_sets == 0)
-       *rset = rsnull_create (rset_nmem, key_it_ctrl); 
+       *rset = rsnull_create (rset_nmem, kc); 
     else if (num_result_sets == 1)
        *rset = result_sets[0];
     else
-       *rset = rsmulti_and_create(rset_nmem, key_it_ctrl, key_it_ctrl->scope,
+       *rset = rsmulti_and_create(rset_nmem, kc, kc->scope,
                                   num_result_sets, result_sets);
     if (!*rset)
        return ZEBRA_FAIL;
@@ -1875,7 +1904,8 @@ static ZEBRA_RES rpn_search_APT_numeric(ZebraHandle zh,
                                        const char *rank_type, int xpath_use,
                                        int num_bases, char **basenames,
                                        NMEM rset_nmem,
-                                       RSET *rset)
+                                       RSET *rset,
+                                       struct rset_key_control *kc)
 {
     char term_dst[IT_MAX_WORD+1];
     const char *termp = termz;
@@ -1915,7 +1945,7 @@ static ZEBRA_RES rpn_search_APT_numeric(ZebraHandle zh,
                       strlen(term_dst), rank_type,
                       0 /* preserve position */,
                       zapt->term->which, rset_nmem, 
-                      key_it_ctrl,key_it_ctrl->scope);
+                      kc, kc->scope);
        if (!result_sets[num_result_sets])
            break;
        num_result_sets++;
@@ -1929,11 +1959,11 @@ static ZEBRA_RES rpn_search_APT_numeric(ZebraHandle zh,
        return ZEBRA_FAIL;
     }
     if (num_result_sets == 0)
-        *rset = rsnull_create(rset_nmem, key_it_ctrl);
+        *rset = rsnull_create(rset_nmem, kc);
     if (num_result_sets == 1)
         *rset = result_sets[0];
     else
-       *rset = rsmulti_and_create(rset_nmem, key_it_ctrl, key_it_ctrl->scope,
+       *rset = rsmulti_and_create(rset_nmem, kc, kc->scope,
                                   num_result_sets, result_sets);
     if (!*rset)
        return ZEBRA_FAIL;
@@ -1946,12 +1976,13 @@ static ZEBRA_RES rpn_search_APT_local(ZebraHandle zh,
                                      oid_value attributeSet,
                                      NMEM stream,
                                      const char *rank_type, NMEM rset_nmem,
-                                     RSET *rset)
+                                     RSET *rset,
+                                     struct rset_key_control *kc)
 {
     RSFD rsfd;
     struct it_key key;
     int sys;
-    *rset = rstemp_create(rset_nmem,key_it_ctrl,key_it_ctrl->scope,
+    *rset = rstemp_create(rset_nmem, kc, kc->scope,
                          res_get (zh->res, "setTmpDir"),0 );
     rsfd = rset_open(*rset, RSETF_WRITE);
     
@@ -1970,7 +2001,8 @@ static ZEBRA_RES rpn_sort_spec(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                               oid_value attributeSet, NMEM stream,
                               Z_SortKeySpecList *sort_sequence,
                               const char *rank_type,
-                              RSET *rset)
+                              RSET *rset,
+                              struct rset_key_control *kc)
 {
     int i;
     int sort_relation_value;
@@ -2057,7 +2089,7 @@ static ZEBRA_RES rpn_sort_spec(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     sks->which = Z_SortKeySpec_null;
     sks->u.null = odr_nullval ();
     sort_sequence->specs[i] = sks;
-    *rset = rsnull_create (NULL, key_it_ctrl);
+    *rset = rsnull_create (NULL, kc);
     return ZEBRA_OK;
 }
 
@@ -2083,7 +2115,8 @@ static int parse_xpath(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
 
 static RSET xpath_trunc(ZebraHandle zh, NMEM stream,
                         int reg_type, const char *term, int use,
-                        oid_value curAttributeSet, NMEM rset_nmem)
+                        oid_value curAttributeSet, NMEM rset_nmem,
+                       struct rset_key_control *kc)
 {
     RSET rset;
     struct grep_info grep_info;
@@ -2096,10 +2129,10 @@ static RSET xpath_trunc(ZebraHandle zh, NMEM stream,
     const char *flags = "void";
 
     if (grep_info_prepare(zh, 0 /* zapt */, &grep_info, '0', stream))
-        return rsnull_create (rset_nmem,key_it_ctrl);
+        return rsnull_create(rset_nmem, kc);
     
     if (ord < 0)
-        return rsnull_create (rset_nmem,key_it_ctrl);
+        return rsnull_create(rset_nmem, kc);
     if (prefix_len)
         term_dict[prefix_len++] = '|';
     else
@@ -2125,7 +2158,7 @@ static RSET xpath_trunc(ZebraHandle zh, NMEM stream,
     rset = rset_trunc(zh, grep_info.isam_p_buf,
                      grep_info.isam_p_indx, term, strlen(term),
                      flags, 1, term_type,rset_nmem,
-                     key_it_ctrl, key_it_ctrl->scope);
+                     kc, kc->scope);
     grep_info_delete(&grep_info);
     return rset;
 }
@@ -2135,7 +2168,8 @@ static RSET rpn_search_xpath(ZebraHandle zh,
                             int num_bases, char **basenames,
                             NMEM stream, const char *rank_type, RSET rset,
                             int xpath_len, struct xpath_location_step *xpath,
-                             NMEM rset_nmem)
+                             NMEM rset_nmem,
+                            struct rset_key_control *kc)
 {
     oid_value curAttributeSet = attributeSet;
     int base_no;
@@ -2245,7 +2279,7 @@ static RSET rpn_search_xpath(ZebraHandle zh,
                 wrbuf_puts(wbuf, "");
                 rset_attr = xpath_trunc(
                     zh, stream, '0', wrbuf_buf(wbuf), 3, 
-                    curAttributeSet,rset_nmem);
+                    curAttributeSet, rset_nmem, kc);
                 wrbuf_free(wbuf, 1);
             } 
             else 
@@ -2257,13 +2291,12 @@ static RSET rpn_search_xpath(ZebraHandle zh,
             if (strlen(xpath_rev))
             {
                 rset_start_tag = xpath_trunc(zh, stream, '0', 
-                        xpath_rev, 1, curAttributeSet, rset_nmem);
+                        xpath_rev, 1, curAttributeSet, rset_nmem, kc);
             
                 rset_end_tag = xpath_trunc(zh, stream, '0', 
-                        xpath_rev, 2, curAttributeSet, rset_nmem);
+                        xpath_rev, 2, curAttributeSet, rset_nmem, kc);
 
-                rset = rsbetween_create(rset_nmem, key_it_ctrl,
-                                       key_it_ctrl->scope,
+                rset = rsbetween_create(rset_nmem, kc, kc->scope,
                                        rset_start_tag, rset,
                                        rset_end_tag, rset_attr);
             }
@@ -2274,14 +2307,13 @@ static RSET rpn_search_xpath(ZebraHandle zh,
     return rset;
 }
 
-
-
 static ZEBRA_RES rpn_search_APT(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                                oid_value attributeSet, NMEM stream,
                                Z_SortKeySpecList *sort_sequence,
                                int num_bases, char **basenames, 
                                NMEM rset_nmem,
-                               RSET *rset)
+                               RSET *rset,
+                               struct rset_key_control *kc)
 {
     ZEBRA_RES res = ZEBRA_OK;
     unsigned reg_id;
@@ -2312,7 +2344,7 @@ static ZEBRA_RES rpn_search_APT(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
 
     if (sort_flag)
         return rpn_sort_spec(zh, zapt, attributeSet, stream, sort_sequence,
-                            rank_type, rset);
+                            rank_type, rset, kc);
     xpath_len = parse_xpath(zh, zapt, attributeSet, xpath, 10, stream);
     if (xpath_len >= 0)
     {
@@ -2327,7 +2359,7 @@ static ZEBRA_RES rpn_search_APT(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                                    reg_id, complete_flag, rank_type,
                                    xpath_use,
                                    num_bases, basenames, rset_nmem,
-                                   rset);
+                                   rset, kc);
     }
     else if (!strcmp(search_type, "and-list"))
     {
@@ -2335,7 +2367,7 @@ static ZEBRA_RES rpn_search_APT(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                                      reg_id, complete_flag, rank_type,
                                      xpath_use,
                                      num_bases, basenames, rset_nmem,
-                                     rset);
+                                     rset, kc);
     }
     else if (!strcmp(search_type, "or-list"))
     {
@@ -2343,19 +2375,20 @@ static ZEBRA_RES rpn_search_APT(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                                     reg_id, complete_flag, rank_type,
                                     xpath_use,
                                     num_bases, basenames, rset_nmem,
-                                    rset);
+                                    rset, kc);
     }
     else if (!strcmp(search_type, "local"))
     {
         res = rpn_search_APT_local(zh, zapt, termz, attributeSet, stream,
-                                  rank_type, rset_nmem, rset);
+                                  rank_type, rset_nmem, rset, kc);
     }
     else if (!strcmp(search_type, "numeric"))
     {
         res = rpn_search_APT_numeric(zh, zapt, termz, attributeSet, stream,
                                     reg_id, complete_flag, rank_type,
                                     xpath_use,
-                                    num_bases, basenames, rset_nmem, rset);
+                                    num_bases, basenames, rset_nmem,
+                                    rset, kc);
     }
     else
     {
@@ -2368,7 +2401,7 @@ static ZEBRA_RES rpn_search_APT(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
        return ZEBRA_FAIL;
     *rset = rpn_search_xpath(zh, attributeSet, num_bases, basenames,
                             stream, rank_type, *rset, 
-                            xpath_len, xpath, rset_nmem);
+                            xpath_len, xpath, rset_nmem, kc);
     if (!*rset)
        return ZEBRA_FAIL;
     return ZEBRA_OK;
@@ -2380,7 +2413,8 @@ static ZEBRA_RES rpn_search_structure(ZebraHandle zh, Z_RPNStructure *zs,
                                      Z_SortKeySpecList *sort_sequence,
                                      int num_bases, char **basenames,
                                      RSET **result_sets, int *num_result_sets,
-                                     Z_Operator *parent_op);
+                                     Z_Operator *parent_op,
+                                     struct rset_key_control *kc);
 
 ZEBRA_RES rpn_search_top(ZebraHandle zh, Z_RPNStructure *zs,
                         oid_value attributeSet, 
@@ -2391,12 +2425,16 @@ ZEBRA_RES rpn_search_top(ZebraHandle zh, Z_RPNStructure *zs,
 {
     RSET *result_sets = 0;
     int num_result_sets = 0;
-    ZEBRA_RES res = rpn_search_structure(zh, zs, attributeSet,
-                                        stream, rset_nmem,
-                                        sort_sequence, 
-                                        num_bases, basenames,
-                                        &result_sets, &num_result_sets,
-                                        0 /* no op */);
+    ZEBRA_RES res;
+    struct rset_key_control *kc = zebra_key_control_create(zh);
+
+    res = rpn_search_structure(zh, zs, attributeSet,
+                              stream, rset_nmem,
+                              sort_sequence, 
+                              num_bases, basenames,
+                              &result_sets, &num_result_sets,
+                              0 /* no parent op */,
+                              kc);
     if (res != ZEBRA_OK)
     {
        int i;
@@ -2409,6 +2447,8 @@ ZEBRA_RES rpn_search_top(ZebraHandle zh, Z_RPNStructure *zs,
     assert(result_sets);
     assert(*result_sets);
     *result_set = *result_sets;
+
+    (*kc->dec)(kc);
     return ZEBRA_OK;
 }
 
@@ -2418,7 +2458,8 @@ ZEBRA_RES rpn_search_structure(ZebraHandle zh, Z_RPNStructure *zs,
                               Z_SortKeySpecList *sort_sequence,
                               int num_bases, char **basenames,
                               RSET **result_sets, int *num_result_sets,
-                              Z_Operator *parent_op)
+                              Z_Operator *parent_op,
+                              struct rset_key_control *kc)
 {
     *num_result_sets = 0;
     if (zs->which == Z_RPNStructure_complex)
@@ -2435,7 +2476,7 @@ ZEBRA_RES rpn_search_structure(ZebraHandle zh, Z_RPNStructure *zs,
                                   sort_sequence,
                                   num_bases, basenames,
                                   &result_sets_l, &num_result_sets_l,
-                                  zop);
+                                  zop, kc);
        if (res != ZEBRA_OK)
        {
            int i;
@@ -2448,7 +2489,7 @@ ZEBRA_RES rpn_search_structure(ZebraHandle zh, Z_RPNStructure *zs,
                                   sort_sequence,
                                   num_bases, basenames,
                                   &result_sets_r, &num_result_sets_r,
-                                  zop);
+                                  zop, kc);
        if (res != ZEBRA_OK)
        {
            int i;
@@ -2478,18 +2519,18 @@ ZEBRA_RES rpn_search_structure(ZebraHandle zh, Z_RPNStructure *zs,
            switch (zop->which)
            {
            case Z_Operator_and:
-               rset = rsmulti_and_create(rset_nmem, key_it_ctrl,
-                                         key_it_ctrl->scope,
+               rset = rsmulti_and_create(rset_nmem, kc,
+                                         kc->scope,
                                          *num_result_sets, *result_sets);
                break;
            case Z_Operator_or:
-               rset = rsmulti_or_create(rset_nmem, key_it_ctrl,
-                                        key_it_ctrl->scope,
+               rset = rsmulti_or_create(rset_nmem, kc,
+                                        kc->scope,
                                         *num_result_sets, *result_sets);
                break;
            case Z_Operator_and_not:
-               rset = rsbool_create_not(rset_nmem, key_it_ctrl,
-                                        key_it_ctrl->scope,
+               rset = rsbool_create_not(rset_nmem, kc,
+                                        kc->scope,
                                         (*result_sets)[0],
                                         (*result_sets)[1]);
                break;
@@ -2509,8 +2550,8 @@ ZEBRA_RES rpn_search_structure(ZebraHandle zh, Z_RPNStructure *zs,
                }
                else
                {
-                   rset = rsprox_create(rset_nmem, key_it_ctrl,
-                                        key_it_ctrl->scope,
+                   rset = rsprox_create(rset_nmem, kc,
+                                        kc->scope,
                                         *num_result_sets, *result_sets, 
                                         *zop->u.prox->ordered,
                                         (!zop->u.prox->exclusion ? 
@@ -2539,7 +2580,8 @@ ZEBRA_RES rpn_search_structure(ZebraHandle zh, Z_RPNStructure *zs,
             yaz_log(YLOG_DEBUG, "rpn_search_APT");
             res = rpn_search_APT(zh, zs->u.simple->u.attributesPlusTerm,
                                 attributeSet, stream, sort_sequence,
-                                num_bases, basenames, rset_nmem, &rset);
+                                num_bases, basenames, rset_nmem, &rset,
+                                kc);
            if (res != ZEBRA_OK)
                return res;
         }
@@ -2598,6 +2640,7 @@ static int scan_handle (char *name, const char *info, int pos, void *client)
        idx = scan_info->after - pos + scan_info->before;
     else
         idx = - pos - 1;
+
     if (idx < 0)
        return 0;
     scan_info->list[idx].term = (char *)
@@ -2695,6 +2738,7 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
     int complete_flag;
     int sort_flag;
     NMEM rset_nmem = NULL; 
+    struct rset_key_control *kc = 0;
 
     *list = 0;
     *is_partial = 0;
@@ -2818,20 +2862,18 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
         return ZEBRA_OK;
     }
     /* prepare dictionary scanning */
-    if (pos <= 0)
-    {
-       zh->errCode = YAZ_BIB1_SCAN_UNSUPP_VALUE_OF_POSITION_IN_RESPONSE;
-       *num_entries = 0;
-       return ZEBRA_FAIL;
-    }
     if (num < 1)
     {
        *num_entries = 0;
        return ZEBRA_OK;
     }
     before = pos-1;
+    if (before < 0)
+       before = 0;
     after = 1+num-pos;
-    yaz_log(YLOG_EBUG, "rpn_scan pos=%d num=%d before=%d "
+    if (after < 0)
+       after = 0;
+    yaz_log(YLOG_DEBUG, "rpn_scan pos=%d num=%d before=%d "
            "after=%d before+after=%d",
            pos, num, before, after, before+after);
     scan_info_array = (struct scan_info *)
@@ -2869,6 +2911,7 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
         odr_malloc(stream, (before+after)*sizeof(*glist));
 
     rset_nmem = nmem_create();
+    kc = zebra_key_control_create(zh);
 
     /* consider terms after main term */
     for (i = 0; i < ord_no; i++)
@@ -2880,8 +2923,10 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
         int j, j0 = -1;
         const char *mterm = NULL;
         const char *tst;
-        RSET rset;
-        
+        RSET rset = 0;
+       int lo = i + pos-1; /* offset in result list */
+
+       /* find: j0 is the first of the minimal values */
         for (j = 0; j < ord_no; j++)
         {
             if (ptr[j] < before+after && ptr[j] >= 0 &&
@@ -2893,50 +2938,73 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
             }
         }
         if (j0 == -1)
-            break;
-        scan_term_untrans(zh, stream->mem, reg_id,
-                         &glist[i+before].term, mterm);
-        rset = rset_trunc(zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
-                         glist[i+before].term, strlen(glist[i+before].term),
-                         NULL, 0, zapt->term->which, rset_nmem, 
-                         key_it_ctrl,key_it_ctrl->scope);
-        ptr[j0]++;
+            break;  /* no value found, stop */
+
+       /* get result set for first one , but only if it's within bounds */
+       if (lo >= 0)
+       {
+           /* get result set for first term */
+           scan_term_untrans(zh, stream->mem, reg_id,
+                             &glist[lo].term, mterm);
+           rset = rset_trunc(zh, &scan_info_array[j0].list[ptr[j0]].isam_p, 1,
+                             glist[lo].term, strlen(glist[lo].term),
+                             NULL, 0, zapt->term->which, rset_nmem, 
+                             kc, kc->scope);
+       }
+       ptr[j0]++; /* move index for this set .. */
+       /* get result set for remaining scan terms */
         for (j = j0+1; j<ord_no; j++)
         {
             if (ptr[j] < before+after && ptr[j] >= 0 &&
                 (tst = scan_info_array[j].list[ptr[j]].term) &&
                 !strcmp (tst, mterm))
             {
-                RSET rsets[2];
-               
-               rsets[0] = rset;
-                rsets[1] =
-                   rset_trunc(zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
-                              glist[i+before].term,
-                              strlen(glist[i+before].term), NULL, 0,
-                              zapt->term->which,rset_nmem,
-                              key_it_ctrl, key_it_ctrl->scope);
-                rset = rsmulti_or_create(rset_nmem, key_it_ctrl,
-                                        2, key_it_ctrl->scope, rsets);
+               if (lo >= 0)
+               {
+                   RSET rsets[2];
+                   
+                   rsets[0] = rset;
+                   rsets[1] =
+                       rset_trunc(
+                           zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
+                           glist[lo].term,
+                           strlen(glist[lo].term), NULL, 0,
+                           zapt->term->which,rset_nmem,
+                           kc, kc->scope);
+                   rset = rsmulti_or_create(rset_nmem, kc,
+                                            2, kc->scope, rsets);
+               }
                 ptr[j]++;
             }
         }
-        if (limit_set)
+       if (lo >= 0)
        {
-           RSET rsets[2];
-           rsets[0] = rset;
-           rsets[1] = rset_dup(limit_set);
-           
-           rset = rsmulti_and_create(rset_nmem, key_it_ctrl,
-                                     key_it_ctrl->scope, 2, rsets);
+           /* merge with limit_set if given */
+           if (limit_set)
+           {
+               RSET rsets[2];
+               rsets[0] = rset;
+               rsets[1] = rset_dup(limit_set);
+               
+               rset = rsmulti_and_create(rset_nmem, kc,
+                                         kc->scope, 2, rsets);
+           }
+           /* count it */
+           count_set(rset, &glist[lo].occurrences);
+           rset_delete(rset);
        }
-       count_set(rset, &glist[i+before].occurrences);
-       rset_delete(rset);
     }
     if (i < after)
     {
        *num_entries -= (after-i);
        *is_partial = 1;
+       if (*num_entries < 0)
+       {
+           (*kc->dec)(kc);
+           nmem_destroy(rset_nmem);
+           *num_entries = 0;
+           return ZEBRA_OK;
+       }
     }
     /* consider terms before main term */
     for (i = 0; i<ord_no; i++)
@@ -2948,6 +3016,7 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
        const char *mterm = NULL;
        const char *tst;
        RSET rset;
+       int lo = before-1-i; /* offset in result list */
        
        for (j = 0; j <ord_no; j++)
        {
@@ -2963,13 +3032,13 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
            break;
        
        scan_term_untrans (zh, stream->mem, reg_id,
-                          &glist[before-1-i].term, mterm);
+                          &glist[lo].term, mterm);
        
        rset = rset_trunc
            (zh, &scan_info_array[j0].list[before-1-ptr[j0]].isam_p, 1,
-            glist[before-1-i].term, strlen(glist[before-1-i].term),
+            glist[lo].term, strlen(glist[lo].term),
             NULL, 0, zapt->term->which,rset_nmem,
-            key_it_ctrl,key_it_ctrl->scope);
+            kc, kc->scope);
        
        ptr[j0]++;
        
@@ -2985,12 +3054,12 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
                rsets[1] = rset_trunc(
                    zh,
                    &scan_info_array[j].list[before-1-ptr[j]].isam_p, 1,
-                   glist[before-1-i].term,
-                   strlen(glist[before-1-i].term), NULL, 0,
+                   glist[lo].term,
+                   strlen(glist[lo].term), NULL, 0,
                    zapt->term->which, rset_nmem,
-                   key_it_ctrl, key_it_ctrl->scope);
-               rset = rsmulti_or_create(rset_nmem, key_it_ctrl,
-                                        2, key_it_ctrl->scope, rsets);
+                   kc, kc->scope);
+               rset = rsmulti_or_create(rset_nmem, kc,
+                                        2, kc->scope, rsets);
                
                ptr[j]++;
            }
@@ -3001,21 +3070,27 @@ ZEBRA_RES rpn_scan(ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
            rsets[0] = rset;
            rsets[1] = rset_dup(limit_set);
            
-           rset = rsmulti_and_create(rset_nmem, key_it_ctrl,
-                                     key_it_ctrl->scope, 2, rsets);
+           rset = rsmulti_and_create(rset_nmem, kc,
+                                     kc->scope, 2, rsets);
        }
-       count_set (rset, &glist[before-1-i].occurrences);
+       count_set (rset, &glist[lo].occurrences);
        rset_delete (rset);
     }
+    (*kc->dec)(kc);
+    nmem_destroy(rset_nmem);
     i = before-i;
     if (i)
     {
         *is_partial = 1;
         *position -= i;
         *num_entries -= i;
+       if (*num_entries <= 0)
+       {
+           *num_entries = 0;
+           return ZEBRA_OK;
+       }
     }
     
-    nmem_destroy(rset_nmem);
     *list = glist + i;               /* list is set to first 'real' entry */
     
     yaz_log(YLOG_DEBUG, "position = %d, num_entries = %d",