More XPATH work; common sequence numbers for extract keys
[idzebra-moved-to-github.git] / index / zrpn.c
index 6bc4537..78f6180 100644 (file)
@@ -3,7 +3,7 @@
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss
  *
- * $Id: zrpn.c,v 1.111 2002-03-21 10:25:42 adam Exp $
+ * $Id: zrpn.c,v 1.115 2002-04-13 18:16:43 adam Exp $
  */
 #include <stdio.h>
 #include <assert.h>
 #endif
 #include <ctype.h>
 
-#include "zserver.h"
+#include "index.h"
 
 #include <charmap.h>
 #include <rstemp.h>
 #include <rsnull.h>
 #include <rsbool.h>
+#include <rsbetween.h>
 
 struct rpn_char_map_info {
     ZebraMaps zm;
@@ -32,12 +33,12 @@ static const char **rpn_char_map_handler (void *vp, const char **from, int len)
     return zebra_maps_input (p->zm, p->reg_type, from, len);
 }
 
-static void rpn_char_map_prepare (ZebraHandle zh, int reg_type,
+static void rpn_char_map_prepare (struct zebra_register *reg, int reg_type,
                                  struct rpn_char_map_info *map_info)
 {
-    map_info->zm = zh->service->zebra_maps;
+    map_info->zm = reg->zebra_maps;
     map_info->reg_type = reg_type;
-    dict_grep_cmap (zh->service->dict, map_info, rpn_char_map_handler);
+    dict_grep_cmap (reg->dict, map_info, rpn_char_map_handler);
 }
 
 typedef struct {
@@ -84,17 +85,17 @@ static int attr_find_ex (AttrType *src, oid_value *attributeSetP,
             case Z_AttributeValue_complex:
                 if (src->minor >= element->value.complex->num_list)
                    break;
+                if (element->attributeSet && attributeSetP)
+                {
+                    oident *attrset;
+                    
+                    attrset = oid_getentbyoid (element->attributeSet);
+                    *attributeSetP = attrset->value;
+                }
                 if (element->value.complex->list[src->minor]->which ==  
                     Z_StringOrNumeric_numeric)
                {
                    ++(src->minor);
-                   if (element->attributeSet && attributeSetP)
-                   {
-                       oident *attrset;
-                       
-                       attrset = oid_getentbyoid (element->attributeSet);
-                       *attributeSetP = attrset->value;
-                   }
                    return
                        *element->value.complex->list[src->minor-1]->u.numeric;
                }
@@ -152,7 +153,7 @@ static void term_untrans  (ZebraHandle zh, int reg_type,
 {
     while (*src)
     {
-        const char *cp = zebra_maps_output (zh->service->zebra_maps,
+        const char *cp = zebra_maps_output (zh->reg->zebra_maps,
                                            reg_type, &src);
        if (!cp)
            *dst++ = *src++;
@@ -209,7 +210,7 @@ static void add_isam_p (const char *name, const char *info,
        
        term_untrans  (p->zh, p->reg_type, term_tmp, name+len+1);
        logf (LOG_LOG, "grep: %d %c %s", su_code, name[len], term_tmp);
-       zebraExplain_lookup_ord (p->zh->service->zei,
+       zebraExplain_lookup_ord (p->zh->reg->zei,
                                 su_code, &db, &set, &use);
        logf (LOG_LOG, "grep:  set=%d use=%d db=%s", set, use, db);
        
@@ -656,7 +657,7 @@ static int string_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     switch (relation_value)
     {
     case 1:
-        if (!term_100 (zh->service->zebra_maps, reg_type,
+        if (!term_100 (zh->reg->zebra_maps, reg_type,
                       term_sub, term_component,
                       space_split, term_dst))
             return 0;
@@ -686,7 +687,7 @@ static int string_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
        *term_tmp = '\0';
         break;
     case 2:
-        if (!term_100 (zh->service->zebra_maps, reg_type,
+        if (!term_100 (zh->reg->zebra_maps, reg_type,
                       term_sub, term_component,
                       space_split, term_dst))
             return 0;
@@ -717,7 +718,7 @@ static int string_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
        *term_tmp = '\0';
         break;
     case 5:
-        if (!term_100 (zh->service->zebra_maps, reg_type,
+        if (!term_100 (zh->reg->zebra_maps, reg_type,
                       term_sub, term_component, space_split, term_dst))
             return 0;
         logf (LOG_DEBUG, "Relation >");
@@ -749,7 +750,7 @@ static int string_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
        *term_tmp = '\0';
         break;
     case 4:
-        if (!term_100 (zh->service->zebra_maps, reg_type, term_sub,
+        if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub,
                       term_component, space_split, term_dst))
             return 0;
         logf (LOG_DEBUG, "Relation >=");
@@ -786,7 +787,7 @@ static int string_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     case 3:
     default:
         logf (LOG_DEBUG, "Relation =");
-        if (!term_100 (zh->service->zebra_maps, reg_type, term_sub,
+        if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub,
                       term_component, space_split, term_dst))
             return 0;
        strcat (term_tmp, "(");
@@ -797,12 +798,43 @@ static int string_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
 }
 
 static int string_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
-                       const char **term_sub, 
-                       oid_value attributeSet, NMEM stream,
-                       struct grep_info *grep_info,
-                       int reg_type, int complete_flag,
-                       int num_bases, char **basenames,
-                       char *term_dst)
+                        const char **term_sub, 
+                        oid_value attributeSet, NMEM stream,
+                        struct grep_info *grep_info,
+                        int reg_type, int complete_flag,
+                        int num_bases, char **basenames,
+                        char *term_dst);
+
+static RSET term_trunc (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
+                        const char **term_sub, 
+                        oid_value attributeSet, NMEM stream,
+                        struct grep_info *grep_info,
+                        int reg_type, int complete_flag,
+                        int num_bases, char **basenames,
+                        char *term_dst,
+                        const char *rank_type)
+{
+    int r;
+    grep_info->isam_p_indx = 0;
+    r = string_term (zh, zapt, term_sub, attributeSet, stream, grep_info,
+                     reg_type, complete_flag, num_bases, basenames,
+                     term_dst);
+    if (r < 1)
+        return 0;
+    logf (LOG_DEBUG, "term: %s", term_dst);
+    return rset_trunc (zh, grep_info->isam_p_buf,
+                       grep_info->isam_p_indx, term_dst,
+                       strlen(term_dst), rank_type, 1 /* preserve pos */);
+}
+
+
+static int string_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
+                        const char **term_sub, 
+                        oid_value attributeSet, NMEM stream,
+                        struct grep_info *grep_info,
+                        int reg_type, int complete_flag,
+                        int num_bases, char **basenames,
+                        char *term_dst)
 {
     char term_dict[2*IT_MAX_WORD+4000];
     int j, r, base_no;
@@ -810,93 +842,108 @@ static int string_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     int truncation_value;
     AttrType use;
     int use_value;
+    const char *use_string = 0;
     oid_value curAttributeSet = attributeSet;
     const char *termp;
     struct rpn_char_map_info rcmi;
     int space_split = complete_flag ? 0 : 1;
 
-    rpn_char_map_prepare (zh, reg_type, &rcmi);
+    rpn_char_map_prepare (zh->reg, reg_type, &rcmi);
     attr_init (&use, zapt, 1);
-    use_value = attr_find (&use, &curAttributeSet);
+    use_value = attr_find_ex (&use, &curAttributeSet, &use_string);
     logf (LOG_DEBUG, "string_term, use value %d", use_value);
     attr_init (&truncation, zapt, 5);
     truncation_value = attr_find (&truncation, NULL);
     logf (LOG_DEBUG, "truncation value %d", truncation_value);
 
-    if (use_value == -1)
+    if (use_value == -1)    /* no attribute - assumy "any" */
+        use_value = 1016;
+    if (use_value == -2)    /* string attribute - assumy "any" */
         use_value = 1016;
 
     for (base_no = 0; base_no < num_bases; base_no++)
     {
         attent attp;
+        data1_local_attribute id_xpath_attr;
         data1_local_attribute *local_attr;
         int max_pos, prefix_len = 0;
 
         termp = *term_sub;
-        if ((r=att_getentbyatt (zh, &attp, curAttributeSet, use_value)))
-        {
-            logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
-                  curAttributeSet, use_value, r);
-           if (r == -1)
-           {
-               char val_str[32];
-               sprintf (val_str, "%d", use_value);
-               zh->errCode = 114;
-               zh->errString = nmem_strdup (stream, val_str);
-           }
-           else
-           {
-               int oid[OID_SIZE];
-               struct oident oident;
-
-               oident.proto = PROTO_Z3950;
-               oident.oclass = CLASS_ATTSET;
-               oident.value = curAttributeSet;
-               oid_ent_to_oid (&oident, oid);
 
-               zh->errCode = 121;
-               zh->errString = nmem_strdup (stream, oident.desc);
-           }
-            return -1;
-        }
-        if (zebraExplain_curDatabase (zh->service->zei, basenames[base_no]))
+        if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
         {
             zh->errCode = 109; /* Database unavailable */
             zh->errString = basenames[base_no];
             return -1;
         }
+        if (curAttributeSet == VAL_IDXPATH)
+        {
+            attp.local_attributes = &id_xpath_attr;
+            attp.attset_ordinal = curAttributeSet;
+            id_xpath_attr.next = 0;
+            id_xpath_attr.local = use_value;
+        }
+        else
+        {
+            if ((r=att_getentbyatt (zh, &attp, curAttributeSet, use_value)))
+            {
+                logf (LOG_DEBUG, "att_getentbyatt fail. set=%d use=%d r=%d",
+                      curAttributeSet, use_value, r);
+                if (r == -1)
+                {
+                    char val_str[32];
+                    sprintf (val_str, "%d", use_value);
+                    zh->errCode = 114;
+                    zh->errString = nmem_strdup (stream, val_str);
+                }
+                else
+                {
+                    int oid[OID_SIZE];
+                    struct oident oident;
+                    
+                    oident.proto = PROTO_Z3950;
+                    oident.oclass = CLASS_ATTSET;
+                    oident.value = curAttributeSet;
+                    oid_ent_to_oid (&oident, oid);
+                    
+                    zh->errCode = 121;
+                    zh->errString = nmem_strdup (stream, oident.desc);
+                }
+                return -1;
+            }
+        }
         for (local_attr = attp.local_attributes; local_attr;
              local_attr = local_attr->next)
         {
             int ord;
-           char ord_buf[32];
-           int i, ord_len;
-
-            ord = zebraExplain_lookupSU (zh->service->zei, attp.attset_ordinal,
-                                          local_attr->local);
+            char ord_buf[32];
+            int i, ord_len;
+            
+            ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
+                                         local_attr->local);
             if (ord < 0)
                 continue;
             if (prefix_len)
                 term_dict[prefix_len++] = '|';
             else
                 term_dict[prefix_len++] = '(';
-
-           ord_len = key_SU_encode (ord, ord_buf);
-           for (i = 0; i<ord_len; i++)
-           {
-               term_dict[prefix_len++] = 1;
-               term_dict[prefix_len++] = ord_buf[i];
-           }
+            
+            ord_len = key_SU_encode (ord, ord_buf);
+            for (i = 0; i<ord_len; i++)
+            {
+                term_dict[prefix_len++] = 1;
+                term_dict[prefix_len++] = ord_buf[i];
+            }
         }
         if (!prefix_len)
         {
-           char val_str[32];
-           sprintf (val_str, "%d", use_value);
-           zh->errCode = 114;
-           zh->errString = nmem_strdup (stream, val_str);
+            char val_str[32];
+            sprintf (val_str, "%d", use_value);
+            zh->errCode = 114;
+            zh->errString = nmem_strdup (stream, val_str);
             return -1;
         }
-        term_dict[prefix_len++] = ')';        
+        term_dict[prefix_len++] = ')';
         term_dict[prefix_len++] = 1;
         term_dict[prefix_len++] = reg_type;
        logf (LOG_DEBUG, "reg_type = %d", term_dict[prefix_len-1]);
@@ -911,59 +958,59 @@ static int string_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                                  reg_type, space_split, term_dst))
                return 0;
            logf (LOG_DEBUG, "dict_lookup_grep: %s", term_dict+prefix_len);
-           r = dict_lookup_grep (zh->service->dict, term_dict, 0,
+           r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
                                  grep_info, &max_pos, 0, grep_handle);
            if (r)
                logf (LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
            break;
        case 1:          /* right truncation */
            term_dict[j++] = '(';
-           if (!term_100 (zh->service->zebra_maps, reg_type,
+           if (!term_100 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, space_split, term_dst))
                return 0;
            strcat (term_dict, ".*)");
-           dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info,
+           dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
                              &max_pos, 0, grep_handle);
            break;
        case 2:          /* keft truncation */
            term_dict[j++] = '('; term_dict[j++] = '.'; term_dict[j++] = '*';
-           if (!term_100 (zh->service->zebra_maps, reg_type,
+           if (!term_100 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, space_split, term_dst))
                return 0;
            strcat (term_dict, ")");
-           dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info,
+           dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
                              &max_pos, 0, grep_handle);
            break;
        case 3:          /* left&right truncation */
            term_dict[j++] = '('; term_dict[j++] = '.'; term_dict[j++] = '*';
-           if (!term_100 (zh->service->zebra_maps, reg_type,
+           if (!term_100 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, space_split, term_dst))
                return 0;
            strcat (term_dict, ".*)");
-           dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info,
+           dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
                              &max_pos, 0, grep_handle);
            break;
            zh->errCode = 120;
            return -1;
        case 101:        /* process # in term */
            term_dict[j++] = '(';
-           if (!term_101 (zh->service->zebra_maps, reg_type,
+           if (!term_101 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, space_split, term_dst))
                return 0;
            strcat (term_dict, ")");
-           r = dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info,
+           r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
                                  &max_pos, 0, grep_handle);
            if (r)
                logf (LOG_WARN, "dict_lookup_grep err, trunc=#: %d", r);
            break;
        case 102:        /* Regexp-1 */
            term_dict[j++] = '(';
-           if (!term_102 (zh->service->zebra_maps, reg_type,
+           if (!term_102 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, space_split, term_dst))
                return 0;
            strcat (term_dict, ")");
            logf (LOG_DEBUG, "Regexp-1 tolerance=%d", r);
-           r = dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info,
+           r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
                                  &max_pos, 0, grep_handle);
            if (r)
                logf (LOG_WARN, "dict_lookup_grep err, trunc=regular: %d",
@@ -972,12 +1019,12 @@ static int string_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
        case 103:       /* Regexp-2 */
            r = 1;
            term_dict[j++] = '(';
-           if (!term_103 (zh->service->zebra_maps, reg_type,
+           if (!term_103 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, &r, space_split, term_dst))
                return 0;
            strcat (term_dict, ")");
            logf (LOG_DEBUG, "Regexp-2 tolerance=%d", r);
-           r = dict_lookup_grep (zh->service->dict, term_dict, r, grep_info,
+           r = dict_lookup_grep (zh->reg->dict, term_dict, r, grep_info,
                                  &max_pos, 2, grep_handle);
            if (r)
                logf (LOG_WARN, "dict_lookup_grep err, trunc=eregular: %d",
@@ -985,33 +1032,33 @@ static int string_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
            break;
        case 104:        /* process # and ! in term */
            term_dict[j++] = '(';
-           if (!term_104 (zh->service->zebra_maps, reg_type,
+           if (!term_104 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, space_split, term_dst))
                return 0;
            strcat (term_dict, ")");
-           r = dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info,
+           r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
                                  &max_pos, 0, grep_handle);
            if (r)
                logf (LOG_WARN, "dict_lookup_grep err, trunc=#/!: %d", r);
            break;
        case 105:        /* process * and ! in term */
            term_dict[j++] = '(';
-           if (!term_105 (zh->service->zebra_maps, reg_type,
+           if (!term_105 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, space_split, term_dst, 1))
                return 0;
            strcat (term_dict, ")");
-           r = dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info,
+           r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
                                  &max_pos, 0, grep_handle);
            if (r)
                logf (LOG_WARN, "dict_lookup_grep err, trunc=*/!: %d", r);
            break;
        case 106:        /* process * and ! in term */
            term_dict[j++] = '(';
-           if (!term_105 (zh->service->zebra_maps, reg_type,
+           if (!term_105 (zh->reg->zebra_maps, reg_type,
                           &termp, term_dict + j, space_split, term_dst, 0))
                return 0;
            strcat (term_dict, ")");
-           r = dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info,
+           r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info,
                                  &max_pos, 0, grep_handle);
            if (r)
                logf (LOG_WARN, "dict_lookup_grep err, trunc=*/!: %d", r);
@@ -1050,7 +1097,7 @@ static void trans_scan_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     
     while ((len = (cp_end - cp)) > 0)
     {
-        map = zebra_maps_input (zh->service->zebra_maps, reg_type, &cp, len);
+        map = zebra_maps_input (zh->reg->zebra_maps, reg_type, &cp, len);
         if (**map == *CHR_SPACE)
             space_map = *map;
         else
@@ -1138,7 +1185,7 @@ static RSET rpn_prox (ZebraHandle zh, RSET *rset, int rset_no,
        parms.rset_term->nn = min_nn;
         parms.cmp = key_compare_it;
        parms.key_size = sizeof (struct it_key);
-       parms.temp_path = res_get (zh->service->res, "setTmpDir");
+       parms.temp_path = res_get (zh->res, "setTmpDir");
        result = rset_create (rset_kind_temp, &parms);
        rsfd_result = rset_open (result, RSETF_WRITE);
        
@@ -1197,7 +1244,7 @@ static RSET rpn_prox (ZebraHandle zh, RSET *rset, int rset_no,
        parms.rset_term->nn = min_nn;
         parms.cmp = key_compare_it;
        parms.key_size = sizeof (struct it_key);
-       parms.temp_path = res_get (zh->service->res, "setTmpDir");
+       parms.temp_path = res_get (zh->res, "setTmpDir");
        result = rset_create (rset_kind_temp, &parms);
        rsfd_result = rset_open (result, RSETF_WRITE);
 
@@ -1321,7 +1368,7 @@ char *normalize_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
        break;
     }
     if (ex_list)
-       wrbuf = zebra_replace(zh->service->zebra_maps, reg_id, ex_list,
+       wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, ex_list,
                              termz, strlen(termz));
     if (!wrbuf)
        return nmem_strdup(stream, termz);
@@ -1334,6 +1381,14 @@ char *normalize_term(ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     }
 }
 
+static void grep_info_delete (struct grep_info *grep_info)
+{
+#ifdef TERM_COUNT
+    xfree(grep_info->term_no);
+#endif
+    xfree (grep_info->isam_p_buf);
+}
+
 static int grep_info_prepare (ZebraHandle zh,
                              Z_AttributesPlusTerm *zapt,
                              struct grep_info *grep_info,
@@ -1392,7 +1447,7 @@ static RSET rpn_search_APT_phrase (ZebraHandle zh,
 {
     char term_dst[IT_MAX_WORD+1];
     RSET rset[60], result;
-    int i, r, rset_no = 0;
+    int i, rset_no = 0;
     struct grep_info grep_info;
     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
     const char *termp = termz;
@@ -1403,24 +1458,17 @@ static RSET rpn_search_APT_phrase (ZebraHandle zh,
     while (1)
     { 
        logf (LOG_DEBUG, "APT_phrase termp=%s", termp);
-       grep_info.isam_p_indx = 0;
-        r = string_term (zh, zapt, &termp, attributeSet, stream, &grep_info,
-                       reg_type, complete_flag, num_bases, basenames,
-                       term_dst);
-        if (r < 1)
+        rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
+                                    stream, &grep_info,
+                                    reg_type, complete_flag,
+                                    num_bases, basenames,
+                                    term_dst, rank_type);
+        if (!rset[rset_no])
             break;
-       logf (LOG_DEBUG, "term: %s", term_dst);
-        rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
-                                    grep_info.isam_p_indx, term_dst,
-                                   strlen(term_dst), rank_type);
-        assert (rset[rset_no]);
         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
             break;
     }
-#ifdef TERM_COUNT
-    xfree(grep_info.term_no);
-#endif
-    xfree (grep_info.isam_p_buf);
+    grep_info_delete (&grep_info);
     if (rset_no == 0)
     {
        rset_null_parms parms;
@@ -1447,7 +1495,7 @@ static RSET rpn_search_APT_or_list (ZebraHandle zh,
 {
     char term_dst[IT_MAX_WORD+1];
     RSET rset[60], result;
-    int i, r, rset_no = 0;
+    int i, rset_no = 0;
     struct grep_info grep_info;
     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
     const char *termp = termz;
@@ -1457,24 +1505,17 @@ static RSET rpn_search_APT_or_list (ZebraHandle zh,
     while (1)
     { 
        logf (LOG_DEBUG, "APT_or_list termp=%s", termp);
-       grep_info.isam_p_indx = 0;
-        r = string_term (zh, zapt, &termp, attributeSet, stream, &grep_info,
-                       reg_type, complete_flag, num_bases, basenames,
-                       term_dst);
-        if (r < 1)
+        rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
+                                    stream, &grep_info,
+                                    reg_type, complete_flag,
+                                    num_bases, basenames,
+                                    term_dst, rank_type);
+        if (!rset[rset_no])
             break;
-       logf (LOG_DEBUG, "term: %s", term_dst);
-        rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
-                                    grep_info.isam_p_indx, term_dst,
-                                   strlen(term_dst), rank_type);
-        assert (rset[rset_no]);
         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
             break;
     }
-#ifdef TERM_COUNT
-    xfree(grep_info.term_no);
-#endif
-    xfree (grep_info.isam_p_buf);
+    grep_info_delete (&grep_info);
     if (rset_no == 0)
     {
        rset_null_parms parms;
@@ -1507,7 +1548,7 @@ static RSET rpn_search_APT_and_list (ZebraHandle zh,
 {
     char term_dst[IT_MAX_WORD+1];
     RSET rset[60], result;
-    int i, r, rset_no = 0;
+    int i, rset_no = 0;
     struct grep_info grep_info;
     char *termz = normalize_term(zh, zapt, termz_org, stream, reg_type);
     const char *termp = termz;
@@ -1517,24 +1558,18 @@ static RSET rpn_search_APT_and_list (ZebraHandle zh,
     while (1)
     { 
        logf (LOG_DEBUG, "APT_and_list termp=%s", termp);
-       grep_info.isam_p_indx = 0;
-        r = string_term (zh, zapt, &termp, attributeSet, stream, &grep_info,
-                       reg_type, complete_flag, num_bases, basenames,
-                       term_dst);
-        if (r < 1)
+        rset[rset_no] = term_trunc (zh, zapt, &termp, attributeSet,
+                                    stream, &grep_info,
+                                    reg_type, complete_flag,
+                                    num_bases, basenames,
+                                    term_dst, rank_type);
+        if (!rset[rset_no])
             break;
-       logf (LOG_DEBUG, "term: %s", term_dst);
-        rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
-                                    grep_info.isam_p_indx, term_dst,
-                                   strlen(term_dst), rank_type);
         assert (rset[rset_no]);
         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
             break;
     }
-#ifdef TERM_COUNT
-    xfree(grep_info.term_no);
-#endif
-    xfree (grep_info.isam_p_buf);
+    grep_info_delete (&grep_info);
     if (rset_no == 0)
     {
        rset_null_parms parms;
@@ -1576,7 +1611,7 @@ static int numeric_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
 
     logf (LOG_DEBUG, "numeric relation value=%d", relation_value);
 
-    if (!term_100 (zh->service->zebra_maps, reg_type, term_sub, term_tmp, 1,
+    if (!term_100 (zh->reg->zebra_maps, reg_type, term_sub, term_tmp, 1,
                   term_dst))
        return 0;
     term_value = atoi (term_tmp);
@@ -1604,7 +1639,7 @@ static int numeric_relation (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
        sprintf (term_tmp, "(0*%d)", term_value);
     }
     logf (LOG_DEBUG, "dict_lookup_grep: %s", term_tmp);
-    r = dict_lookup_grep (zh->service->dict, term_dict, 0, grep_info, max_pos,
+    r = dict_lookup_grep (zh->reg->dict, term_dict, 0, grep_info, max_pos,
                           0, grep_handle);
     if (r)
         logf (LOG_WARN, "dict_lookup_grep fail, rel=gt: %d", r);
@@ -1627,7 +1662,7 @@ static int numeric_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     const char *termp;
     struct rpn_char_map_info rcmi;
 
-    rpn_char_map_prepare (zh, reg_type, &rcmi);
+    rpn_char_map_prepare (zh->reg, reg_type, &rcmi);
     attr_init (&use, zapt, 1);
     use_value = attr_find (&use, &curAttributeSet);
     logf (LOG_DEBUG, "numeric_term, use value %d", use_value);
@@ -1652,7 +1687,7 @@ static int numeric_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                zh->errCode = 121;
             return -1;
         }
-        if (zebraExplain_curDatabase (zh->service->zei, basenames[base_no]))
+        if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
         {
             zh->errCode = 109; /* Database unavailable */
             zh->errString = basenames[base_no];
@@ -1665,7 +1700,7 @@ static int numeric_term (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
            char ord_buf[32];
            int i, ord_len;
 
-            ord = zebraExplain_lookupSU (zh->service->zei, attp.attset_ordinal,
+            ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
                                           local_attr->local);
             if (ord < 0)
                 continue;
@@ -1730,15 +1765,13 @@ static RSET rpn_search_APT_numeric (ZebraHandle zh,
        logf (LOG_DEBUG, "term: %s", term_dst);
         rset[rset_no] = rset_trunc (zh, grep_info.isam_p_buf,
                                     grep_info.isam_p_indx, term_dst,
-                                   strlen(term_dst), rank_type);
+                                   strlen(term_dst), rank_type,
+                                    0 /* preserve position */);
         assert (rset[rset_no]);
         if (++rset_no >= (int) (sizeof(rset)/sizeof(*rset)))
             break;
     }
-#ifdef TERM_COUNT
-    xfree(grep_info.term_no);
-#endif
-    xfree (grep_info.isam_p_buf);
+    grep_info_delete (&grep_info);
     if (rset_no == 0)
     {
        rset_null_parms parms;
@@ -1774,7 +1807,7 @@ static RSET rpn_search_APT_local (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     parms.rset_term = rset_term_create (termz, -1, rank_type);
     parms.cmp = key_compare_it;
     parms.key_size = sizeof (struct it_key);
-    parms.temp_path = res_get (zh->service->res, "setTmpDir");
+    parms.temp_path = res_get (zh->res, "setTmpDir");
     result = rset_create (rset_kind_temp, &parms);
     rsfd = rset_open (result, RSETF_WRITE);
 
@@ -1888,6 +1921,136 @@ static RSET rpn_sort_spec (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     return rset_create (rset_kind_null, &parms);
 }
 
+static RSET rpn_search_xpath (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
+                              oid_value attributeSet,
+                              int num_bases, char **basenames,
+                              NMEM stream, const char *rank_type, RSET rset)
+{
+    AttrType use;
+    const char *use_string = 0;
+    oid_value curAttributeSet = attributeSet;
+    char term_dict[2048];
+    int base_no;
+    int reg_type = '0';
+    struct grep_info grep_info;
+
+    yaz_log (LOG_LOG, "rpn_search_xpath 1");
+    attr_init (&use, zapt, 1);
+    attr_find_ex (&use, &curAttributeSet, &use_string);
+
+    if (curAttributeSet != VAL_IDXPATH)
+    {
+        yaz_log (LOG_LOG, "rpn_search_xpath - not 1");
+        return rset;
+    }
+    if (!use_string)
+    {
+        yaz_log (LOG_LOG, "rpn_search_xpath - not 2");
+        return rset;
+    }
+
+    dict_grep_cmap (zh->reg->dict, 0, 0);
+    if (grep_info_prepare (zh, zapt, &grep_info, reg_type, stream))
+       return 0;
+
+    yaz_log (LOG_LOG, "rpn_search_xpath 2");
+    for (base_no = 0; base_no < num_bases; base_no++)
+    {
+        const char *termp = use_string;
+        rset_between_parms parms;
+        RSET rset_start_tag, rset_end_tag;
+        int ord, ord_len, i, r, max_pos;
+        int prefix_len ;
+        char ord_buf[32];
+        if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
+        {
+            zh->errCode = 109; /* Database unavailable */
+            zh->errString = basenames[base_no];
+            return rset;
+        }
+
+        prefix_len = 0;
+        ord = zebraExplain_lookupSU (zh->reg->zei, curAttributeSet, 1);
+        if (ord < 0)
+            continue;
+        if (prefix_len)
+            term_dict[prefix_len++] = '|';
+        else
+            term_dict[prefix_len++] = '(';
+        
+        ord_len = key_SU_encode (ord, ord_buf);
+        for (i = 0; i<ord_len; i++)
+        {
+            term_dict[prefix_len++] = 1;
+            term_dict[prefix_len++] = ord_buf[i];
+        }
+        term_dict[prefix_len++] = ')';
+        term_dict[prefix_len++] = 1;
+        term_dict[prefix_len++] = reg_type;
+
+        termp = use_string;
+        strcpy (term_dict+prefix_len, use_string);
+        
+        grep_info.isam_p_indx = 0;
+        yaz_log (LOG_LOG, "rpn_search_xpath 3 %s", term_dict+prefix_len);
+        r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
+                              &grep_info, &max_pos, 0, grep_handle);
+        yaz_log (LOG_LOG, "%s %d positions", use_string,
+                 grep_info.isam_p_indx);
+        rset_start_tag =
+            rset_trunc (zh, grep_info.isam_p_buf,
+                        grep_info.isam_p_indx, use_string, strlen(use_string),
+                        rank_type, 1);
+
+        prefix_len = 0;
+        ord = zebraExplain_lookupSU (zh->reg->zei, curAttributeSet, 2);
+        if (ord < 0)
+            continue;
+        if (prefix_len)
+            term_dict[prefix_len++] = '|';
+        else
+            term_dict[prefix_len++] = '(';
+        
+        ord_len = key_SU_encode (ord, ord_buf);
+        for (i = 0; i<ord_len; i++)
+        {
+            term_dict[prefix_len++] = 1;
+            term_dict[prefix_len++] = ord_buf[i];
+        }
+        term_dict[prefix_len++] = ')';
+        term_dict[prefix_len++] = 1;
+        term_dict[prefix_len++] = reg_type;
+
+        termp = use_string;
+
+        strcpy (term_dict+prefix_len, use_string);
+
+        grep_info.isam_p_indx = 0;
+        r = dict_lookup_grep (zh->reg->dict, term_dict, 0,
+                              &grep_info, &max_pos, 0, grep_handle);
+
+        yaz_log (LOG_LOG, "%s %d positions", use_string,
+                 grep_info.isam_p_indx);
+        rset_end_tag =
+            rset_trunc (zh, grep_info.isam_p_buf,
+                        grep_info.isam_p_indx, use_string, strlen(use_string),
+                        rank_type, 1);
+
+        parms.key_size = sizeof(struct it_key);
+        parms.cmp = key_compare_it;
+        parms.rset_l = rset_start_tag;
+        parms.rset_m = rset;
+        parms.rset_r = rset_end_tag;
+        parms.printer = key_print_it;
+        yaz_log (LOG_LOG, "rpn_search_xpath 4");
+        rset = rset_create (rset_kind_between, &parms);
+    }
+    grep_info_delete (&grep_info);
+
+    return rset;
+}
+
+
 
 static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
                             oid_value attributeSet, NMEM stream,
@@ -1900,8 +2063,9 @@ static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
     int complete_flag;
     int sort_flag;
     char termz[IT_MAX_WORD+1];
+    RSET rset = 0;
 
-    zebra_maps_attr (zh->service->zebra_maps, zapt, &reg_id, &search_type,
+    zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
                     rank_type, &complete_flag, &sort_flag);
     
     logf (LOG_DEBUG, "reg_id=%c", reg_id);
@@ -1922,35 +2086,37 @@ static RSET rpn_search_APT (ZebraHandle zh, Z_AttributesPlusTerm *zapt,
 
     if (!strcmp (search_type, "phrase"))
     {
-       return rpn_search_APT_phrase (zh, zapt, termz, attributeSet, stream,
+       rset = rpn_search_APT_phrase (zh, zapt, termz, attributeSet, stream,
                                      reg_id, complete_flag, rank_type,
                                      num_bases, basenames);
     }
     else if (!strcmp (search_type, "and-list"))
     {
-       return rpn_search_APT_and_list (zh, zapt, termz, attributeSet, stream,
+       rset = rpn_search_APT_and_list (zh, zapt, termz, attributeSet, stream,
                                        reg_id, complete_flag, rank_type,
                                        num_bases, basenames);
     }
     else if (!strcmp (search_type, "or-list"))
     {
-       return rpn_search_APT_or_list (zh, zapt, termz, attributeSet, stream,
+       rset = rpn_search_APT_or_list (zh, zapt, termz, attributeSet, stream,
                                       reg_id, complete_flag, rank_type,
                                       num_bases, basenames);
     }
     else if (!strcmp (search_type, "local"))
     {
-        return rpn_search_APT_local (zh, zapt, termz, attributeSet, stream,
+        rset = rpn_search_APT_local (zh, zapt, termz, attributeSet, stream,
                                     rank_type);
     }
     else if (!strcmp (search_type, "numeric"))
     {
-       return rpn_search_APT_numeric (zh, zapt, termz, attributeSet, stream,
+       rset = rpn_search_APT_numeric (zh, zapt, termz, attributeSet, stream,
                                       reg_id, complete_flag, rank_type,
                                       num_bases, basenames);
     }
-    zh->errCode = 118;
-    return NULL;
+    else
+        zh->errCode = 118;
+    return rpn_search_xpath (zh, zapt, attributeSet, num_bases, basenames,
+                             stream, rank_type, rset);
 }
 
 static RSET rpn_search_structure (ZebraHandle zh, Z_RPNStructure *zs,
@@ -2241,7 +2407,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
     attr_init (&use, zapt, 1);
     use_value = attr_find (&use, &attributeset);
 
-    if (zebra_maps_attr (zh->service->zebra_maps, zapt, &reg_id, &search_type,
+    if (zebra_maps_attr (zh->reg->zebra_maps, zapt, &reg_id, &search_type,
                         rank_type, &complete_flag, &sort_flag))
     {
        *num_entries = 0;
@@ -2269,7 +2435,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
            *num_entries = 0;
            return;
         }
-        if (zebraExplain_curDatabase (zh->service->zei, basenames[base_no]))
+        if (zebraExplain_curDatabase (zh->reg->zei, basenames[base_no]))
         {
             zh->errString = basenames[base_no];
            zh->errCode = 109; /* Database unavailable */
@@ -2281,7 +2447,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
         {
             int ord;
 
-            ord = zebraExplain_lookupSU (zh->service->zei, attp.attset_ordinal,
+            ord = zebraExplain_lookupSU (zh->reg->zei, attp.attset_ordinal,
                                         local_attr->local);
             if (ord > 0)
                 ords[ord_no++] = ord;
@@ -2305,7 +2471,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
         struct scan_info *scan_info = scan_info_array + i;
        struct rpn_char_map_info rcmi;
 
-       rpn_char_map_prepare (zh, reg_id, &rcmi);
+       rpn_char_map_prepare (zh->reg, reg_id, &rcmi);
 
         scan_info->before = before;
         scan_info->after = after;
@@ -2323,7 +2489,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
 
         trans_scan_term (zh, zapt, termz+prefix_len, reg_id);
                     
-        dict_scan (zh->service->dict, termz, &before_tmp, &after_tmp,
+        dict_scan (zh->reg->dict, termz, &before_tmp, &after_tmp,
                   scan_info, scan_handle);
     }
     glist = (ZebraScanEntry *)
@@ -2357,7 +2523,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
                           &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);
+                          NULL, 0);
 
         ptr[j0]++;
         for (j = j0+1; j<ord_no; j++)
@@ -2372,7 +2538,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
                 rset2 =
                    rset_trunc (zh, &scan_info_array[j].list[ptr[j]].isam_p, 1,
                               glist[i+before].term,
-                              strlen(glist[i+before].term), NULL);
+                              strlen(glist[i+before].term), NULL, 0);
 
                 bool_parms.key_size = sizeof(struct it_key);
                 bool_parms.cmp = key_compare_it;
@@ -2423,7 +2589,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
         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),
-               NULL);
+               NULL, 0);
 
         ptr[j0]++;
 
@@ -2439,7 +2605,7 @@ void rpn_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
                 rset2 = 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);
+                                   strlen(glist[before-1-i].term), NULL, 0);
 
                 bool_parms.key_size = sizeof(struct it_key);
                 bool_parms.cmp = key_compare_it;