nmake: align with pazpar2 WRT icu/libxslt
[idzebra-moved-to-github.git] / index / zinfo.c
index 2e6dae9..1e30ca0 100644 (file)
@@ -1,62 +1,43 @@
-/*
- * Copyright (C) 1994-1998, Index Data I/S 
- * All rights reserved.
- * Sebastian Hammer, Adam Dickmeiss
- *
- * $Log: zinfo.c,v $
- * Revision 1.10  1998-06-08 14:43:15  adam
- * Added suport for EXPLAIN Proxy servers - added settings databasePath
- * and explainDatabase to facilitate this. Increased maximum number
- * of databases and attributes in one register.
- *
- * Revision 1.9  1998/06/02 12:10:27  adam
- * Fixed bug related to attributeDetails.
- *
- * Revision 1.8  1998/05/20 10:12:20  adam
- * Implemented automatic EXPLAIN database maintenance.
- * Modified Zebra to work with ASN.1 compiled version of YAZ.
- *
- * Revision 1.7  1998/03/05 08:45:13  adam
- * New result set model and modular ranking system. Moved towards
- * descent server API. System information stored as "SGML" records.
- *
- * Revision 1.6  1998/02/17 10:29:27  adam
- * Moved towards 'automatic' EXPLAIN database.
- *
- * Revision 1.5  1997/10/27 14:33:05  adam
- * Moved towards generic character mapping depending on "structure"
- * field in abstract syntax file. Fixed a few memory leaks. Fixed
- * bug with negative integers when doing searches with relational
- * operators.
- *
- * Revision 1.4  1997/09/25 14:57:08  adam
- * Added string.h.
- *
- * Revision 1.3  1996/05/22 08:21:59  adam
- * Added public ZebDatabaseInfo structure.
- *
- * Revision 1.2  1996/05/14 06:16:41  adam
- * Compact use/set bytes used in search service.
- *
- * Revision 1.1  1996/05/13 14:23:07  adam
- * Work on compaction of set/use bytes in dictionary.
- *
- */
+/* This file is part of the Zebra server.
+   Copyright (C) Index Data
 
 
-#include <stdlib.h>
+Zebra is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <sys/types.h>
 #include <assert.h>
 #include <assert.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
 
 #include <string.h>
 #include <time.h>
 
-#include <zebraver.h>
+#include <idzebra/version.h>
 #include "zinfo.h"
 
 #define ZINFO_DEBUG 0
 
 struct zebSUInfo {
 #include "zinfo.h"
 
 #define ZINFO_DEBUG 0
 
 struct zebSUInfo {
-    int set;
-    int use;
+    char *index_type;
+    zinfo_index_category_t cat;
+    char *str;
     int ordinal;
     int ordinal;
+    zint doc_occurrences;
+    zint term_occurrences;
 };
 
 struct zebSUInfoB {
 };
 
 struct zebSUInfoB {
@@ -67,7 +48,7 @@ struct zebSUInfoB {
 typedef struct zebAccessObjectB *zebAccessObject;
 struct zebAccessObjectB {
     void *handle;
 typedef struct zebAccessObjectB *zebAccessObject;
 struct zebAccessObjectB {
     void *handle;
-    int sysno;
+    zint sysno;
     Odr_oid *oid;
     zebAccessObject next;
 };
     Odr_oid *oid;
     zebAccessObject next;
 };
@@ -80,7 +61,7 @@ struct zebAccessInfoB {
 
 typedef struct {
     struct zebSUInfoB *SUInfo;
 
 typedef struct {
     struct zebSUInfoB *SUInfo;
-    int sysno;
+    zint sysno;
     int dirty;
     int readFlag;
     data1_node *data1_tree;
     int dirty;
     int readFlag;
     data1_node *data1_tree;
@@ -88,11 +69,12 @@ typedef struct {
 
 struct zebDatabaseInfoB {
     zebAttributeDetails attributeDetails;
 
 struct zebDatabaseInfoB {
     zebAttributeDetails attributeDetails;
+    int ordinalDatabase;
     char *databaseName;
     data1_node *data1_database;
     char *databaseName;
     data1_node *data1_database;
-    int recordCount;     /* records in db */
-    int recordBytes;     /* size of records */
-    int sysno;           /* sysno of database info */
+    zint recordCount;    /* records in db */
+    zint recordBytes;    /* size of records */
+    zint sysno;          /* sysno of database info */
     int readFlag;        /* 1: read is needed when referenced; 0 if not */
     int dirty;           /* 1: database is dirty: write is needed */
     struct zebDatabaseInfoB *next;
     int readFlag;        /* 1: read is needed when referenced; 0 if not */
     int dirty;           /* 1: database is dirty: write is needed */
     struct zebDatabaseInfoB *next;
@@ -105,241 +87,136 @@ struct zebraExplainAttset {
     struct zebraExplainAttset *next;
 };
 
     struct zebraExplainAttset *next;
 };
 
+struct zebraCategoryListInfo {
+    int dirty;
+    zint sysno;
+    data1_node *data1_categoryList;
+};
+
 struct zebraExplainInfo {
 struct zebraExplainInfo {
-    int  ordinalSU;
-    int  runNumber;
-    int  dirty;
+    int ordinalSU;
+    int ordinalDatabase;
+    zint runNumber;
+    int dirty;
+    int write_flag;
     Records records;
     data1_handle dh;
     Res res;
     struct zebraExplainAttset *attsets;
     NMEM nmem;
     data1_node *data1_target;
     Records records;
     data1_handle dh;
     Res res;
     struct zebraExplainAttset *attsets;
     NMEM nmem;
     data1_node *data1_target;
+    struct zebraCategoryListInfo *categoryList;
     struct zebDatabaseInfoB *databaseInfo;
     struct zebDatabaseInfoB *curDatabaseInfo;
     zebAccessInfo accessInfo;
     char date[15]; /* YYYY MMDD HH MM SS */
     struct zebDatabaseInfoB *databaseInfo;
     struct zebDatabaseInfoB *curDatabaseInfo;
     zebAccessInfo accessInfo;
     char date[15]; /* YYYY MMDD HH MM SS */
-    int (*updateFunc)(void *handle, Record drec, data1_node *n);
+    ZebraExplainUpdateFunc *updateFunc;
     void *updateHandle;
 };
 
     void *updateHandle;
 };
 
-static void zebraExplain_initCommonInfo (ZebraExplainInfo zei, data1_node *n);
-static void zebraExplain_initAccessInfo (ZebraExplainInfo zei, data1_node *n);
+static void zebraExplain_initCommonInfo(ZebraExplainInfo zei, data1_node *n);
+static void zebraExplain_initAccessInfo(ZebraExplainInfo zei, data1_node *n);
 
 
-static data1_node *read_sgml_rec (data1_handle dh, NMEM nmem, Record rec)
+static data1_node *read_sgml_rec(data1_handle dh, NMEM nmem, Record rec)
 {
 {
-    return data1_read_sgml (dh, nmem, rec->info[recInfo_storeData]);
+    return data1_read_sgml(dh, nmem, rec->info[recInfo_storeData]);
 }
 
 }
 
-static data1_node *data1_search_tag (data1_handle dh, data1_node *n,
-                                   const char *tag)
-{
-    logf (LOG_DEBUG, "data1_search_tag %s", tag);
-    for (; n; n = n->next)
-       if (n->which == DATA1N_tag && n->u.tag.tag &&
-           !yaz_matchstr (tag, n->u.tag.tag))
-       {
-           logf (LOG_DEBUG, " found");
-           return n;
-       }
-    logf (LOG_DEBUG, " not found");
-    return 0;
-}
-
-static data1_node *data1_add_tag (data1_handle dh, data1_node *at,
-                                 const char *tag, NMEM nmem)
-{
-    data1_node *partag = get_parent_tag(dh, at);
-    data1_node *res = data1_mk_node (dh, nmem);
-    data1_element *e = NULL;
-
-    res->parent = at;
-    res->which = DATA1N_tag;
-    res->u.tag.tag = data1_insert_string (dh, res, nmem, tag);
-    res->u.tag.node_selected = 0;
-    res->u.tag.make_variantlist = 0;
-    res->u.tag.no_data_requested = 0;
-    res->u.tag.get_bytes = -1;
-   
-    if (partag)
-       e = partag->u.tag.element;
-    res->u.tag.element =
-       data1_getelementbytagname (dh, at->root->u.root.absyn,
-                                  e, res->u.tag.tag);
-    res->root = at->root;
-    if (!at->child)
-       at->child = res;
-    else
-    {
-       assert (at->last_child);
-       at->last_child->next = res;
-    }
-    at->last_child = res;
-    return res;
-}
-
-static data1_node *data1_make_tag (data1_handle dh, data1_node *at,
-                                  const char *tag, NMEM nmem)
-{
-    data1_node *node = data1_search_tag (dh, at->child, tag);
-    if (!node)
-       node = data1_add_tag (dh, at, tag, nmem);
-    else
-       node->child = node->last_child = NULL;
-    return node;
-}
-
-static data1_node *data1_add_tagdata_int (data1_handle dh, data1_node *at,
-                                         const char *tag, int num,
-                                         NMEM nmem)
-{
-    data1_node *node_data;
-    
-    node_data = data1_add_taggeddata (dh, at->root, at, tag, nmem);
-    if (!node_data)
-       return 0;
-    node_data->u.data.what = DATA1I_num;
-    node_data->u.data.data = node_data->lbuf;
-    sprintf (node_data->u.data.data, "%d", num);
-    node_data->u.data.len = strlen (node_data->u.data.data);
-    return node_data;
-}
-
-static data1_node *data1_add_tagdata_oid (data1_handle dh, data1_node *at,
-                                          const char *tag, Odr_oid *oid,
-                                          NMEM nmem)
-{
-    data1_node *node_data;
-    char str[128], *p = str;
-    Odr_oid *ii;
-    
-    node_data = data1_add_taggeddata (dh, at->root, at, tag, nmem);
-    if (!node_data)
-       return 0;
-    
-    for (ii = oid; *ii >= 0; ii++)
-    {
-       if (ii != oid)
-           *p++ = '.';
-       sprintf (p, "%d", *ii);
-       p += strlen (p);
-    }
-    node_data->u.data.what = DATA1I_oid;
-    node_data->u.data.len = strlen (str);
-    node_data->u.data.data = data1_insert_string (dh, node_data, nmem, str);
-    return node_data;
-}
-
-
-static data1_node *data1_add_tagdata_text (data1_handle dh, data1_node *at,
-                                          const char *tag, const char *str,
-                                          NMEM nmem)
-{
-    data1_node *node_data;
-    
-    node_data = data1_add_taggeddata (dh, at->root, at, tag, nmem);
-    if (!node_data)
-       return 0;
-    node_data->u.data.what = DATA1I_text;
-    node_data->u.data.len = strlen (str);
-    node_data->u.data.data = data1_insert_string (dh, node_data, nmem, str);
-    return node_data;
-}
-
-static data1_node *data1_make_tagdata_text (data1_handle dh, data1_node *at,
-                                           const char *tag, const char *str,
-                                           NMEM nmem)
-{
-    data1_node *node = data1_search_tag (dh, at->child, tag);
-    if (!node)
-        return data1_add_tagdata_text (dh, at, tag, str, nmem);
-    else
-    {
-       data1_node *node_data = node->child;
-       node_data->u.data.what = DATA1I_text;
-       node_data->u.data.data = node_data->lbuf;
-       strcpy (node_data->u.data.data, str);
-       node_data->u.data.len = strlen (node_data->u.data.data);
-       return node_data;
-    }
-}
-
-static void zebraExplain_writeDatabase (ZebraExplainInfo zei,
+static void zebraExplain_writeDatabase(ZebraExplainInfo zei,
                                         struct zebDatabaseInfoB *zdi,
                                        int key_flush);
                                         struct zebDatabaseInfoB *zdi,
                                        int key_flush);
-static void zebraExplain_writeAttributeDetails (ZebraExplainInfo zei,
+static void zebraExplain_writeAttributeDetails(ZebraExplainInfo zei,
                                                zebAttributeDetails zad,
                                                const char *databaseName,
                                                int key_flush);
                                                zebAttributeDetails zad,
                                                const char *databaseName,
                                                int key_flush);
-static void zebraExplain_writeTarget (ZebraExplainInfo zei, int key_flush);
-static void zebraExplain_writeAttributeSet (ZebraExplainInfo zei,
+static void zebraExplain_writeTarget(ZebraExplainInfo zei, int key_flush);
+static void zebraExplain_writeAttributeSet(ZebraExplainInfo zei,
                                            zebAccessObject o,
                                            int key_flush);
                                            zebAccessObject o,
                                            int key_flush);
+static void zebraExplain_writeCategoryList(ZebraExplainInfo zei,
+                                           struct zebraCategoryListInfo *zcl,
+                                           int key_flush);
 
 
-static Record createRecord (Records records, int *sysno)
+
+static Record createRecord(Records records, zint *sysno)
 {
     Record rec;
     if (*sysno)
     {
 {
     Record rec;
     if (*sysno)
     {
-       rec = rec_get (records, *sysno);
-       xfree (rec->info[recInfo_storeData]);
+       rec = rec_get(records, *sysno);
+       if (!rec)
+           return 0;
+       xfree(rec->info[recInfo_storeData]);
     }
     else
     {
     }
     else
     {
-       rec = rec_new (records);
+       rec = rec_new(records);
+       if (!rec)
+           return 0;
        *sysno = rec->sysno;
        *sysno = rec->sysno;
-       
+
        rec->info[recInfo_fileType] =
        rec->info[recInfo_fileType] =
-           rec_strdup ("grs.sgml", &rec->size[recInfo_fileType]);
+           rec_strdup("grs.sgml", &rec->size[recInfo_fileType]);
        rec->info[recInfo_databaseName] =
        rec->info[recInfo_databaseName] =
-           rec_strdup ("IR-Explain-1",
-                       &rec->size[recInfo_databaseName]); 
+           rec_strdup("IR-Explain-1",
+                       &rec->size[recInfo_databaseName]);
     }
     return rec;
 }
 
     }
     return rec;
 }
 
