Do not build for Debian lenny anymore
[idzebra-moved-to-github.git] / dict / delete.c
index cb9d64d..d81c384 100644 (file)
-/*
- * Copyright (C) 1994, Index Data I/S 
- * All rights reserved.
- * Sebastian Hammer, Adam Dickmeiss
- *
- * $Log: delete.c,v $
- * Revision 1.4  1996-02-02 13:43:50  adam
- * The public functions simply use char instead of Dict_char to represent
- * search strings. Dict_char is used internally only.
- *
- * Revision 1.3  1995/12/07  11:48:55  adam
- * Insert operation obeys DICT_type = 1 (slack in page).
- * Function dict_open exists if page size or magic aren't right.
- *
- * Revision 1.2  1995/12/06  17:48:30  adam
- * Bug fix: delete didn't work.
- *
- * Revision 1.1  1995/12/06  14:52:21  adam
- * New function: dict_delete.
- *
- */
+/* This file is part of the Zebra server.
+   Copyright (C) 1994-2011 Index Data
+
+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 <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <assert.h>
 
-#include <dict.h>
+#include "dict-p.h"
 
-static int dict_del (Dict dict, const Dict_char *str)
+static void dict_del_subtree(Dict dict, Dict_ptr ptr,
+                             void *client, 
+                             int (*f)(const char *, void *))
+{
+    void *p = 0;
+    short *indxp;
+    int i, hi;
+    
+    if (!ptr)
+       return;
+       
+    dict_bf_readp(dict->dbf, ptr, &p);
+    indxp = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));
+    hi = DICT_nodir(p)-1;
+    for (i = 0; i <= hi; i++)
+    {
+       if (indxp[-i] > 0)
+       {
+           /* string (Dict_char *) DICT_EOS terminated */
+           /* unsigned char        length of information */
+           /* char *               information */
+           char *info = (char*)p + indxp[-i];
+           if (f)
+               (*f)(info + (dict_strlen((Dict_char*) info)+1)
+                    *sizeof(Dict_char), client);
+       }
+       else
+       {
+           Dict_ptr subptr;
+           
+           /* Dict_ptr             subptr */
+           /* Dict_char            sub char */
+           /* unsigned char        length of information */
+           /* char *               information */
+           char *info = (char*)p - indxp[-i];
+           memcpy(&subptr, info, sizeof(Dict_ptr));
+           
+           if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
+           {
+               if (f)
+                   (*f)(info+sizeof(Dict_ptr)+sizeof(Dict_char), client);
+           }
+           if (subptr)
+           {
+               dict_del_subtree(dict, subptr, client, f);
+       
+               /* page may be gone. reread it .. */
+               dict_bf_readp(dict->dbf, ptr, &p);
+               indxp = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));
+           }
+       }
+    }
+    DICT_backptr(p) = dict->head.freelist;
+    dict->head.freelist = ptr;
+    dict_bf_touch(dict->dbf, ptr);
+}
+
+static int dict_del_string(Dict dict, const Dict_char *str, Dict_ptr ptr,
+                           int sub_flag, void *client, 
+                           int (*f)(const char *, void *))
 {
-    Dict_ptr ptr = 1;
     int mid, lo, hi;
     int cmp;
     void *p;
     short *indxp;
     char *info;
+    int r = 0;
+    Dict_ptr subptr = 0;
 
-    dict_bf_readp (dict->dbf, ptr, &p);
+    if (!ptr)
+       return 0;
+    dict_bf_readp(dict->dbf, ptr, &p);
     mid = lo = 0;
     hi = DICT_nodir(p)-1;
-    indxp = (short*) ((char*) p+DICT_pagesize(dict)-sizeof(short));    
+    indxp = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));    
     while (lo <= hi)
     {
         mid = (lo+hi)/2;
@@ -49,59 +111,132 @@ static int dict_del (Dict dict, const Dict_char *str)
             /* unsigned char        length of information */
             /* char *               information */
             info = (char*)p + indxp[-mid];
-            cmp = dict_strcmp((Dict_char*) info, str);
-            if (!cmp)
-            {
-                hi = DICT_nodir(p)-1;
-                while (mid < hi)
-                {
-                    indxp[-mid] = indxp[-mid-1];
-                    mid++;
-                }
-                DICT_type(p) = 1;
-                (DICT_nodir(p))--;
-                dict_bf_touch (dict->dbf, ptr);
-                return 1;
-            }
+
+           cmp = dict_strcmp((Dict_char*) info, str);
+           if (sub_flag)
+           {
+               /* determine if prefix match */
+               if (!dict_strncmp(str, (Dict_char*) info, dict_strlen(str)))
+               {
+                   if (f)
+                       (*f)(info + (dict_strlen((Dict_char*) info)+1)
+                            *sizeof(Dict_char), client);
+
+                   hi = DICT_nodir(p)-1;
+                   while (mid < hi)
+                   {
+                       indxp[-mid] = indxp[-mid-1];
+                       mid++;
+                   }
+                   DICT_type(p) = 1;
+                   (DICT_nodir(p))--;
+                   dict_bf_touch(dict->dbf, ptr);
+                   --hi;
+                   mid = lo = 0;
+                    r = 1; /* signal deleted */
+                    /* start again (may not be the most efficient way to go)*/
+                   continue; 
+               }
+           }
+           else
+           {
+               /* normal delete: delete if equal */
+               if (!cmp)
+               {
+                   hi = DICT_nodir(p)-1;
+                   while (mid < hi)
+                   {
+                       indxp[-mid] = indxp[-mid-1];
+                       mid++;
+                   }
+                   DICT_type(p) = 1;
+                   (DICT_nodir(p))--;
+                   dict_bf_touch(dict->dbf, ptr);
+                    r = 1;
+                    break;
+               }
+           }
         }
         else
         {
             Dict_char dc;
-            Dict_ptr subptr;
 
             /* Dict_ptr             subptr */
             /* Dict_char            sub char */
             /* unsigned char        length of information */
             /* char *               information */
             info = (char*)p - indxp[-mid];
-            memcpy (&dc, info+sizeof(Dict_ptr), sizeof(Dict_char));
+            memcpy(&dc, info+sizeof(Dict_ptr), sizeof(Dict_char));
             cmp = dc- *str;
             if (!cmp)
             {
-                memcpy (&subptr, info, sizeof(Dict_ptr));
+                memcpy(&subptr, info, sizeof(Dict_ptr));
                 if (*++str == DICT_EOS)
                 {
                     if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
                     {
+                        /* entry does exist. Wipe it out */
                         info[sizeof(Dict_ptr)+sizeof(Dict_char)] = 0;
                         DICT_type(p) = 1;
-                        dict_bf_touch (dict->dbf, ptr);
-                        return 1;
+                        dict_bf_touch(dict->dbf, ptr);
+
+                       if (f)
+                           (*f)(info+sizeof(Dict_ptr)+sizeof(Dict_char),
+                                client);
+                        r = 1;
                     }
-                    return 0;
+                   if (sub_flag)
+                   {
+                        /* must delete all suffixes (subtrees) as well */
+                        hi = DICT_nodir(p)-1;
+                        while (mid < hi)
+                        {
+                            indxp[-mid] = indxp[-mid-1];
+                            mid++;
+                        }
+                        (DICT_nodir(p))--;
+                        DICT_type(p) = 1;
+                        dict_bf_touch(dict->dbf, ptr);
+                   }
                 }
                 else
                 {
-                    if (subptr == 0)
-                        return 0;
-                    ptr = subptr;
-                    dict_bf_readp (dict->dbf, ptr, &p);
-                    mid = lo = 0;
-                    hi = DICT_nodir(p)-1;
-                    indxp = (short*) ((char*) p+DICT_pagesize(dict)
-                                      -sizeof(short));
-                    continue;
+                    /* subptr may be 0 */
+                    r = dict_del_string(dict, str, subptr, sub_flag, client, f);
+
+                    /* recover */
+                    dict_bf_readp(dict->dbf, ptr, &p);
+                    indxp = (short*)
+                        ((char*) p+DICT_bsize(p)-sizeof(short));
+                    info = (char*)p - indxp[-mid];
+
+                    subptr = 0; /* avoid dict_del_subtree (end of function)*/
+                    if (r == 2)
+                    {   /* subptr page became empty and is removed */
+                        
+                        /* see if this entry is a real one or if it just
+                           serves as pointer to subptr */
+                        if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
+                        {
+                            /* this entry do exist, set subptr to 0 */
+                            memcpy(info, &subptr, sizeof(subptr));
+                        }
+                        else
+                        {
+                            /* this entry ONLY points to subptr. remove it */
+                            hi = DICT_nodir(p)-1;
+                            while (mid < hi)
+                            {
+                                indxp[-mid] = indxp[-mid-1];
+                                mid++;
+                            }
+                            (DICT_nodir(p))--;
+                        }
+                        dict_bf_touch(dict->dbf, ptr);
+                        r = 1;
+                    }
                 }
+                break;
             }
         }
         if (cmp < 0)
@@ -109,12 +244,37 @@ static int dict_del (Dict dict, const Dict_char *str)
         else
             hi = mid-1;
     }
-    return 0;
+    if (DICT_nodir(p) == 0 && ptr != dict->head.root)
+    {
+        DICT_backptr(p) = dict->head.freelist;
+        dict->head.freelist = ptr;
+        dict_bf_touch(dict->dbf, ptr);
+        r = 2;
+    }
+    if (subptr && sub_flag)
+        dict_del_subtree(dict, subptr, client, f);
+
+    return r;
+}
+
+int dict_delete(Dict dict, const char *p)
+{
+    return dict_del_string(dict, (const Dict_char*) p, dict->head.root, 0,
+                           0, 0);
 }
 
-int dict_delete (Dict dict, const char *p)
+int dict_delete_subtree(Dict dict, const char *p, void *client,
+                        int (*f)(const char *info, void *client))
 {
-    if (dict->head.last == 1)
-        return 0;
-    return dict_del (dict, (const Dict_char*) p);
+    return dict_del_string(dict, (const Dict_char*) p, dict->head.root, 1,
+                           client, f);
 }
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+