X-Path attribute expressions with spaces in them is now handled.
[idzebra-moved-to-github.git] / isamb / isamb.c
index 2ac59fb..e2042d1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isamb.c,v 1.23 2003-03-02 23:12:50 adam Exp $
+/* $Id: isamb.c,v 1.27 2003-06-23 15:36:11 adam Exp $
    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003
    Index Data Aps
 
@@ -45,7 +45,7 @@ struct ISAMB_head {
 
 struct ISAMB_cache_entry {
     ISAMB_P pos;
-    char *buf;
+    unsigned char *buf;
     int dirty;
     int hits;
     struct ISAMB_cache_entry *next;
@@ -61,7 +61,7 @@ struct ISAMB_file {
 
 struct ISAMB_s {
     BFiles bfs;
-    ISAMC_M method;
+    ISAMC_M *method;
 
     struct ISAMB_file *file;
     int no_cat;
@@ -105,19 +105,21 @@ void decode_ptr (char **src, int *pos)
     (*src) += sizeof(*pos);
 }
 
-ISAMB isamb_open (BFiles bfs, const char *name, int writeflag, ISAMC_M method,
+ISAMB isamb_open (BFiles bfs, const char *name, int writeflag, ISAMC_M *method,
                   int cache)
 {
     ISAMB isamb = xmalloc (sizeof(*isamb));
     int i, b_size = 32;
 
     isamb->bfs = bfs;
-    isamb->method = (ISAMC_M) xmalloc (sizeof(*method));
+    isamb->method = (ISAMC_M *) xmalloc (sizeof(*method));
     memcpy (isamb->method, method, sizeof(*method));
     isamb->no_cat = 4;
     isamb->log_io = 0;
+    isamb->log_freelist = 0;
     isamb->cache = cache;
 
+    assert (cache == 0);
     isamb->file = xmalloc (sizeof(*isamb->file) * isamb->no_cat);
     for (i = 0; i<isamb->no_cat; i++)
     {
@@ -273,14 +275,19 @@ struct ISAMB_block *open_block (ISAMB b, ISAMC_P pos)
         yaz_log (b->log_io, "bf_read: open_block");
         if (!bf_read (b->file[cat].bf, pos/4, 0, 0, p->buf))
         {
-            yaz_log (LOG_FATAL, "read failure for pos=%ld block=%ld",
+            yaz_log (LOG_FATAL, "isamb: read fail for pos=%ld block=%ld",
                      (long) pos, (long) pos/4);
             abort();
         }
     }
     p->bytes = p->buf + ISAMB_DATA_OFFSET;
     p->leaf = p->buf[0];
-    p->size = p->buf[1] + 256 * p->buf[2] - ISAMB_DATA_OFFSET;
+    p->size = (p->buf[1] + 256 * p->buf[2]) - ISAMB_DATA_OFFSET;
+    if (p->size < 0)
+    {
+        fprintf (stderr, "pos=%d\n", pos);
+    }
+    assert (p->size >= 0);
     p->offset = 0;
     p->dirty = 0;
     p->deleted = 0;
@@ -304,12 +311,13 @@ struct ISAMB_block *new_block (ISAMB b, int leaf, int cat)
     else
     {
         p->pos = b->file[cat].head.free_list;
+        assert((p->pos & 3) == cat);
         if (!get_block (b, p->pos, p->buf, 0))
         {
             yaz_log (b->log_io, "bf_read: new_block");
             if (!bf_read (b->file[cat].bf, p->pos/4, 0, 0, p->buf))
             {
-                yaz_log (LOG_FATAL, "read failure for pos=%ld block=%ld",
+                yaz_log (LOG_FATAL, "isamb: read fail for pos=%ld block=%ld",
                          (long) p->pos/4, (long) p->pos/4);
                 abort ();
             }
@@ -342,6 +350,34 @@ struct ISAMB_block *new_int (ISAMB b, int cat)
     return new_block (b, 0, cat);
 }
 
+static void check_block (ISAMB b, struct ISAMB_block *p)
+{
+    if (p->leaf)
+    {
+        ;
+    }
+    else
+    {
+        /* sanity check */
+        char *startp = p->bytes;
+        char *src = startp;
+        char *endp = p->bytes + p->size;
+        int pos;
+            
+        decode_ptr (&src, &pos);
+        assert ((pos&3) == p->cat);
+        while (src != endp)
+        {
+            int item_len;
+            decode_ptr (&src, &item_len);
+            assert (item_len > 0 && item_len < 30);
+            src += item_len;
+            decode_ptr (&src, &pos);
+            assert ((pos&3) == p->cat);
+        }
+    }
+}
+
 void close_block (ISAMB b, struct ISAMB_block *p)
 {
     if (!p)
@@ -354,16 +390,18 @@ void close_block (ISAMB b, struct ISAMB_block *p)
         b->file[p->cat].head.free_list = p->pos;
         if (!get_block (b, p->pos, p->buf, 1))
         {
-            yaz_log (b->log_io, "bf_write: close_block");
+            yaz_log (b->log_io, "bf_write: close_block (deleted)");
             bf_write (b->file[p->cat].bf, p->pos/4, 0, 0, p->buf);
         }
     }
     else if (p->dirty)
     {
         int size = p->size + ISAMB_DATA_OFFSET;
+        assert (p->size >= 0);
         p->buf[0] = p->leaf;
         p->buf[1] = size & 255;
         p->buf[2] = size >> 8;
+        check_block(b, p);
         if (!get_block (b, p->pos, p->buf, 1))
         {
             yaz_log (b->log_io, "bf_write: close_block");
@@ -377,14 +415,14 @@ void close_block (ISAMB b, struct ISAMB_block *p)
 
 int insert_sub (ISAMB b, struct ISAMB_block **p,
                 void *new_item, int *mode,
-                ISAMC_I stream,
+                ISAMC_I *stream,
                 struct ISAMB_block **sp,
                 void *sub_item, int *sub_size,
                 void *max_item);
 
 int insert_int (ISAMB b, struct ISAMB_block *p, void *lookahead_item,
                 int *mode,
-                ISAMC_I stream, struct ISAMB_block **sp,
+                ISAMC_I *stream, struct ISAMB_block **sp,
                 void *split_item, int *split_size, void *last_max_item)
 {
     char *startp = p->bytes;
@@ -398,11 +436,13 @@ int insert_int (ISAMB b, struct ISAMB_block *p, void *lookahead_item,
 
     *sp = 0;
 
+    assert(p->size >= 0);
     decode_ptr (&src, &pos);
     while (src != endp)
     {
         int item_len;
         int d;
+        char *src0 = src;
         decode_ptr (&src, &item_len);
         d = (*b->method->compare_item)(src, lookahead_item);
         if (d > 0)
@@ -412,6 +452,7 @@ int insert_int (ISAMB b, struct ISAMB_block *p, void *lookahead_item,
             more = insert_sub (b, &sub_p1, lookahead_item, mode,
                                stream, &sub_p2, 
                                sub_item, &sub_size, src);
+            src = src0;
             break;
         }
         src += item_len;
@@ -448,6 +489,7 @@ int insert_int (ISAMB b, struct ISAMB_block *p, void *lookahead_item,
             dst += endp - src;
         }
         p->size = dst - dst_buf;
+        assert (p->size >= 0);
         if (p->size <= b->file[p->cat].head.block_max)
         {
             memcpy (startp, dst_buf, dst - dst_buf);
@@ -489,7 +531,8 @@ int insert_int (ISAMB b, struct ISAMB_block *p, void *lookahead_item,
 
 
 int insert_leaf (ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
-                 int *lookahead_mode, ISAMC_I stream, struct ISAMB_block **sp2,
+                 int *lookahead_mode, ISAMC_I *stream,
+                struct ISAMB_block **sp2,
                  void *sub_item, int *sub_size,
                  void *max_item)
 {
@@ -529,7 +572,11 @@ int insert_leaf (ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
             if (d > 0)
             {
                 dst_item = lookahead_item;
-                assert (*lookahead_mode);
+                if (!*lookahead_mode)
+                {
+                    yaz_log (LOG_WARN, "isamb: Inconsistent register (1)");
+                    assert (*lookahead_mode);
+                }
             }
             else
                 dst_item = file_item_buf;
@@ -615,7 +662,7 @@ int insert_leaf (ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
         }
         if (!*lookahead_mode)
         {
-            yaz_log (LOG_WARN, "Inconsistent register (2)");
+            yaz_log (LOG_WARN, "isamb: Inconsistent register (2)");
             abort();
         }
         else if (!half1 && dst > cut)   
@@ -710,7 +757,7 @@ int insert_leaf (ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
 
 int insert_sub (ISAMB b, struct ISAMB_block **p, void *new_item,
                 int *mode,
-                ISAMC_I stream,
+                ISAMC_I *stream,
                 struct ISAMB_block **sp,
                 void *sub_item, int *sub_size,
                 void *max_item)
@@ -723,7 +770,36 @@ int insert_sub (ISAMB b, struct ISAMB_block **p, void *new_item,
                            sub_size, max_item);
 }
 
-int isamb_merge (ISAMB b, ISAMC_P pos, ISAMC_I stream)
+int isamb_unlink (ISAMB b, ISAMC_P pos)
+{
+    struct ISAMB_block *p1;
+
+    if (!pos)
+       return 0;
+    p1 = open_block(b, pos);
+    p1->deleted = 1;
+    if (!p1->leaf)
+    {
+       int sub_p;
+       int item_len;
+       char *src = p1->bytes + p1->offset;
+
+       decode_ptr(&src, &sub_p);
+       isamb_unlink(b, sub_p);
+       
+       while (src != p1->bytes + p1->size)
+       {
+           decode_ptr(&src, &item_len);
+           src += item_len;
+           decode_ptr(&src, &sub_p);
+           isamb_unlink(b, sub_p);
+       }
+    }
+    close_block(b, p1);
+    return 0;
+}
+
+int isamb_merge (ISAMB b, ISAMC_P pos, ISAMC_I *stream)
 {
     char item_buf[DST_ITEM_MAX];
     char *item_ptr;