-void zebraExplain_close (ZebraExplainInfo zei, int writeFlag,
-                        int (*updateH)(Record drec, data1_node *n))
+void zebraExplain_flush(ZebraExplainInfo zei, void *handle)
 {
 {
-    struct zebDatabaseInfoB *zdi;
-    
-    logf (LOG_DEBUG, "zebraExplain_close wr=%d", writeFlag);
-    if (writeFlag)
+    if (!zei)
+        return;
+    zei->updateHandle = handle;
+    if (zei->write_flag)
     {
     {
+       struct zebDatabaseInfoB *zdi;
        zebAccessObject o;
        zebAccessObject o;
+
        /* write each database info record */
        for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
        {
        /* write each database info record */
        for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
        {
-           zebraExplain_writeDatabase (zei, zdi, 1);
-           zebraExplain_writeAttributeDetails (zei, zdi->attributeDetails,
+           zebraExplain_writeDatabase(zei, zdi, 1);
+           zebraExplain_writeAttributeDetails(zei, zdi->attributeDetails,
                                                zdi->databaseName, 1);
        }
                                                zdi->databaseName, 1);
        }
-       zebraExplain_writeTarget (zei, 1);
-       
-       assert (zei->accessInfo);
+       zebraExplain_writeTarget(zei, 1);
+       zebraExplain_writeCategoryList(zei,
+                                       zei->categoryList,
+                                       1);
+       assert(zei->accessInfo);
        for (o = zei->accessInfo->attributeSetIds; o; o = o->next)
            if (!o->sysno)
        for (o = zei->accessInfo->attributeSetIds; o; o = o->next)
            if (!o->sysno)
-               zebraExplain_writeAttributeSet (zei, o, 1);
+               zebraExplain_writeAttributeSet(zei, o, 1);
        for (o = zei->accessInfo->schemas; o; o = o->next)
            if (!o->sysno)
            {
        for (o = zei->accessInfo->schemas; o; o = o->next)
            if (!o->sysno)
            {
-/*             zebraExplain_writeSchema (zei, o, 1); */
+/*             zebraExplain_writeSchema(zei, o, 1); */
            }
 
        for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
        {
            }
 
        for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
        {
-           zebraExplain_writeDatabase (zei, zdi, 0);
-           zebraExplain_writeAttributeDetails (zei, zdi->attributeDetails,
+           zebraExplain_writeDatabase(zei, zdi, 0);
+           zebraExplain_writeAttributeDetails(zei, zdi->attributeDetails,
                                                zdi->databaseName, 0);
        }
                                                zdi->databaseName, 0);
        }
-       zebraExplain_writeTarget (zei, 0);
-       
+       zebraExplain_writeTarget(zei, 0);
     }
     }
-    nmem_destroy (zei->nmem);
-    xfree (zei);
 }
 
 }
 
-void zebraExplain_mergeOids (ZebraExplainInfo zei, data1_node *n,
+void zebraExplain_close(ZebraExplainInfo zei)
+{
+#if ZINFO_DEBUG
+    yaz_log(YLOG_LOG, "zebraExplain_close");
+#endif
+    if (!zei)
+       return;
+    zebraExplain_flush(zei, zei->updateHandle);
+    nmem_destroy(zei->nmem);
+}
+
+void zebraExplain_mergeOids(ZebraExplainInfo zei, data1_node *n,
                             zebAccessObject *op)
 {
     data1_node *np;
                             zebAccessObject *op)
 {
     data1_node *np;
@@ -351,26 +228,26 @@ void zebraExplain_mergeOids (ZebraExplainInfo zei, data1_node *n,
        Odr_oid *oid;
        zebAccessObject ao;
 
        Odr_oid *oid;
        zebAccessObject ao;
 
-       if (np->which != DATA1N_tag || strcmp (np->u.tag.tag, "oid"))
+       if (np->which != DATA1N_tag || strcmp(np->u.tag.tag, "oid"))
            continue;
        len = np->child->u.data.len;
        if (len > 63)
            len = 63;
            continue;
        len = np->child->u.data.len;
        if (len > 63)
            len = 63;
-       memcpy (str, np->child->u.data.data, len);
+       memcpy(str, np->child->u.data.data, len);
        str[len] = '\0';
        str[len] = '\0';
-       
-       oid = odr_getoidbystr_nmem (zei->nmem, str);
+
+       oid = odr_getoidbystr_nmem(zei->nmem, str);
 
        for (ao = *op; ao; ao = ao->next)
 
        for (ao = *op; ao; ao = ao->next)
-           if (!oid_oidcmp (oid, ao->oid))
+           if (!oid_oidcmp(oid, ao->oid))
            {
                ao->sysno = 1;
                break;
            }
        if (!ao)
        {
            {
                ao->sysno = 1;
                break;
            }
        if (!ao)
        {
-           ao = nmem_malloc (zei->nmem, sizeof(*ao));
-           ao->handle = NULL;
+           ao = (zebAccessObject) nmem_malloc(zei->nmem, sizeof(*ao));
+           ao->handle = 0;
            ao->sysno = 1;
            ao->oid = oid;
            ao->next = *op;
            ao->sysno = 1;
            ao->oid = oid;
            ao->next = *op;
@@ -379,477 +256,792 @@ void zebraExplain_mergeOids (ZebraExplainInfo zei, data1_node *n,
     }
 }
 
     }
 }
 
-void zebraExplain_mergeAccessInfo (ZebraExplainInfo zei, data1_node *n,
+void zebraExplain_mergeAccessInfo(ZebraExplainInfo zei, data1_node *n,
                                   zebAccessInfo *accessInfo)
 {
     data1_node *np;
                                   zebAccessInfo *accessInfo)
 {
     data1_node *np;
-    
+
     if (!n)
     {
     if (!n)
     {
-       *accessInfo = nmem_malloc (zei->nmem, sizeof(**accessInfo));
-       (*accessInfo)->attributeSetIds = NULL;
-       (*accessInfo)->schemas = NULL;
+       *accessInfo = (zebAccessInfo)
+           nmem_malloc(zei->nmem, sizeof(**accessInfo));
+       (*accessInfo)->attributeSetIds = 0;
+       (*accessInfo)->schemas = 0;
     }
     else
     {
     }
     else
     {
-       if (!(n = data1_search_tag (zei->dh, n->child, "accessInfo")))
+       if (!(n = data1_search_tag(zei->dh, n->child, "accessInfo")))
            return;
            return;
-       if ((np = data1_search_tag (zei->dh, n->child, "attributeSetIds")))
-           zebraExplain_mergeOids (zei, np,
+       if ((np = data1_search_tag(zei->dh, n->child, "attributeSetIds")))
+           zebraExplain_mergeOids(zei, np,
                                    &(*accessInfo)->attributeSetIds);
                                    &(*accessInfo)->attributeSetIds);
-       if ((np = data1_search_tag (zei->dh, n->child, "schemas")))
-           zebraExplain_mergeOids (zei, np,
+       if ((np = data1_search_tag(zei->dh, n->child, "schemas")))
+           zebraExplain_mergeOids(zei, np,
                                    &(*accessInfo)->schemas);
     }
 }
 
                                    &(*accessInfo)->schemas);
     }
 }
 
-ZebraExplainInfo zebraExplain_open (
+/* Explain structure
+    root record
+      of type targetInfo
+      and has sysno = 1
+
+    databaseList (list of databases)
+*/
+/*
+Example root:
+explain:
+  targetInfo: TargetInfo
+    name: Zebra
+    namedResultSets: 1
+    multipleDbSearch: 1
+    nicknames:
+      name: Zebra
+    commonInfo:
+      dateAdded: 20030630190601
+      dateChanged: 20030630190601
+      languageCode: EN
+    accessinfo:
+      unitSystems:
+        string: ISO
+      attributeSetIds:
+        oid: 1.2.840.10003.3.2
+        oid: 1.2.840.10003.3.5
+        oid: 1.2.840.10003.3.1
+      schemas:
+        oid: 1.2.840.10003.13.1000.81.2
+        oid: 1.2.840.10003.13.2
+    zebraInfo:
+      version: 1.3.12
+      databaseList:
+        database:
+          name: Default
+          id: 50
+          attributeDetailsId: 51
+        database:
+          name: IR-Explain-1
+          id: 52
+          attributeDetailsId: 53
+      ordinalSU: 38
+      runNumber: 1
+nextResultSetPosition = 2
+*/
+
+ZebraExplainInfo zebraExplain_open(
     Records records, data1_handle dh,
     Res res,
     int writeFlag,
     void *updateHandle,
     Records records, data1_handle dh,
     Res res,
     int writeFlag,
     void *updateHandle,
-    int (*updateFunc)(void *handle, Record drec, data1_node *n))
+    ZebraExplainUpdateFunc *updateFunc)
 {
     Record trec;
     ZebraExplainInfo zei;
     struct zebDatabaseInfoB **zdip;
     time_t our_time;
     struct tm *tm;
 {
     Record trec;
     ZebraExplainInfo zei;
     struct zebDatabaseInfoB **zdip;
     time_t our_time;
     struct tm *tm;
+    NMEM nmem = nmem_create();
 
 
-    logf (LOG_DEBUG, "zebraExplain_open wr=%d", writeFlag);
-    zei = xmalloc (sizeof(*zei));
+#if ZINFO_DEBUG
+    yaz_log(YLOG_LOG, "zebraExplain_open wr=%d", writeFlag);
+#endif
+    zei = (ZebraExplainInfo) nmem_malloc(nmem, sizeof(*zei));
+    zei->databaseInfo = 0;
+    zei->write_flag = writeFlag;
     zei->updateHandle = updateHandle;
     zei->updateFunc = updateFunc;
     zei->dirty = 0;
     zei->updateHandle = updateHandle;
     zei->updateFunc = updateFunc;
     zei->dirty = 0;
-    zei->curDatabaseInfo = NULL;
+    zei->ordinalDatabase = 1;
+    zei->curDatabaseInfo = 0;
     zei->records = records;
     zei->records = records;
-    zei->nmem = nmem_create ();
+    zei->nmem = nmem;
     zei->dh = dh;
     zei->dh = dh;
-    zei->attsets = NULL;
-    zei->res = res;
 
 
-    time (&our_time);
-    tm = localtime (&our_time);
-    sprintf (zei->date, "%04d%02d%02d%02d%02d%02d",
-            tm->tm_year+1900, tm->tm_mon+1,  tm->tm_mday,
-            tm->tm_hour, tm->tm_min, tm->tm_sec);
+    data1_get_absyn(zei->dh, "explain", DATA1_XPATH_INDEXING_DISABLE);
 
 
+    zei->attsets = 0;
+    zei->res = res;
+    zei->categoryList = (struct zebraCategoryListInfo *)
+       nmem_malloc(zei->nmem, sizeof(*zei->categoryList));
+    zei->categoryList->sysno = 0;
+    zei->categoryList->dirty = 0;
+    zei->categoryList->data1_categoryList = 0;
+
+    if ( atoi(res_get_def(res, "notimestamps", "0") )== 0)
+    {
+        time(&our_time);
+        tm = localtime(&our_time);
+        sprintf(zei->date, "%04d%02d%02d%02d%02d%02d",
+                tm->tm_year+1900, tm->tm_mon+1,  tm->tm_mday,
+                tm->tm_hour, tm->tm_min, tm->tm_sec);
+    } else {
+        sprintf(zei->date, "%04d%02d%02d%02d%02d%02d",
+                0, 0, 0,  0, 0, 0);
+    }
     zdip = &zei->databaseInfo;
     zdip = &zei->databaseInfo;
-    trec = rec_get (records, 1);      /* get "root" record */
+    trec = rec_get_root(records);      /* get "root" record */
 
 
-    zebraExplain_mergeAccessInfo (zei, 0, &zei->accessInfo);
+    zei->ordinalSU = 1;
+    zei->runNumber = 0;
+
+    zebraExplain_mergeAccessInfo(zei, 0, &zei->accessInfo);
     if (trec)    /* targetInfo already exists ... */
     {
        data1_node *node_tgtinfo, *node_zebra, *node_list, *np;
 
     if (trec)    /* targetInfo already exists ... */
     {
        data1_node *node_tgtinfo, *node_zebra, *node_list, *np;
 
-       zei->data1_target = read_sgml_rec (zei->dh, zei->nmem, trec);
-
+       zei->data1_target = read_sgml_rec(zei->dh, zei->nmem, trec);
+#if 0
+       if (!zei->data1_target || !zei->data1_target->u.root.absyn)
+#else
+       if (!zei->data1_target)
+#endif
+       {
+           yaz_log(YLOG_FATAL, "Explain schema missing. Check profilePath");
+           nmem_destroy(zei->nmem);
+           return 0;
+       }
 #if ZINFO_DEBUG
 #if ZINFO_DEBUG
-       data1_pr_tree (zei->dh, zei->data1_target, stderr);
+       data1_pr_tree(zei->dh, zei->data1_target, stderr);
 #endif
 #endif
-       node_tgtinfo = data1_search_tag (zei->dh, zei->data1_target->child,
-                                        "targetInfo");
-       zebraExplain_mergeAccessInfo (zei, node_tgtinfo,
+       node_tgtinfo = data1_search_tag(zei->dh, zei->data1_target,
+                                        "/targetInfo");
+        if (!node_tgtinfo)
+        {
+           yaz_log(YLOG_FATAL, "Node node_tgtinfo missing");
+           nmem_destroy(zei->nmem);
+           return 0;
+        }
+       zebraExplain_mergeAccessInfo(zei, node_tgtinfo,
                                      &zei->accessInfo);
 
                                      &zei->accessInfo);
 
-       node_zebra = data1_search_tag (zei->dh, node_tgtinfo->child,
+       node_zebra = data1_search_tag(zei->dh, node_tgtinfo->child,
                                       "zebraInfo");
                                       "zebraInfo");
-       node_list = data1_search_tag (zei->dh, node_zebra->child,
-                                     "databaseList");
-       for (np = node_list->child; np; np = np->next)
+        if (!node_zebra)
+        {
+           yaz_log(YLOG_FATAL, "Node node_zebra missing");
+           nmem_destroy(zei->nmem);
+           return 0;
+        }
+       np = 0;
+       if (node_zebra)
        {
        {
-           data1_node *node_name = NULL;
-           data1_node *node_id = NULL;
-           data1_node *node_aid = NULL;
+           node_list = data1_search_tag(zei->dh, node_zebra->child,
+                                         "databaseList");
+           if (node_list)
+               np = node_list->child;
+       }
+       for(; np; np = np->next)
+       {
+           data1_node *node_name = 0;
+           data1_node *node_id = 0;
+           data1_node *node_aid = 0;
            data1_node *np2;
            data1_node *np2;
-           if (np->which != DATA1N_tag || strcmp (np->u.tag.tag, "database"))
+           if (np->which != DATA1N_tag || strcmp(np->u.tag.tag, "database"))
                continue;
                continue;
-           for (np2 = np->child; np2; np2 = np2->next)
+           for(np2 = np->child; np2; np2 = np2->next)
            {
                if (np2->which != DATA1N_tag)
                    continue;
            {
                if (np2->which != DATA1N_tag)
                    continue;
-               if (!strcmp (np2->u.tag.tag, "name"))
+               if (!strcmp(np2->u.tag.tag, "name"))
                    node_name = np2->child;
                    node_name = np2->child;
-               else if (!strcmp (np2->u.tag.tag, "id"))
+               else if (!strcmp(np2->u.tag.tag, "id"))
                    node_id = np2->child;
                    node_id = np2->child;
-               else if (!strcmp (np2->u.tag.tag, "attributeDetailsId"))
+               else if (!strcmp(np2->u.tag.tag, "attributeDetailsId"))
                    node_aid = np2->child;
            }
                    node_aid = np2->child;
            }
-           assert (node_id && node_name && node_aid);
-           
-           *zdip = nmem_malloc (zei->nmem, sizeof(**zdip));
+           assert(node_id && node_name && node_aid);
 
 
+           *zdip =(struct zebDatabaseInfoB *)
+               nmem_malloc(zei->nmem, sizeof(**zdip));
             (*zdip)->readFlag = 1;
             (*zdip)->dirty = 0;
             (*zdip)->readFlag = 1;
             (*zdip)->dirty = 0;
-           (*zdip)->data1_database = NULL;
+           (*zdip)->data1_database = 0;
            (*zdip)->recordCount = 0;
            (*zdip)->recordBytes = 0;
            (*zdip)->recordCount = 0;
            (*zdip)->recordBytes = 0;
-           zebraExplain_mergeAccessInfo (zei, 0, &(*zdip)->accessInfo);
+           zebraExplain_mergeAccessInfo(zei, 0, &(*zdip)->accessInfo);
 
 
-           (*zdip)->databaseName = nmem_malloc (zei->nmem,
-                                                1+node_name->u.data.len);
-           memcpy ((*zdip)->databaseName, node_name->u.data.data,
-                   node_name->u.data.len);
+           (*zdip)->databaseName = (char *)
+               nmem_malloc(zei->nmem, 1+node_name->u.data.len);
+           memcpy((*zdip)->databaseName, node_name->u.data.data,
+                  node_name->u.data.len);
            (*zdip)->databaseName[node_name->u.data.len] = '\0';
            (*zdip)->databaseName[node_name->u.data.len] = '\0';
-           (*zdip)->sysno = atoi_n (node_id->u.data.data,
-                                    node_id->u.data.len);
-           (*zdip)->attributeDetails =
-               nmem_malloc (zei->nmem, sizeof(*(*zdip)->attributeDetails));
-           (*zdip)->attributeDetails->sysno = atoi_n (node_aid->u.data.data,
-                                                      node_aid->u.data.len);
+           (*zdip)->sysno = atoi_zn(node_id->u.data.data,
+                                     node_id->u.data.len);
+           (*zdip)->attributeDetails = (zebAttributeDetails)
+               nmem_malloc(zei->nmem, sizeof(*(*zdip)->attributeDetails));
+           (*zdip)->attributeDetails->sysno = atoi_zn(node_aid->u.data.data,
+                                                       node_aid->u.data.len);
            (*zdip)->attributeDetails->readFlag = 1;
            (*zdip)->attributeDetails->dirty = 0;
            (*zdip)->attributeDetails->readFlag = 1;
            (*zdip)->attributeDetails->dirty = 0;
-           (*zdip)->attributeDetails->SUInfo = NULL;
+           (*zdip)->attributeDetails->SUInfo = 0;
 
            zdip = &(*zdip)->next;
        }
 
            zdip = &(*zdip)->next;
        }
-       np = data1_search_tag (zei->dh, node_zebra->child,
-                              "ordinalSU");
-       np = np->child;
-       assert (np && np->which == DATA1N_data);
-       zei->ordinalSU = atoi_n (np->u.data.data, np->u.data.len);
-
-       np = data1_search_tag (zei->dh, node_zebra->child,
-                              "runNumber");
-       np = np->child;
-       assert (np && np->which == DATA1N_data);
-       zei->runNumber = atoi_n (np->u.data.data, np->u.data.len);
-       *zdip = NULL;
-       rec_rm (&trec);
+       if (node_zebra)
+       {
+           np = data1_search_tag(zei->dh, node_zebra->child,
+                                 "ordinalSU");
+           np = np->child;
+           assert(np && np->which == DATA1N_data);
+           zei->ordinalSU = atoi_n(np->u.data.data, np->u.data.len);
+
+           np = data1_search_tag(zei->dh, node_zebra->child,
+                                 "ordinalDatabase");
+           np = np->child;
+           assert(np && np->which == DATA1N_data);
+           zei->ordinalDatabase = atoi_n(np->u.data.data, np->u.data.len);
+
+           np = data1_search_tag(zei->dh, node_zebra->child,
+                                  "runNumber");
+           np = np->child;
+           assert(np && np->which == DATA1N_data);
+           zei->runNumber = atoi_zn(np->u.data.data, np->u.data.len);
+            yaz_log(YLOG_DEBUG, "read runnumber=" ZINT_FORMAT, zei->runNumber);
+           *zdip = 0;
+       }
+       rec_free(&trec);
     }
     else  /* create initial targetInfo */
     {
        data1_node *node_tgtinfo;
     }
     else  /* create initial targetInfo */
     {
        data1_node *node_tgtinfo;
-        zei->ordinalSU = 1;
-       zei->runNumber = 0;
 
 
+       *zdip = 0;
        if (writeFlag)
        {
            char *sgml_buf;
            int sgml_len;
 
            zei->data1_target =
        if (writeFlag)
        {
            char *sgml_buf;
            int sgml_len;
 
            zei->data1_target =
-               data1_read_sgml (zei->dh, zei->nmem,
+               data1_read_sgml(zei->dh, zei->nmem,
                                 "<explain><targetInfo>TargetInfo\n"
                                 "<name>Zebra</>\n"
                                 "<namedResultSets>1</>\n"
                                 "<multipleDBSearch>1</>\n"
                                 "<nicknames><name>Zebra</></>\n"
                                 "</></>\n" );
                                 "<explain><targetInfo>TargetInfo\n"
                                 "<name>Zebra</>\n"
                                 "<namedResultSets>1</>\n"
                                 "<multipleDBSearch>1</>\n"
                                 "<nicknames><name>Zebra</></>\n"
                                 "</></>\n" );
+           if (!zei->data1_target)
+           {
+               yaz_log(YLOG_FATAL, "Explain schema missing. Check profilePath");
+               nmem_destroy(zei->nmem);
+               return 0;
+           }
+           node_tgtinfo = data1_search_tag(zei->dh, zei->data1_target,
+                                             "/targetInfo");
+           assert(node_tgtinfo);
 
 
-           node_tgtinfo = data1_search_tag (zei->dh, zei->data1_target->child,
-                                           "targetInfo");
-           assert (node_tgtinfo);
-
-
-           zebraExplain_initCommonInfo (zei, node_tgtinfo);
-           zebraExplain_initAccessInfo (zei, node_tgtinfo);
+           zebraExplain_initCommonInfo(zei, node_tgtinfo);
+           zebraExplain_initAccessInfo(zei, node_tgtinfo);
 
            /* write now because we want to be sure about the sysno */
 
            /* write now because we want to be sure about the sysno */
-           trec = rec_new (records);
+           trec = rec_new(records);
+           if (!trec)
+           {
+               yaz_log(YLOG_FATAL, "Cannot create root Explain record");
+               nmem_destroy(zei->nmem);
+               return 0;
+           }
            trec->info[recInfo_fileType] =
            trec->info[recInfo_fileType] =
-               rec_strdup ("grs.sgml", &trec->size[recInfo_fileType]);
+               rec_strdup("grs.sgml", &trec->size[recInfo_fileType]);
            trec->info[recInfo_databaseName] =
            trec->info[recInfo_databaseName] =
-               rec_strdup ("IR-Explain-1", &trec->size[recInfo_databaseName]);
-           
+               rec_strdup("IR-Explain-1", &trec->size[recInfo_databaseName]);
+
            sgml_buf = data1_nodetoidsgml(dh, zei->data1_target, 0, &sgml_len);
            sgml_buf = data1_nodetoidsgml(dh, zei->data1_target, 0, &sgml_len);
-           trec->info[recInfo_storeData] = xmalloc (sgml_len);
-           memcpy (trec->info[recInfo_storeData], sgml_buf, sgml_len);
+           trec->info[recInfo_storeData] = (char *) xmalloc(sgml_len);
+           memcpy(trec->info[recInfo_storeData], sgml_buf, sgml_len);
            trec->size[recInfo_storeData] = sgml_len;
            trec->size[recInfo_storeData] = sgml_len;
-           
-           rec_put (records, &trec);
+
+           rec_put(records, &trec);
+           rec_free(&trec);
+       }
+
+       zebraExplain_newDatabase(zei, "IR-Explain-1", 0);
+
+       if (!zei->categoryList->dirty)
+       {
+           struct zebraCategoryListInfo *zcl = zei->categoryList;
+           data1_node *node_cl;
+
+           zcl->dirty = 1;
+           zcl->data1_categoryList =
+               data1_read_sgml(zei->dh, zei->nmem,
+                                "<explain><categoryList>CategoryList\n"
+                                "</></>\n");
+
+           if (zcl->data1_categoryList)
+           {
+               node_cl = data1_search_tag(zei->dh, zcl->data1_categoryList,
+                                           "/categoryList");
+               assert(node_cl);
+               zebraExplain_initCommonInfo(zei, node_cl);
+           }
        }
        }
-       *zdip = NULL;
-       rec_rm (&trec);
-       zebraExplain_newDatabase (zei, "IR-Explain-1", 0);
     }
     return zei;
 }
 
     }
     return zei;
 }
 
-static void zebraExplain_readAttributeDetails (ZebraExplainInfo zei,
+static void zebraExplain_readAttributeDetails(ZebraExplainInfo zei,
                                               zebAttributeDetails zad)
 {
     Record rec;
     struct zebSUInfoB **zsuip = &zad->SUInfo;
     data1_node *node_adinfo, *node_zebra, *node_list, *np;
 
                                               zebAttributeDetails zad)
 {
     Record rec;
     struct zebSUInfoB **zsuip = &zad->SUInfo;
     data1_node *node_adinfo, *node_zebra, *node_list, *np;
 
-    assert (zad->sysno);
-    rec = rec_get (zei->records, zad->sysno);
+    assert(zad->sysno);
+    rec = rec_get(zei->records, zad->sysno);
 
 
-    zad->data1_tree = read_sgml_rec (zei->dh, zei->nmem, rec);
+    zad->data1_tree = read_sgml_rec(zei->dh, zei->nmem, rec);
 
 
-    node_adinfo = data1_search_tag (zei->dh, zad->data1_tree->child,
-                                   "attributeDetails");
-    node_zebra = data1_search_tag (zei->dh, node_adinfo->child,
+    node_adinfo = data1_search_tag(zei->dh, zad->data1_tree,
+                                   "/attributeDetails");
+    node_zebra = data1_search_tag(zei->dh, node_adinfo->child,
                                 "zebraInfo");
                                 "zebraInfo");
-    node_list = data1_search_tag (zei->dh, node_zebra->child,
+    node_list = data1_search_tag(zei->dh, node_zebra->child,
                                  "attrlist");
     for (np = node_list->child; np; np = np->next)
     {
                                  "attrlist");
     for (np = node_list->child; np; np = np->next)
     {
-       data1_node *node_set = NULL;
-       data1_node *node_use = NULL;
-       data1_node *node_ordinal = NULL;
+       data1_node *node_str = 0;
+       data1_node *node_ordinal = 0;
+       data1_node *node_type = 0;
+       data1_node *node_cat = 0;
+        data1_node *node_doc_occurrences = 0;
+        data1_node *node_term_occurrences = 0;
        data1_node *np2;
        data1_node *np2;
-       if (np->which != DATA1N_tag || strcmp (np->u.tag.tag, "attr"))
+
+       if (np->which != DATA1N_tag || strcmp(np->u.tag.tag, "attr"))
            continue;
        for (np2 = np->child; np2; np2 = np2->next)
        {
            if (np2->which != DATA1N_tag || !np2->child ||
                np2->child->which != DATA1N_data)
                continue;
            continue;
        for (np2 = np->child; np2; np2 = np2->next)
        {
            if (np2->which != DATA1N_tag || !np2->child ||
                np2->child->which != DATA1N_data)
                continue;
-           if (!strcmp (np2->u.tag.tag, "set"))
-               node_set = np2->child;
-           else if (!strcmp (np2->u.tag.tag, "use"))
-               node_use = np2->child;
-           else if (!strcmp (np2->u.tag.tag, "ordinal"))
+           if (!strcmp(np2->u.tag.tag, "str"))
+               node_str = np2->child;
+           else if (!strcmp(np2->u.tag.tag, "ordinal"))
                node_ordinal = np2->child;
                node_ordinal = np2->child;
+           else if (!strcmp(np2->u.tag.tag, "type"))
+               node_type = np2->child;
+           else if (!strcmp(np2->u.tag.tag, "cat"))
+               node_cat = np2->child;
+           else if (!strcmp(np2->u.tag.tag, "dococcurrences"))
+               node_doc_occurrences = np2->child;
+           else if (!strcmp(np2->u.tag.tag, "termoccurrences"))
+               node_term_occurrences = np2->child;
+            else
+            {
+                yaz_log(YLOG_LOG, "Unknown tag '%s' in attributeDetails",
+                        np2->u.tag.tag);
+            }
+       }
+       assert(node_ordinal);
+
+        *zsuip = (struct zebSUInfoB *)
+           nmem_malloc(zei->nmem, sizeof(**zsuip));
+
+       if (node_type && node_type->u.data.len > 0)
+           (*zsuip)->info.index_type =
+                nmem_strdupn(zei->nmem,
+                             node_type->u.data.data,
+                             node_type->u.data.len);
+       else
+       {
+           yaz_log(YLOG_WARN, "Missing attribute 'type' in attribute info");
+           (*zsuip)->info.index_type = "w";
+       }
+        if (node_cat && node_cat->u.data.len > 0)
+        {
+            zinfo_index_category_t cat;
+
+            data1_node *np = node_cat;
+            if (!strncmp(np->u.data.data, "index", np->u.data.len))
+                cat = zinfo_index_category_index;
+            else if (!strncmp(np->u.data.data, "sort", np->u.data.len))
+                cat = zinfo_index_category_sort;
+            else if (!strncmp(np->u.data.data, "alwaysmatches",
+                              np->u.data.len))
+                cat = zinfo_index_category_alwaysmatches;
+            else if (!strncmp(np->u.data.data, "anchor",
+                              np->u.data.len))
+                cat = zinfo_index_category_anchor;
+            else
+            {
+                yaz_log(YLOG_WARN, "Bad index cateogry '%.*s'",
+                        np->u.data.len, np->u.data.data);
+                cat = zinfo_index_category_index;
+            }
+            (*zsuip)->info.cat = cat;
+        }
+        else
+            (*zsuip)->info.cat = zinfo_index_category_index;
+
+        if (node_doc_occurrences)
+        {
+            data1_node *np = node_doc_occurrences;
+            (*zsuip)->info.doc_occurrences = atoi_zn(np->u.data.data,
+                                                     np->u.data.len);
+        }
+        if (node_term_occurrences)
+        {
+            data1_node *np = node_term_occurrences;
+            (*zsuip)->info.term_occurrences = atoi_zn(np->u.data.data,
+                                                      np->u.data.len);
+        }
+       if (node_str)
+       {
+           (*zsuip)->info.str = nmem_strdupn(zei->nmem,
+                                              node_str->u.data.data,
+                                              node_str->u.data.len);
+       }
+       else
+       {
+           yaz_log(YLOG_WARN, "Missing set/use/str in attribute info");
+           continue;
        }
        }
-       assert (node_set && node_use && node_ordinal);
-       
-        *zsuip = nmem_malloc (zei->nmem, sizeof(**zsuip));
-       (*zsuip)->info.set = atoi_n (node_set->u.data.data,
-                                    node_set->u.data.len);
-       (*zsuip)->info.use = atoi_n (node_use->u.data.data,
-                                    node_use->u.data.len);
-       (*zsuip)->info.ordinal = atoi_n (node_ordinal->u.data.data,
+       (*zsuip)->info.ordinal = atoi_n(node_ordinal->u.data.data,
                                         node_ordinal->u.data.len);
                                         node_ordinal->u.data.len);
-       logf (LOG_DEBUG, "set=%d use=%d ordinal=%d",
-             (*zsuip)->info.set, (*zsuip)->info.use, (*zsuip)->info.ordinal);
         zsuip = &(*zsuip)->next;
     }
         zsuip = &(*zsuip)->next;
     }
-    *zsuip = NULL;
+    *zsuip = 0;
     zad->readFlag = 0;
     zad->readFlag = 0;
-    rec_rm (&rec);
+    rec_free(&rec);
 }
 
 }
 
-static void zebraExplain_readDatabase (ZebraExplainInfo zei,
-                                      struct zebDatabaseInfoB *zdi)
+static void zebraExplain_readDatabase(ZebraExplainInfo zei,
+                                      struct zebDatabaseInfoB *zdi)
 {
     Record rec;
     data1_node *node_dbinfo, *node_zebra, *np;
 
 {
     Record rec;
     data1_node *node_dbinfo, *node_zebra, *np;
 
-    assert (zdi->sysno);
-    rec = rec_get (zei->records, zdi->sysno);
+    assert(zdi->sysno);
+    rec = rec_get(zei->records, zdi->sysno);
+
+    zdi->data1_database = read_sgml_rec(zei->dh, zei->nmem, rec);
 
 
-    zdi->data1_database = read_sgml_rec (zei->dh, zei->nmem, rec);
-    
-    node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database->child,
-                                  "databaseInfo");
-    zebraExplain_mergeAccessInfo (zei, node_dbinfo, &zdi->accessInfo);
+    node_dbinfo = data1_search_tag(zei->dh, zdi->data1_database,
+                                    "/databaseInfo");
+    assert(node_dbinfo);
+    zebraExplain_mergeAccessInfo(zei, node_dbinfo, &zdi->accessInfo);
 
 
-    node_zebra = data1_search_tag (zei->dh, node_dbinfo->child,
+    node_zebra = data1_search_tag(zei->dh, node_dbinfo->child,
                                 "zebraInfo");
                                 "zebraInfo");
-    np  = data1_search_tag (zei->dh, node_dbinfo->child,
-                           "recordBytes");
-    if (np && np->child && np->child->which == DATA1N_data)
-       zdi->recordBytes = atoi_n (np->child->u.data.data,
-                                  np->child->u.data.len);
-    if ((np = data1_search_tag (zei->dh, node_dbinfo->child,
+    if (node_zebra
+       && (np = data1_search_tag(zei->dh, node_zebra->child,
+                                  "recordBytes"))
+       && np->child && np->child->which == DATA1N_data)
+       zdi->recordBytes = atoi_zn(np->child->u.data.data,
+                                   np->child->u.data.len);
+
+    if (node_zebra
+       && (np = data1_search_tag(zei->dh, node_zebra->child,
+                                  "ordinalDatabase"))
+       && np->child && np->child->which == DATA1N_data)
+       zdi->ordinalDatabase = atoi_n(np->child->u.data.data,
+                                     np->child->u.data.len);
+
+    if ((np = data1_search_tag(zei->dh, node_dbinfo->child,
                                "recordCount")) &&
                                "recordCount")) &&
-       (np = data1_search_tag (zei->dh, np->child,
+       (np = data1_search_tag(zei->dh, np->child,
                                "recordCountActual")) &&
        np->child->which == DATA1N_data)
     {
                                "recordCountActual")) &&
        np->child->which == DATA1N_data)
     {
-       zdi->recordCount = atoi_n (np->child->u.data.data,
-                                  np->child->u.data.len);
-    }    
+       zdi->recordCount = atoi_zn(np->child->u.data.data,
+                                   np->child->u.data.len);
+    }
     zdi->readFlag = 0;
     zdi->readFlag = 0;
-    rec_rm (&rec);
+    rec_free(&rec);
+}
+
+int zebraExplain_removeDatabase(ZebraExplainInfo zei, void *update_handle)
+{
+    struct zebDatabaseInfoB **zdip = &zei->databaseInfo;
+
+    while (*zdip)
+    {
+       if (*zdip == zei->curDatabaseInfo)
+       {
+           struct zebDatabaseInfoB *zdi = *zdip;
+           Record rec;
+
+           zei->dirty = 1;
+           zei->updateHandle = update_handle;
+
+           if (zdi->attributeDetails)
+           {
+               /* remove attribute details keys and delete it */
+               zebAttributeDetails zad = zdi->attributeDetails;
+
+               rec = rec_get(zei->records, zad->sysno);
+               (*zei->updateFunc)(zei->updateHandle, rec, 0);
+               rec_del(zei->records, &rec);
+           }
+           /* remove database record keys and delete it */
+           rec = rec_get(zei->records, zdi->sysno);
+           (*zei->updateFunc)(zei->updateHandle, rec, 0);
+           rec_del(zei->records, &rec);
+
+           /* remove from list */
+           *zdip = zdi->next;
+
+           /* current database is IR-Explain-1 */
+           return 0;
+       }
+       zdip = &(*zdip)->next;
+    }
+    return -1;
 }
 
 }
 
-int zebraExplain_curDatabase (ZebraExplainInfo zei, const char *database)
+int zebraExplain_curDatabase(ZebraExplainInfo zei, const char *database)
 {
     struct zebDatabaseInfoB *zdi;
 {
     struct zebDatabaseInfoB *zdi;
-    
-    assert (zei);
+    const char *database_n = strrchr(database, '/');
+
+    if (database_n)
+        database_n++;
+    else
+        database_n = database;
+
+    assert(zei);
     if (zei->curDatabaseInfo &&
     if (zei->curDatabaseInfo &&
-        !strcmp (zei->curDatabaseInfo->databaseName, database))
+        !STRCASECMP(zei->curDatabaseInfo->databaseName, database))
         return 0;
     for (zdi = zei->databaseInfo; zdi; zdi=zdi->next)
     {
         return 0;
     for (zdi = zei->databaseInfo; zdi; zdi=zdi->next)
     {
-        if (!strcmp (zdi->databaseName, database))
+        if (!STRCASECMP(zdi->databaseName, database_n))
             break;
     }
     if (!zdi)
         return -1;
 #if ZINFO_DEBUG
             break;
     }
     if (!zdi)
         return -1;
 #if ZINFO_DEBUG
-    logf (LOG_LOG, "zebraExplain_curDatabase: %s", database);
+    yaz_log(YLOG_LOG, "zebraExplain_curDatabase: %s", database);
 #endif
     if (zdi->readFlag)
     {
 #if ZINFO_DEBUG
 #endif
     if (zdi->readFlag)
     {
 #if ZINFO_DEBUG
-       logf (LOG_LOG, "zebraExplain_readDatabase: %s", database);
+       yaz_log(YLOG_LOG, "zebraExplain_readDatabase: %s", database);
 #endif
 #endif
-        zebraExplain_readDatabase (zei, zdi);
+        zebraExplain_readDatabase(zei, zdi);
     }
     if (zdi->attributeDetails->readFlag)
     {
 #if ZINFO_DEBUG
     }
     if (zdi->attributeDetails->readFlag)
     {
 #if ZINFO_DEBUG
-       logf (LOG_LOG, "zebraExplain_readAttributeDetails: %s", database);
+       yaz_log(YLOG_LOG, "zebraExplain_readAttributeDetails: %s", database);
 #endif
 #endif
-        zebraExplain_readAttributeDetails (zei, zdi->attributeDetails);
+        zebraExplain_readAttributeDetails(zei, zdi->attributeDetails);
     }
     zei->curDatabaseInfo = zdi;
     return 0;
 }
 
     }
     zei->curDatabaseInfo = zdi;
     return 0;
 }
 
-static void zebraExplain_initCommonInfo (ZebraExplainInfo zei, data1_node *n)
+static void zebraExplain_initCommonInfo(ZebraExplainInfo zei, data1_node *n)
 {
 {
-    data1_node *c = data1_add_tag (zei->dh, n, "commonInfo", zei->nmem);
-
-    data1_add_tagdata_text (zei->dh, c, "dateAdded", zei->date, zei->nmem);
-    data1_add_tagdata_text (zei->dh, c, "dateChanged", zei->date, zei->nmem);
-    data1_add_tagdata_text (zei->dh, c, "languageCode", "EN", zei->nmem);
+    data1_node *c = data1_mk_tag(zei->dh, zei->nmem, "commonInfo", 0, n);
+    data1_mk_tag_data_text(zei->dh, c, "dateAdded", zei->date, zei->nmem);
+    data1_mk_tag_data_text(zei->dh, c, "dateChanged", zei->date, zei->nmem);
+    data1_mk_tag_data_text(zei->dh, c, "languageCode", "EN", zei->nmem);
 }
 
 }
 
-static void zebraExplain_updateCommonInfo (ZebraExplainInfo zei, data1_node *n)
+static void zebraExplain_updateCommonInfo(ZebraExplainInfo zei, data1_node *n)
 {
 {
-    data1_node *c = data1_search_tag (zei->dh, n->child, "commonInfo");
-    assert (c);
-    data1_make_tagdata_text (zei->dh, c, "dateChanged", zei->date, zei->nmem);
+    data1_node *c = data1_search_tag(zei->dh, n->child, "commonInfo");
+    assert(c);
+    data1_mk_tag_data_text_uni(zei->dh, c, "dateChanged", zei->date,
+                                zei->nmem);
 }
 
 }
 
-static void zebraExplain_initAccessInfo (ZebraExplainInfo zei, data1_node *n)
+static void zebraExplain_initAccessInfo(ZebraExplainInfo zei, data1_node *n)
 {
 {
-    data1_node *c = data1_add_tag (zei->dh, n, "accessInfo", zei->nmem);
-    data1_node *d = data1_add_tag (zei->dh, c, "unitSystems", zei->nmem);
-    data1_add_tagdata_text (zei->dh, d, "string", "ISO", zei->nmem);
+    data1_node *c = data1_mk_tag(zei->dh, zei->nmem, "accessInfo", 0, n);
+    data1_node *d = data1_mk_tag(zei->dh, zei->nmem, "unitSystems", 0, c);
+    data1_mk_tag_data_text(zei->dh, d, "string", "ISO", zei->nmem);
 }
 
 }
 
-static void zebraExplain_updateAccessInfo (ZebraExplainInfo zei, data1_node *n,
+static void zebraExplain_updateAccessInfo(ZebraExplainInfo zei, data1_node *n,
                                           zebAccessInfo accessInfo)
 {
                                           zebAccessInfo accessInfo)
 {
-    data1_node *c = data1_search_tag (zei->dh, n->child, "accessInfo");
+    data1_node *c = data1_search_tag(zei->dh, n->child, "accessInfo");
     data1_node *d;
     zebAccessObject p;
     data1_node *d;
     zebAccessObject p;
-    
-    assert (c);
+
+    if (!c)
+    {
+        data1_pr_tree(zei->dh, n, stdout);
+        zebra_exit("zebraExplain_updateAccessInfo");
+    }
 
     if ((p = accessInfo->attributeSetIds))
     {
 
     if ((p = accessInfo->attributeSetIds))
     {
-       d = data1_make_tag (zei->dh, c, "attributeSetIds", zei->nmem);
+       d = data1_mk_tag_uni(zei->dh, zei->nmem, "attributeSetIds", c);
        for (; p; p = p->next)
        for (; p; p = p->next)
-           data1_add_tagdata_oid (zei->dh, d, "oid", p->oid, zei->nmem);
+           data1_mk_tag_data_oid(zei->dh, d, "oid", p->oid, zei->nmem);
     }
     if ((p = accessInfo->schemas))
     {
     }
     if ((p = accessInfo->schemas))
     {
-       d = data1_make_tag (zei->dh, c, "schemas", zei->nmem);
+       d = data1_mk_tag_uni(zei->dh, zei->nmem, "schemas", c);
        for (; p; p = p->next)
        for (; p; p = p->next)
-           data1_add_tagdata_oid (zei->dh, d, "oid", p->oid, zei->nmem);
+           data1_mk_tag_data_oid(zei->dh, d, "oid", p->oid, zei->nmem);
     }
 }
 
     }
 }
 
-int zebraExplain_newDatabase (ZebraExplainInfo zei, const char *database,
+int zebraExplain_newDatabase(ZebraExplainInfo zei, const char *database,
                              int explain_database)
 {
     struct zebDatabaseInfoB *zdi;
     data1_node *node_dbinfo, *node_adinfo;
                              int explain_database)
 {
     struct zebDatabaseInfoB *zdi;
     data1_node *node_dbinfo, *node_adinfo;
+    const char *database_n = strrchr(database, '/');
+
+    if (database_n)
+        database_n++;
+    else
+        database_n = database;
 
 #if ZINFO_DEBUG
 
 #if ZINFO_DEBUG
-    logf (LOG_LOG, "zebraExplain_newDatabase: %s", database);
+    yaz_log(YLOG_LOG, "zebraExplain_newDatabase: %s", database);
 #endif
 #endif
-    assert (zei);
+    assert(zei);
     for (zdi = zei->databaseInfo; zdi; zdi=zdi->next)
     {
     for (zdi = zei->databaseInfo; zdi; zdi=zdi->next)
     {
-        if (!strcmp (zdi->databaseName, database))
+        if (!STRCASECMP(zdi->databaseName, database_n))
             break;
     }
     if (zdi)
         return -1;
     /* it's new really. make it */
             break;
     }
     if (zdi)
         return -1;
     /* it's new really. make it */
-    zdi = nmem_malloc (zei->nmem, sizeof(*zdi));
+    zdi = (struct zebDatabaseInfoB *) nmem_malloc(zei->nmem, sizeof(*zdi));
     zdi->next = zei->databaseInfo;
     zei->databaseInfo = zdi;
     zdi->sysno = 0;
     zdi->recordCount = 0;
     zdi->recordBytes = 0;
     zdi->readFlag = 0;
     zdi->next = zei->databaseInfo;
     zei->databaseInfo = zdi;
     zdi->sysno = 0;
     zdi->recordCount = 0;
     zdi->recordBytes = 0;
     zdi->readFlag = 0;
-    zdi->databaseName = nmem_strdup (zei->nmem, database);
+    zdi->databaseName = nmem_strdup(zei->nmem, database_n);
+
+    zdi->ordinalDatabase = zei->ordinalDatabase++;
+
+    zebraExplain_mergeAccessInfo(zei, 0, &zdi->accessInfo);
 
 
-    zebraExplain_mergeAccessInfo (zei, 0, &zdi->accessInfo);
-    
-    assert (zei->dh);
-    assert (zei->nmem);
+    assert(zei->dh);
+    assert(zei->nmem);
 
     zdi->data1_database =
 
     zdi->data1_database =
-       data1_read_sgml (zei->dh, zei->nmem, 
+       data1_read_sgml(zei->dh, zei->nmem,
                         "<explain><databaseInfo>DatabaseInfo\n"
                         "</></>\n");
                         "<explain><databaseInfo>DatabaseInfo\n"
                         "</></>\n");
-    
-    node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database->child,
-                                  "databaseInfo");
-    assert (node_dbinfo);
+    if (!zdi->data1_database)
+       return -2;
 
 
-    zebraExplain_initCommonInfo (zei, node_dbinfo);
-    zebraExplain_initAccessInfo (zei, node_dbinfo);
+    node_dbinfo = data1_search_tag(zei->dh, zdi->data1_database,
+                                    "/databaseInfo");
+    assert(node_dbinfo);
 
 
-    data1_add_tagdata_text (zei->dh, node_dbinfo, "name",
+    zebraExplain_initCommonInfo(zei, node_dbinfo);
+    zebraExplain_initAccessInfo(zei, node_dbinfo);
+
+    data1_mk_tag_data_text(zei->dh, node_dbinfo, "name",
                               database, zei->nmem);
                               database, zei->nmem);
-    
+
     if (explain_database)
     if (explain_database)
-       data1_add_tagdata_text (zei->dh, node_dbinfo, "explainDatabase",
+       data1_mk_tag_data_text(zei->dh, node_dbinfo, "explainDatabase",
                                "", zei->nmem);
                                "", zei->nmem);
-    
-    data1_add_tagdata_text (zei->dh, node_dbinfo, "userFee",
+
+    data1_mk_tag_data_text(zei->dh, node_dbinfo, "userFee",
                            "0", zei->nmem);
                            "0", zei->nmem);
-    
-    data1_add_tagdata_text (zei->dh, node_dbinfo, "available",
+
+    data1_mk_tag_data_text(zei->dh, node_dbinfo, "available",
                            "1", zei->nmem);
                            "1", zei->nmem);
-    
+
 #if ZINFO_DEBUG
 #if ZINFO_DEBUG
-    data1_pr_tree (zei->dh, zdi->data1_database, stderr);
+    data1_pr_tree(zei->dh, zdi->data1_database, stderr);
 #endif
     zdi->dirty = 1;
     zei->dirty = 1;
     zei->curDatabaseInfo = zdi;
 
 #endif
     zdi->dirty = 1;
     zei->dirty = 1;
     zei->curDatabaseInfo = zdi;
 
-    zdi->attributeDetails =
-       nmem_malloc (zei->nmem, sizeof(*zdi->attributeDetails));
+    zdi->attributeDetails = (zebAttributeDetails)
+       nmem_malloc(zei->nmem, sizeof(*zdi->attributeDetails));
     zdi->attributeDetails->readFlag = 0;
     zdi->attributeDetails->sysno = 0;
     zdi->attributeDetails->dirty = 1;
     zdi->attributeDetails->readFlag = 0;
     zdi->attributeDetails->sysno = 0;
     zdi->attributeDetails->dirty = 1;
-    zdi->attributeDetails->SUInfo = NULL;
+    zdi->attributeDetails->SUInfo = 0;
     zdi->attributeDetails->data1_tree =
     zdi->attributeDetails->data1_tree =
-       data1_read_sgml (zei->dh, zei->nmem,
+       data1_read_sgml(zei->dh, zei->nmem,
                         "<explain><attributeDetails>AttributeDetails\n"
                         "</></>\n");
 
                         "<explain><attributeDetails>AttributeDetails\n"
                         "</></>\n");
 
-    node_adinfo =
-       data1_search_tag (zei->dh, zdi->attributeDetails->data1_tree->child,
-                         "attributeDetails");
-    assert (node_adinfo);
+    node_adinfo = data1_search_tag(zei->dh, zdi->attributeDetails->data1_tree,
+                                    "/attributeDetails");
+    assert(node_adinfo);
+
+    zebraExplain_initCommonInfo(zei, node_adinfo);
 
 
-    zebraExplain_initCommonInfo (zei, node_adinfo);
+    data1_mk_tag_data_text(zei->dh, node_adinfo, "name", database, zei->nmem);
 
     return 0;
 }
 
 
     return 0;
 }
 
-static void writeAttributeValueDetails (ZebraExplainInfo zei,
-                                 zebAttributeDetails zad,
-                                 data1_node *node_atvs, data1_attset *attset)
 
 
+static void zebraExplain_writeCategoryList(ZebraExplainInfo zei,
+                                           struct zebraCategoryListInfo *zcl,
+                                           int key_flush)
 {
 {
-    struct zebSUInfoB *zsui;
-    int set_ordinal = attset->reference;
-    data1_attset_child *c;
+    char *sgml_buf;
+    int sgml_len;
+    int i;
+    Record drec;
+    data1_node *node_ci, *node_categoryList;
+    zint sysno = 0;
+    static char *category[] = {
+       "CategoryList",
+       "TargetInfo",
+       "DatabaseInfo",
+       "AttributeDetails",
+       0
+    };
+
+    assert(zcl);
+    if (!zcl->dirty)
+       return ;
+    zcl->dirty = 0;
+    node_categoryList = zcl->data1_categoryList;
 
 
-    for (c = attset->children; c; c = c->next)
-       writeAttributeValueDetails (zei, zad, node_atvs, c->child);
-    for (zsui = zad->SUInfo; zsui; zsui = zsui->next)
+#if ZINFO_DEBUG
+    yaz_log(YLOG_LOG, "zebraExplain_writeCategoryList");
+#endif
+
+    drec = createRecord(zei->records, &sysno);
+    if (!drec)
+       return;
+
+    node_ci = data1_search_tag(zei->dh, node_categoryList,
+                               "/categoryList");
+    assert (node_ci);
+    node_ci = data1_mk_tag(zei->dh, zei->nmem, "categories", 0 /* attr */,
+                            node_ci);
+    assert (node_ci);
+
+    for (i = 0; category[i]; i++)
     {
     {
-       data1_node *node_attvalue, *node_value;
-       if (set_ordinal != zsui->info.set)
-           continue;
-       node_attvalue = data1_add_tag (zei->dh, node_atvs, "attributeValue",
-                                      zei->nmem);
-       node_value = data1_add_tag (zei->dh, node_attvalue, "value",
-                                   zei->nmem);
-       data1_add_tagdata_int (zei->dh, node_value, "numeric",
-                              zsui->info.use, zei->nmem);
+       data1_node *node_cat = data1_mk_tag(zei->dh, zei->nmem,  "category",
+                                             0 /* attr */, node_ci);
+
+       data1_mk_tag_data_text(zei->dh, node_cat, "name",
+                               category[i], zei->nmem);
     }
     }
+    /* extract *searchable* keys from it. We do this here, because
+       record count, etc. is affected */
+    if (key_flush)
+       (*zei->updateFunc)(zei->updateHandle, drec, node_categoryList);
+
+    /* convert to "SGML" and write it */
+#if ZINFO_DEBUG
+    data1_pr_tree(zei->dh, node_categoryList, stderr);
+#endif
+    sgml_buf = data1_nodetoidsgml(zei->dh, node_categoryList, 0, &sgml_len);
+    drec->info[recInfo_storeData] = (char *) xmalloc(sgml_len);
+    memcpy(drec->info[recInfo_storeData], sgml_buf, sgml_len);
+    drec->size[recInfo_storeData] = sgml_len;
+
+    rec_put(zei->records, &drec);
 }
 
 }
 
-static void zebraExplain_writeAttributeDetails (ZebraExplainInfo zei,
+static void zebraExplain_writeAttributeDetails(ZebraExplainInfo zei,
                                                zebAttributeDetails zad,
                                                const char *databaseName,
                                                int key_flush)
                                                zebAttributeDetails zad,
                                                const char *databaseName,
                                                int key_flush)
@@ -857,116 +1049,84 @@ static void zebraExplain_writeAttributeDetails (ZebraExplainInfo zei,
     char *sgml_buf;
     int sgml_len;
     Record drec;
     char *sgml_buf;
     int sgml_len;
     Record drec;
-    data1_node *node_adinfo, *node_list, *node_zebra, *node_attributesBySet;
+    data1_node *node_adinfo, *node_list, *node_zebra;
     struct zebSUInfoB *zsui;
     struct zebSUInfoB *zsui;
-    int set_min;
-    
+
     if (!zad->dirty)
        return;
     if (!zad->dirty)
        return;
-    
+
     zad->dirty = 0;
 #if ZINFO_DEBUG
     zad->dirty = 0;
 #if ZINFO_DEBUG
-    logf (LOG_LOG, "zebraExplain_writeAttributeDetails");    
+    yaz_log(YLOG_LOG, "zebraExplain_writeAttributeDetails");
+    data1_pr_tree(zei->dh, zad->data1_tree, stderr);
 #endif
 
 #endif
 
-    drec = createRecord (zei->records, &zad->sysno);
-    assert (zad->data1_tree);
-    node_adinfo = data1_search_tag (zei->dh, zad->data1_tree->child,
-                                  "attributeDetails");
-    zebraExplain_updateCommonInfo (zei, node_adinfo);
+    drec = createRecord(zei->records, &zad->sysno);
+    if (!drec)
+       return;
+    assert(zad->data1_tree);
+
+    node_adinfo = data1_search_tag(zei->dh, zad->data1_tree,
+                                  "/attributeDetails");
+    zebraExplain_updateCommonInfo(zei, node_adinfo);
 
 
-    data1_add_tagdata_text (zei->dh, node_adinfo, "name",
-                           databaseName, zei->nmem);
+    /* zebra info (private) .. no children yet.. so se don't index zebraInfo */
+    node_zebra = data1_mk_tag_uni(zei->dh, zei->nmem,
+                                "zebraInfo", node_adinfo);
 
     /* extract *searchable* keys from it. We do this here, because
        record count, etc. is affected */
     if (key_flush)
        (*zei->updateFunc)(zei->updateHandle, drec, zad->data1_tree);
 
     /* extract *searchable* keys from it. We do this here, because
        record count, etc. is affected */
     if (key_flush)
        (*zei->updateFunc)(zei->updateHandle, drec, zad->data1_tree);
-
-    node_attributesBySet = data1_make_tag (zei->dh, node_adinfo,
-                                          "attributesBySet", zei->nmem);
-    set_min = -1;
-    while (1)
-    {
-       data1_node *node_asd;
-       data1_attset *attset;
-       int set_ordinal = -1;
-       for (zsui = zad->SUInfo; zsui; zsui = zsui->next)
-       {
-           if ((set_ordinal < 0 || set_ordinal > zsui->info.set)
-               && zsui->info.set > set_min)
-               set_ordinal = zsui->info.set;
-       }
-       if (set_ordinal < 0)
-           break;
-       set_min = set_ordinal;
-       node_asd = data1_add_tag (zei->dh, node_attributesBySet,
-                                 "attributeSetDetails", zei->nmem);
-
-       attset = data1_attset_search_id (zei->dh, set_ordinal);
-       if (!attset)
-       {
-           zebraExplain_loadAttsets (zei->dh, zei->res);
-           attset = data1_attset_search_id (zei->dh, set_ordinal);
-       }
-       if (attset)
-       {
-           int oid[OID_SIZE];
-           oident oe;
-           
-           oe.proto = PROTO_Z3950;
-           oe.oclass = CLASS_ATTSET;
-           oe.value = set_ordinal;
-           
-           if (oid_ent_to_oid (&oe, oid))
-           {
-               data1_node *node_abt, *node_atd, *node_atvs;
-               data1_add_tagdata_oid (zei->dh, node_asd, "oid",
-                                      oid, zei->nmem);
-
-               node_abt = data1_add_tag (zei->dh, node_asd,
-                                         "attributesByType", zei->nmem);
-               node_atd = data1_add_tag (zei->dh, node_abt,
-                                         "attributeTypeDetails", zei->nmem);
-               data1_add_tagdata_int (zei->dh, node_atd,
-                                       "type", 1, zei->nmem);
-               node_atvs = data1_add_tag (zei->dh, node_atd, 
-                                         "attributeValues", zei->nmem);
-               writeAttributeValueDetails (zei, zad, node_atvs, attset);
-           }
-       }
-    }
-    /* zebra info (private) */
-    node_zebra = data1_make_tag (zei->dh, node_adinfo,
-                                "zebraInfo", zei->nmem);
-    node_list = data1_make_tag (zei->dh, node_zebra,
-                                "attrlist", zei->nmem);
+    node_list = data1_mk_tag_uni(zei->dh, zei->nmem,
+                                "attrlist", node_zebra);
     for (zsui = zad->SUInfo; zsui; zsui = zsui->next)
     {
        data1_node *node_attr;
     for (zsui = zad->SUInfo; zsui; zsui = zsui->next)
     {
        data1_node *node_attr;
-       node_attr = data1_add_tag (zei->dh, node_list,
-                                     "attr", zei->nmem);
-       data1_add_tagdata_int (zei->dh, node_attr, "set",
-                                 zsui->info.set, zei->nmem);
-       data1_add_tagdata_int (zei->dh, node_attr, "use",
-                                 zsui->info.use, zei->nmem);
-       data1_add_tagdata_int (zei->dh, node_attr, "ordinal",
-                                 zsui->info.ordinal, zei->nmem);
+       node_attr = data1_mk_tag(zei->dh, zei->nmem, "attr", 0 /* attr */,
+                                  node_list);
+
+       data1_mk_tag_data_text(zei->dh, node_attr, "type",
+                               zsui->info.index_type, zei->nmem);
+        data1_mk_tag_data_text(zei->dh, node_attr, "str",
+                               zsui->info.str, zei->nmem);
+       data1_mk_tag_data_int(zei->dh, node_attr, "ordinal",
+                              zsui->info.ordinal, zei->nmem);
+
+        data1_mk_tag_data_zint(zei->dh, node_attr, "dococcurrences",
+                                zsui->info.doc_occurrences, zei->nmem);
+        data1_mk_tag_data_zint(zei->dh, node_attr, "termoccurrences",
+                                zsui->info.term_occurrences, zei->nmem);
+        switch(zsui->info.cat)
+        {
+        case zinfo_index_category_index:
+           data1_mk_tag_data_text(zei->dh, node_attr, "cat",
+                                   "index", zei->nmem); break;
+        case zinfo_index_category_sort:
+           data1_mk_tag_data_text(zei->dh, node_attr, "cat",
+                                   "sort", zei->nmem); break;
+        case zinfo_index_category_alwaysmatches:
+           data1_mk_tag_data_text(zei->dh, node_attr, "cat",
+                                   "alwaysmatches", zei->nmem); break;
+        case zinfo_index_category_anchor:
+           data1_mk_tag_data_text(zei->dh, node_attr, "cat",
+                                   "anchor", zei->nmem); break;
+        }
     }
     /* convert to "SGML" and write it */
 #if ZINFO_DEBUG
     }
     /* convert to "SGML" and write it */
 #if ZINFO_DEBUG
-    data1_pr_tree (zei->dh, zad->data1_tree, stderr);
+    data1_pr_tree(zei->dh, zad->data1_tree, stderr);
 #endif
     sgml_buf = data1_nodetoidsgml(zei->dh, zad->data1_tree,
                                  0, &sgml_len);
 #endif
     sgml_buf = data1_nodetoidsgml(zei->dh, zad->data1_tree,
                                  0, &sgml_len);
-    drec->info[recInfo_storeData] = xmalloc (sgml_len);
-    memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
+    drec->info[recInfo_storeData] = (char *) xmalloc(sgml_len);
+    memcpy(drec->info[recInfo_storeData], sgml_buf, sgml_len);
     drec->size[recInfo_storeData] = sgml_len;
     drec->size[recInfo_storeData] = sgml_len;
-    
-    rec_put (zei->records, &drec);
+
+    rec_put(zei->records, &drec);
 }
 
 }
 
-static void zebraExplain_writeDatabase (ZebraExplainInfo zei,
+static void zebraExplain_writeDatabase(ZebraExplainInfo zei,
                                         struct zebDatabaseInfoB *zdi,
                                        int key_flush)
 {
                                         struct zebDatabaseInfoB *zdi,
                                        int key_flush)
 {
@@ -974,51 +1134,60 @@ static void zebraExplain_writeDatabase (ZebraExplainInfo zei,
     int sgml_len;
     Record drec;
     data1_node *node_dbinfo, *node_count, *node_zebra;
     int sgml_len;
     Record drec;
     data1_node *node_dbinfo, *node_count, *node_zebra;
-    
+
     if (!zdi->dirty)
        return;
 
     zdi->dirty = 0;
 #if ZINFO_DEBUG
     if (!zdi->dirty)
        return;
 
     zdi->dirty = 0;
 #if ZINFO_DEBUG
-    logf (LOG_LOG, "zebraExplain_writeDatabase %s", zdi->databaseName);
+    yaz_log(YLOG_LOG, "zebraExplain_writeDatabase %s", zdi->databaseName);
 #endif
 #endif
-    drec = createRecord (zei->records, &zdi->sysno);
-    assert (zdi->data1_database);
-    node_dbinfo = data1_search_tag (zei->dh, zdi->data1_database->child,
-                                  "databaseInfo");
+    drec = createRecord(zei->records, &zdi->sysno);
+    if (!drec)
+       return;
+    assert(zdi->data1_database);
+
+    node_dbinfo = data1_search_tag(zei->dh, zdi->data1_database,
+                                    "/databaseInfo");
+
+    assert(node_dbinfo);
+    zebraExplain_updateCommonInfo(zei, node_dbinfo);
+    zebraExplain_updateAccessInfo(zei, node_dbinfo, zdi->accessInfo);
+
+    /* record count */
+    node_count = data1_mk_tag_uni(zei->dh, zei->nmem,
+                                "recordCount", node_dbinfo);
+    data1_mk_tag_data_zint(zei->dh, node_count, "recordCountActual",
+                           zdi->recordCount, zei->nmem);
 
 
-    zebraExplain_updateCommonInfo (zei, node_dbinfo);
-    zebraExplain_updateAccessInfo (zei, node_dbinfo, zdi->accessInfo);
+    /* zebra info (private) */
+    node_zebra = data1_mk_tag_uni(zei->dh, zei->nmem,
+                                "zebraInfo", node_dbinfo);
 
     /* extract *searchable* keys from it. We do this here, because
        record count, etc. is affected */
     if (key_flush)
        (*zei->updateFunc)(zei->updateHandle, drec, zdi->data1_database);
 
     /* extract *searchable* keys from it. We do this here, because
        record count, etc. is affected */
     if (key_flush)
        (*zei->updateFunc)(zei->updateHandle, drec, zdi->data1_database);
-    /* record count */
-    node_count = data1_make_tag (zei->dh, node_dbinfo,
-                                "recordCount", zei->nmem);
-    data1_add_tagdata_int (zei->dh, node_count, "recordCountActual",
-                             zdi->recordCount, zei->nmem);
-
-    /* zebra info (private) */
-    node_zebra = data1_make_tag (zei->dh, node_dbinfo,
-                                "zebraInfo", zei->nmem);
-    data1_add_tagdata_int (zei->dh, node_zebra,
+    data1_mk_tag_data_zint(zei->dh, node_zebra,
                           "recordBytes", zdi->recordBytes, zei->nmem);
                           "recordBytes", zdi->recordBytes, zei->nmem);
+
+    data1_mk_tag_data_zint(zei->dh, node_zebra,
+                          "ordinalDatabase", zdi->ordinalDatabase, zei->nmem);
+
     /* convert to "SGML" and write it */
 #if ZINFO_DEBUG
     /* convert to "SGML" and write it */
 #if ZINFO_DEBUG
-    data1_pr_tree (zei->dh, zdi->data1_database, stderr);
+    data1_pr_tree(zei->dh, zdi->data1_database, stderr);
 #endif
     sgml_buf = data1_nodetoidsgml(zei->dh, zdi->data1_database,
                                  0, &sgml_len);
 #endif
     sgml_buf = data1_nodetoidsgml(zei->dh, zdi->data1_database,
                                  0, &sgml_len);
-    drec->info[recInfo_storeData] = xmalloc (sgml_len);
-    memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
+    drec->info[recInfo_storeData] = (char *) xmalloc(sgml_len);
+    memcpy(drec->info[recInfo_storeData], sgml_buf, sgml_len);
     drec->size[recInfo_storeData] = sgml_len;
     drec->size[recInfo_storeData] = sgml_len;
-    
-    rec_put (zei->records, &drec);
+
+    rec_put(zei->records, &drec);
 }
 
 }
 
-static void writeAttributeValues (ZebraExplainInfo zei,
+static void writeAttributeValues(ZebraExplainInfo zei,
                                  data1_node *node_values,
                                  data1_attset *attset)
 {
                                  data1_node *node_values,
                                  data1_attset *attset)
 {
@@ -1029,23 +1198,24 @@ static void writeAttributeValues (ZebraExplainInfo zei,
        return;
 
     for (c = attset->children; c; c = c->next)
        return;
 
     for (c = attset->children; c; c = c->next)
-       writeAttributeValues (zei, node_values, c->child);
+       writeAttributeValues(zei, node_values, c->child);
     for (atts = attset->atts; atts; atts = atts->next)
     {
        data1_node *node_value;
     for (atts = attset->atts; atts; atts = atts->next)
     {
        data1_node *node_value;
-       
-       node_value = data1_add_tag (zei->dh, node_values, "attributeValue",
-                                   zei->nmem);
-       data1_add_tagdata_text (zei->dh, node_value, "name",
+
+       node_value = data1_mk_tag(zei->dh, zei->nmem, "attributeValue",
+                                   0 /* attr */, node_values);
+       data1_mk_tag_data_text(zei->dh, node_value, "name",
                                atts->name, zei->nmem);
                                atts->name, zei->nmem);
-        node_value = data1_add_tag (zei->dh, node_value, "value", zei->nmem);
-       data1_add_tagdata_int (zei->dh, node_value, "numeric",
+        node_value = data1_mk_tag(zei->dh, zei->nmem, "value",
+                                   0 /* attr */, node_value);
+       data1_mk_tag_data_int(zei->dh, node_value, "numeric",
                               atts->value, zei->nmem);
     }
 }
 
 
                               atts->value, zei->nmem);
     }
 }
 
 
-static void zebraExplain_writeAttributeSet (ZebraExplainInfo zei,
+static void zebraExplain_writeAttributeSet(ZebraExplainInfo zei,
                                            zebAccessObject o,
                                            int key_flush)
 {
                                            zebAccessObject o,
                                            int key_flush)
 {
@@ -1054,49 +1224,51 @@ static void zebraExplain_writeAttributeSet (ZebraExplainInfo zei,
     Record drec;
     data1_node *node_root, *node_attinfo, *node_attributes, *node_atttype;
     data1_node *node_values;
     Record drec;
     data1_node *node_root, *node_attinfo, *node_attributes, *node_atttype;
     data1_node *node_values;
-    struct oident *entp;
-    struct data1_attset *attset = NULL;
-    
-    if ((entp = oid_getentbyoid (o->oid)))
-       attset = data1_attset_search_id (zei->dh, entp->value);
-           
+    struct data1_attset *attset = 0;
+
+    if (o->oid)
+       attset = data1_attset_search_id(zei->dh, o->oid);
+
 #if ZINFO_DEBUG
 #if ZINFO_DEBUG
-    logf (LOG_LOG, "zebraExplain_writeAttributeSet %s",
-         attset ? attset->name : "<unknown>");    
+    yaz_log(YLOG_LOG, "zebraExplain_writeAttributeSet %s",
+         attset ? attset->name : "<unknown>");
 #endif
 
 #endif
 
-    drec = createRecord (zei->records, &o->sysno);
+    drec = createRecord(zei->records, &o->sysno);
+    if (!drec)
+       return;
     node_root =
     node_root =
-       data1_read_sgml (zei->dh, zei->nmem,
+       data1_read_sgml(zei->dh, zei->nmem,
                         "<explain><attributeSetInfo>AttributeSetInfo\n"
                         "</></>\n" );
 
                         "<explain><attributeSetInfo>AttributeSetInfo\n"
                         "</></>\n" );
 
-    node_attinfo = data1_search_tag (zei->dh, node_root->child,
-                                  "attributeSetInfo");
+    node_attinfo = data1_search_tag(zei->dh, node_root,
+                                  "/attributeSetInfo");
 
 
-    zebraExplain_initCommonInfo (zei, node_attinfo);
-    zebraExplain_updateCommonInfo (zei, node_attinfo);
+    assert(node_attinfo);
+    zebraExplain_initCommonInfo(zei, node_attinfo);
+    zebraExplain_updateCommonInfo(zei, node_attinfo);
 
 
-    data1_add_tagdata_oid (zei->dh, node_attinfo,
+    data1_mk_tag_data_oid(zei->dh, node_attinfo,
                            "oid", o->oid, zei->nmem);
     if (attset && attset->name)
                            "oid", o->oid, zei->nmem);
     if (attset && attset->name)
-       data1_add_tagdata_text (zei->dh, node_attinfo,
+       data1_mk_tag_data_text(zei->dh, node_attinfo,
                                "name", attset->name, zei->nmem);
                                "name", attset->name, zei->nmem);
-    
-    node_attributes = data1_make_tag (zei->dh, node_attinfo,
-                                     "attributes", zei->nmem);
-    node_atttype = data1_make_tag (zei->dh, node_attributes,
-                                  "attributeType", zei->nmem);
-    data1_add_tagdata_text (zei->dh, node_atttype,
+
+    node_attributes = data1_mk_tag_uni(zei->dh, zei->nmem,
+                                     "attributes", node_attinfo);
+    node_atttype = data1_mk_tag_uni(zei->dh, zei->nmem,
+                                  "attributeType", node_attributes);
+    data1_mk_tag_data_text(zei->dh, node_atttype,
                            "name", "Use", zei->nmem);
                            "name", "Use", zei->nmem);
-    data1_add_tagdata_text (zei->dh, node_atttype,
+    data1_mk_tag_data_text(zei->dh, node_atttype,
                            "description", "Use Attribute", zei->nmem);
                            "description", "Use Attribute", zei->nmem);
-    data1_add_tagdata_int (zei->dh, node_atttype,
+    data1_mk_tag_data_int(zei->dh, node_atttype,
                           "type", 1, zei->nmem);
                           "type", 1, zei->nmem);
-    node_values = data1_add_tag (zei->dh, node_atttype,
-                                "attributeValues", zei->nmem);
+    node_values = data1_mk_tag(zei->dh, zei->nmem,
+                                "attributeValues", 0 /* attr */, node_atttype);
     if (attset)
     if (attset)
-       writeAttributeValues (zei, node_values, attset);
+       writeAttributeValues(zei, node_values, attset);
 
     /* extract *searchable* keys from it. We do this here, because
        record count, etc. is affected */
 
     /* extract *searchable* keys from it. We do this here, because
        record count, etc. is affected */
@@ -1104,17 +1276,17 @@ static void zebraExplain_writeAttributeSet (ZebraExplainInfo zei,
        (*zei->updateFunc)(zei->updateHandle, drec, node_root);
     /* convert to "SGML" and write it */
 #if ZINFO_DEBUG
        (*zei->updateFunc)(zei->updateHandle, drec, node_root);
     /* convert to "SGML" and write it */
 #if ZINFO_DEBUG
-    data1_pr_tree (zei->dh, node_root, stderr);
+    data1_pr_tree(zei->dh, node_root, stderr);
 #endif
     sgml_buf = data1_nodetoidsgml(zei->dh, node_root, 0, &sgml_len);
 #endif
     sgml_buf = data1_nodetoidsgml(zei->dh, node_root, 0, &sgml_len);
-    drec->info[recInfo_storeData] = xmalloc (sgml_len);
-    memcpy (drec->info[recInfo_storeData], sgml_buf, sgml_len);
+    drec->info[recInfo_storeData] = (char *) xmalloc(sgml_len);
+    memcpy(drec->info[recInfo_storeData], sgml_buf, sgml_len);
     drec->size[recInfo_storeData] = sgml_len;
     drec->size[recInfo_storeData] = sgml_len;
-    
-    rec_put (zei->records, &drec);
+
+    rec_put(zei->records, &drec);
 }
 
 }
 
-static void zebraExplain_writeTarget (ZebraExplainInfo zei, int key_flush)
+static void zebraExplain_writeTarget(ZebraExplainInfo zei, int key_flush)
 {
     struct zebDatabaseInfoB *zdi;
     data1_node *node_tgtinfo, *node_list, *node_zebra;
 {
     struct zebDatabaseInfoB *zdi;
     data1_node *node_tgtinfo, *node_list, *node_zebra;
@@ -1126,137 +1298,272 @@ static void zebraExplain_writeTarget (ZebraExplainInfo zei, int key_flush)
        return;
     zei->dirty = 0;
 
        return;
     zei->dirty = 0;
 
-    trec = rec_get (zei->records, 1);
-    xfree (trec->info[recInfo_storeData]);
+    trec = rec_get_root(zei->records);
+    xfree(trec->info[recInfo_storeData]);
 
 
-    node_tgtinfo = data1_search_tag (zei->dh, zei->data1_target->child,
-                                  "targetInfo");
-    assert (node_tgtinfo);
+    node_tgtinfo = data1_search_tag(zei->dh, zei->data1_target,
+                                     "/targetInfo");
+    assert(node_tgtinfo);
 
 
-    zebraExplain_updateCommonInfo (zei, node_tgtinfo);
-    zebraExplain_updateAccessInfo (zei, node_tgtinfo, zei->accessInfo);
+    zebraExplain_updateCommonInfo(zei, node_tgtinfo);
+    zebraExplain_updateAccessInfo(zei, node_tgtinfo, zei->accessInfo);
 
 
+    node_zebra = data1_mk_tag_uni(zei->dh, zei->nmem,
+                                "zebraInfo", node_tgtinfo);
     /* convert to "SGML" and write it */
     if (key_flush)
        (*zei->updateFunc)(zei->updateHandle, trec, zei->data1_target);
 
     /* convert to "SGML" and write it */
     if (key_flush)
        (*zei->updateFunc)(zei->updateHandle, trec, zei->data1_target);
 
-    node_zebra = data1_make_tag (zei->dh, node_tgtinfo,
-                                "zebraInfo", zei->nmem);
-    data1_add_tagdata_text (zei->dh, node_zebra, "version",
+    data1_mk_tag_data_text(zei->dh, node_zebra, "version",
                               ZEBRAVER, zei->nmem);
                               ZEBRAVER, zei->nmem);
-    node_list = data1_add_tag (zei->dh, node_zebra,
-                                 "databaseList", zei->nmem);
+    node_list = data1_mk_tag(zei->dh, zei->nmem,
+                              "databaseList", 0 /* attr */, node_zebra);
     for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
     {
        data1_node *node_db;
     for (zdi = zei->databaseInfo; zdi; zdi = zdi->next)
     {
        data1_node *node_db;
-       node_db = data1_add_tag (zei->dh, node_list,
-                                   "database", zei->nmem);
-       data1_add_tagdata_text (zei->dh, node_db, "name",
-                                  zdi->databaseName, zei->nmem);
-       data1_add_tagdata_int (zei->dh, node_db, "id",
-                                 zdi->sysno, zei->nmem);
-       data1_add_tagdata_int (zei->dh, node_db, "attributeDetailsId",
-                                 zdi->attributeDetails->sysno, zei->nmem);
+       node_db = data1_mk_tag(zei->dh, zei->nmem,
+                                "database", 0 /* attr */, node_list);
+       data1_mk_tag_data_text(zei->dh, node_db, "name",
+                                zdi->databaseName, zei->nmem);
+       data1_mk_tag_data_zint(zei->dh, node_db, "id",
+                               zdi->sysno, zei->nmem);
+       data1_mk_tag_data_zint(zei->dh, node_db, "attributeDetailsId",
+                               zdi->attributeDetails->sysno, zei->nmem);
     }
     }
-    data1_add_tagdata_int (zei->dh, node_zebra, "ordinalSU",
-                             zei->ordinalSU, zei->nmem);
+    data1_mk_tag_data_int(zei->dh, node_zebra, "ordinalSU",
+                           zei->ordinalSU, zei->nmem);
 
 
-    data1_add_tagdata_int (zei->dh, node_zebra, "runNumber",
-                             zei->runNumber, zei->nmem);
+    data1_mk_tag_data_int(zei->dh, node_zebra, "ordinalDatabase",
+                           zei->ordinalDatabase, zei->nmem);
+
+    data1_mk_tag_data_zint(zei->dh, node_zebra, "runNumber",
+                           zei->runNumber, zei->nmem);
 
 #if ZINFO_DEBUG
 
 #if ZINFO_DEBUG
-    data1_pr_tree (zei->dh, zei->data1_target, stderr);
+    data1_pr_tree(zei->dh, zei->data1_target, stderr);
 #endif
     sgml_buf = data1_nodetoidsgml(zei->dh, zei->data1_target,
                                  0, &sgml_len);
 #endif
     sgml_buf = data1_nodetoidsgml(zei->dh, zei->data1_target,
                                  0, &sgml_len);
-    trec->info[recInfo_storeData] = xmalloc (sgml_len);
-    memcpy (trec->info[recInfo_storeData], sgml_buf, sgml_len);
+    trec->info[recInfo_storeData] = (char *) xmalloc(sgml_len);
+    memcpy(trec->info[recInfo_storeData], sgml_buf, sgml_len);
     trec->size[recInfo_storeData] = sgml_len;
     trec->size[recInfo_storeData] = sgml_len;
-    
-    rec_put (zei->records, &trec);
+
+    rec_put(zei->records, &trec);
 }
 
 }
 
-int zebraExplain_lookupSU (ZebraExplainInfo zei, int set, int use)
+int zebraExplain_lookup_attr_str(ZebraExplainInfo zei,
+                                 zinfo_index_category_t cat,
+                                 const char *index_type,
+                                const char *str)
+{
+    struct zebSUInfoB **zsui;
+
+    assert(zei->curDatabaseInfo);
+    for (zsui = &zei->curDatabaseInfo->attributeDetails->SUInfo;
+        *zsui; zsui = &(*zsui)->next)
+        if ( (index_type == 0
+              || !strcmp((*zsui)->info.index_type, index_type))
+             && (*zsui)->info.cat == cat
+             && !yaz_matchstr((*zsui)->info.str, str))
+        {
+            struct zebSUInfoB *zsui_this = *zsui;
+
+            /* take it out of the list and move to front */
+            *zsui = (*zsui)->next;
+            zsui_this->next = zei->curDatabaseInfo->attributeDetails->SUInfo;
+            zei->curDatabaseInfo->attributeDetails->SUInfo = zsui_this;
+
+            return zsui_this->info.ordinal;
+        }
+    return -1;
+}
+
+int zebraExplain_trav_ord(ZebraExplainInfo zei, void *handle,
+                         int (*f)(void *handle, int ord,
+                                   const char *index_type,
+                                   const char *string_index,
+                                   zinfo_index_category_t cat))
+{
+    struct zebDatabaseInfoB *zdb = zei->curDatabaseInfo;
+    if (zdb)
+    {
+       struct zebSUInfoB *zsui = zdb->attributeDetails->SUInfo;
+       for ( ;zsui; zsui = zsui->next)
+           (*f)(handle,  zsui->info.ordinal,
+                 zsui->info.index_type, zsui->info.str,
+                 zsui->info.cat);
+    }
+    return 0;
+}
+
+
+struct zebSUInfoB *zebraExplain_get_sui_info(ZebraExplainInfo zei, int ord,
+                                              int dirty_mark,
+                                              const char **db)
+{
+    struct zebDatabaseInfoB *zdb;
+
+    for (zdb = zei->databaseInfo; zdb; zdb = zdb->next)
+    {
+       struct zebSUInfoB **zsui;
+
+       if (zdb->attributeDetails->readFlag)
+           zebraExplain_readAttributeDetails(zei, zdb->attributeDetails);
+
+       for (zsui = &zdb->attributeDetails->SUInfo; *zsui;
+             zsui = &(*zsui)->next)
+           if ((*zsui)->info.ordinal == ord)
+            {
+                struct zebSUInfoB *zsui_this = *zsui;
+
+                /* take it out of the list and move to front */
+                *zsui = (*zsui)->next;
+                zsui_this->next = zdb->attributeDetails->SUInfo;
+                zdb->attributeDetails->SUInfo = zsui_this;
+
+                if (dirty_mark)
+                    zdb->attributeDetails->dirty = 1;
+                if (db)
+                    *db = zdb->databaseName;
+                return zsui_this;
+            }
+    }
+    return 0;
+}
+
+
+
+int zebraExplain_ord_adjust_occurrences(ZebraExplainInfo zei, int ord,
+                                        int term_delta, int doc_delta)
+{
+    struct zebSUInfoB *zsui = zebraExplain_get_sui_info(zei, ord, 1, 0);
+    if (zsui)
+    {
+        zsui->info.term_occurrences += term_delta;
+        zsui->info.doc_occurrences += doc_delta;
+        return 0;
+    }
+    return -1;
+}
+
+int zebraExplain_ord_get_occurrences(ZebraExplainInfo zei, int ord,
+                                     zint *term_occurrences,
+                                     zint *doc_occurrences)
+{
+    struct zebSUInfoB *zsui = zebraExplain_get_sui_info(zei, ord, 0, 0);
+    if (zsui)
+    {
+        *term_occurrences = zsui->info.term_occurrences;
+        *doc_occurrences = zsui->info.doc_occurrences;
+        return 0;
+    }
+    return -1;
+}
+
+zint zebraExplain_ord_get_doc_occurrences(ZebraExplainInfo zei, int ord)
+{
+    struct zebSUInfoB *zsui = zebraExplain_get_sui_info(zei, ord, 0, 0);
+    if (zsui)
+        return zsui->info.doc_occurrences;
+    return 0;
+}
+
+zint zebraExplain_ord_get_term_occurrences(ZebraExplainInfo zei, int ord)
+{
+    struct zebSUInfoB *zsui = zebraExplain_get_sui_info(zei, ord, 0, 0);
+    if (zsui)
+        return zsui->info.term_occurrences;
+    return 0;
+}
+
+int zebraExplain_lookup_ord(ZebraExplainInfo zei, int ord,
+                           const char **index_type,
+                           const char **db,
+                           const char **string_index)
 {
     struct zebSUInfoB *zsui;
 
 {
     struct zebSUInfoB *zsui;
 
-    assert (zei->curDatabaseInfo);
-    for (zsui = zei->curDatabaseInfo->attributeDetails->SUInfo;
-        zsui; zsui=zsui->next)
-        if (zsui->info.use == use && zsui->info.set == set)
-            return zsui->info.ordinal;
+    if (index_type)
+       *index_type = 0;
+    if (string_index)
+       *string_index = 0;
+
+    zsui = zebraExplain_get_sui_info(zei, ord, 0, db);
+    if (zsui)
+    {
+        if (string_index)
+            *string_index = zsui->info.str;
+        if (index_type)
+            *index_type = zsui->info.index_type;
+        return 0;
+    }
     return -1;
 }
 
     return -1;
 }
 
-zebAccessObject zebraExplain_announceOid (ZebraExplainInfo zei,
+
+
+zebAccessObject zebraExplain_announceOid(ZebraExplainInfo zei,
                                          zebAccessObject *op,
                                          Odr_oid *oid)
 {
     zebAccessObject ao;
                                          zebAccessObject *op,
                                          Odr_oid *oid)
 {
     zebAccessObject ao;
-    
+
     for (ao = *op; ao; ao = ao->next)
     for (ao = *op; ao; ao = ao->next)
-       if (!oid_oidcmp (oid, ao->oid))
+       if (!oid_oidcmp(oid, ao->oid))
            break;
     if (!ao)
     {
            break;
     if (!ao)
     {
-       ao = nmem_malloc (zei->nmem, sizeof(*ao));
-       ao->handle = NULL;
+       ao = (zebAccessObject) nmem_malloc(zei->nmem, sizeof(*ao));
+       ao->handle = 0;
        ao->sysno = 0;
        ao->sysno = 0;
-       ao->oid = odr_oiddup_nmem (zei->nmem, oid);
+       ao->oid = odr_oiddup_nmem(zei->nmem, oid);
        ao->next = *op;
        *op = ao;
     }
     return ao;
 }
 
        ao->next = *op;
        *op = ao;
     }
     return ao;
 }
 
-void zebraExplain_addAttributeSet (ZebraExplainInfo zei, int set)
-{
-    oident oe;
-    int oid[OID_SIZE];
-
-    oe.proto = PROTO_Z3950;
-    oe.oclass = CLASS_ATTSET;
-    oe.value = set;
-
-    if (oid_ent_to_oid (&oe, oid))
-    {
-       zebraExplain_announceOid (zei, &zei->accessInfo->attributeSetIds, oid);
-       zebraExplain_announceOid (zei, &zei->curDatabaseInfo->
-                                 accessInfo->attributeSetIds, oid);
-    }
-}
-
-int zebraExplain_addSU (ZebraExplainInfo zei, int set, int use)
+struct zebSUInfoB *zebraExplain_add_sui_info(ZebraExplainInfo zei,
+                                             zinfo_index_category_t cat,
+                                             const char *index_type)
 {
     struct zebSUInfoB *zsui;
 
 {
     struct zebSUInfoB *zsui;
 
-    assert (zei->curDatabaseInfo);
-    for (zsui = zei->curDatabaseInfo->attributeDetails->SUInfo;
-        zsui; zsui=zsui->next)
-        if (zsui->info.use == use && zsui->info.set == set)
-            return -1;
-    zebraExplain_addAttributeSet (zei, set);
-    zsui = nmem_malloc (zei->nmem, sizeof(*zsui));
+    assert(zei->curDatabaseInfo);
+    zsui = (struct zebSUInfoB *) nmem_malloc(zei->nmem, sizeof(*zsui));
     zsui->next = zei->curDatabaseInfo->attributeDetails->SUInfo;
     zei->curDatabaseInfo->attributeDetails->SUInfo = zsui;
     zei->curDatabaseInfo->attributeDetails->dirty = 1;
     zei->dirty = 1;
     zsui->next = zei->curDatabaseInfo->attributeDetails->SUInfo;
     zei->curDatabaseInfo->attributeDetails->SUInfo = zsui;
     zei->curDatabaseInfo->attributeDetails->dirty = 1;
     zei->dirty = 1;
-    zsui->info.set = set;
-    zsui->info.use = use;
+    zsui->info.index_type = nmem_strdup(zei->nmem, index_type);
+    zsui->info.cat = cat;
+    zsui->info.doc_occurrences = 0;
+    zsui->info.term_occurrences = 0;
     zsui->info.ordinal = (zei->ordinalSU)++;
     zsui->info.ordinal = (zei->ordinalSU)++;
+    return zsui;
+}
+
+int zebraExplain_add_attr_str(ZebraExplainInfo zei,
+                              zinfo_index_category_t cat,
+                              const char *index_type,
+                             const char *index_name)
+{
+    struct zebSUInfoB *zsui = zebraExplain_add_sui_info(zei, cat, index_type);
+
+    zsui->info.str = nmem_strdup(zei->nmem, index_name);
     return zsui->info.ordinal;
 }
 
     return zsui->info.ordinal;
 }
 
-void zebraExplain_addSchema (ZebraExplainInfo zei, Odr_oid *oid)
+void zebraExplain_addSchema(ZebraExplainInfo zei, Odr_oid *oid)
 {
 {
-    zebraExplain_announceOid (zei, &zei->accessInfo->schemas, oid);
-    zebraExplain_announceOid (zei, &zei->curDatabaseInfo->
+    zebraExplain_announceOid(zei, &zei->accessInfo->schemas, oid);
+    zebraExplain_announceOid(zei, &zei->curDatabaseInfo->
                              accessInfo->schemas, oid);
 }
 
                              accessInfo->schemas, oid);
 }
 
-void zebraExplain_recordBytesIncrement (ZebraExplainInfo zei, int adjust_num)
+void zebraExplain_recordBytesIncrement(ZebraExplainInfo zei, int adjust_num)
 {
 {
-    assert (zei->curDatabaseInfo);
+    assert(zei->curDatabaseInfo);
 
     if (adjust_num)
     {
 
     if (adjust_num)
     {
@@ -1265,9 +1572,9 @@ void zebraExplain_recordBytesIncrement (ZebraExplainInfo zei, int adjust_num)
     }
 }
 
     }
 }
 
-void zebraExplain_recordCountIncrement (ZebraExplainInfo zei, int adjust_num)
+void zebraExplain_recordCountIncrement(ZebraExplainInfo zei, int adjust_num)
 {
 {
-    assert (zei->curDatabaseInfo);
+    assert(zei->curDatabaseInfo);
 
     if (adjust_num)
     {
 
     if (adjust_num)
     {
@@ -1276,37 +1583,49 @@ void zebraExplain_recordCountIncrement (ZebraExplainInfo zei, int adjust_num)
     }
 }
 
     }
 }
 
-int zebraExplain_runNumberIncrement (ZebraExplainInfo zei, int adjust_num)
+zint zebraExplain_runNumberIncrement(ZebraExplainInfo zei, int adjust_num)
 {
     if (adjust_num)
 {
     if (adjust_num)
+    {
        zei->dirty = 1;
        zei->dirty = 1;
+    }
     return zei->runNumber += adjust_num;
 }
 
     return zei->runNumber += adjust_num;
 }
 
-RecordAttr *rec_init_attr (ZebraExplainInfo zei, Record rec)
+RecordAttr *rec_init_attr(ZebraExplainInfo zei, Record rec)
 {
     RecordAttr *recordAttr;
 
     if (rec->info[recInfo_attr])
        return (RecordAttr *) rec->info[recInfo_attr];
 {
     RecordAttr *recordAttr;
 
     if (rec->info[recInfo_attr])
        return (RecordAttr *) rec->info[recInfo_attr];
-    recordAttr = xmalloc (sizeof(*recordAttr));
+    recordAttr = (RecordAttr *) xmalloc(sizeof(*recordAttr));
+
+    memset(recordAttr, '\0', sizeof(*recordAttr));
     rec->info[recInfo_attr] = (char *) recordAttr;
     rec->size[recInfo_attr] = sizeof(*recordAttr);
     rec->info[recInfo_attr] = (char *) recordAttr;
     rec->size[recInfo_attr] = sizeof(*recordAttr);
-    
+
     recordAttr->recordSize = 0;
     recordAttr->recordOffset = 0;
     recordAttr->runNumber = zei->runNumber;
     recordAttr->recordSize = 0;
     recordAttr->recordOffset = 0;
     recordAttr->runNumber = zei->runNumber;
+    recordAttr->staticrank = 0;
     return recordAttr;
 }
 
 static void att_loadset(void *p, const char *n, const char *name)
 {
     return recordAttr;
 }
 
 static void att_loadset(void *p, const char *n, const char *name)
 {
-    data1_handle dh = p;
-    if (!data1_get_attset (dh, name))
-       logf (LOG_WARN, "Couldn't load attribute set %s", name);
+    data1_handle dh = (data1_handle) p;
+    if (!data1_get_attset(dh, name))
+       yaz_log(YLOG_WARN, "Directive attset failed for %s", name);
+}
+
+int zebraExplain_get_database_ord(ZebraExplainInfo zei)
+{
+    if (!zei->curDatabaseInfo)
+       return -1;
+    return zei->curDatabaseInfo->ordinalDatabase;
 }
 
 }
 
-void zebraExplain_loadAttsets (data1_handle dh, Res res)
+void zebraExplain_loadAttsets(data1_handle dh, Res res)
 {
     res_trav(res, "attset", dh, att_loadset);
 }
 {
     res_trav(res, "attset", dh, att_loadset);
 }
@@ -1316,6 +1635,15 @@ void zebraExplain_loadAttsets (data1_handle dh, Res res)
      adds attributeSet (in AccessInfo area) to DatabaseInfo if it doesn't
      exist for the database.
 
      adds attributeSet (in AccessInfo area) to DatabaseInfo if it doesn't
      exist for the database.
 
-     If the database doesn't exist globally (in TargetInfo) an 
+     If the database doesn't exist globally (in TargetInfo) an
      AttributeSetInfo must be added (globally).
  */
      AttributeSetInfo must be added (globally).
  */
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+