eb5e41c7622ec084383704df5005aebfe660a1dc
[idzebra-moved-to-github.git] / dict / delete.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2010 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <assert.h>
24
25 #include "dict-p.h"
26
27 static void dict_del_subtree(Dict dict, Dict_ptr ptr,
28                              void *client, 
29                              int (*f)(const char *, void *))
30 {
31     void *p = 0;
32     short *indxp;
33     int i, hi;
34     
35     if (!ptr)
36         return;
37         
38     dict_bf_readp(dict->dbf, ptr, &p);
39     indxp = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));
40     hi = DICT_nodir(p)-1;
41     for (i = 0; i <= hi; i++)
42     {
43         if (indxp[-i] > 0)
44         {
45             /* string (Dict_char *) DICT_EOS terminated */
46             /* unsigned char        length of information */
47             /* char *               information */
48             char *info = (char*)p + indxp[-i];
49             if (f)
50                 (*f)(info + (dict_strlen((Dict_char*) info)+1)
51                      *sizeof(Dict_char), client);
52         }
53         else
54         {
55             Dict_ptr subptr;
56             
57             /* Dict_ptr             subptr */
58             /* Dict_char            sub char */
59             /* unsigned char        length of information */
60             /* char *               information */
61             char *info = (char*)p - indxp[-i];
62             memcpy(&subptr, info, sizeof(Dict_ptr));
63             
64             if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
65             {
66                 if (f)
67                     (*f)(info+sizeof(Dict_ptr)+sizeof(Dict_char), client);
68             }
69             if (subptr)
70             {
71                 dict_del_subtree(dict, subptr, client, f);
72         
73                 /* page may be gone. reread it .. */
74                 dict_bf_readp(dict->dbf, ptr, &p);
75                 indxp = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));
76             }
77         }
78     }
79     DICT_backptr(p) = dict->head.freelist;
80     dict->head.freelist = ptr;
81     dict_bf_touch(dict->dbf, ptr);
82 }
83
84 static int dict_del_string(Dict dict, const Dict_char *str, Dict_ptr ptr,
85                            int sub_flag, void *client, 
86                            int (*f)(const char *, void *))
87 {
88     int mid, lo, hi;
89     int cmp;
90     void *p;
91     short *indxp;
92     char *info;
93     int r = 0;
94     Dict_ptr subptr = 0;
95
96     if (!ptr)
97         return 0;
98     dict_bf_readp(dict->dbf, ptr, &p);
99     mid = lo = 0;
100     hi = DICT_nodir(p)-1;
101     indxp = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));    
102     while (lo <= hi)
103     {
104         mid = (lo+hi)/2;
105         if (indxp[-mid] > 0)
106         {
107             /* string (Dict_char *) DICT_EOS terminated */
108             /* unsigned char        length of information */
109             /* char *               information */
110             info = (char*)p + indxp[-mid];
111
112             cmp = dict_strcmp((Dict_char*) info, str);
113             if (sub_flag)
114             {
115                 /* determine if prefix match */
116                 if (!dict_strncmp(str, (Dict_char*) info, dict_strlen(str)))
117                 {
118                     if (f)
119                         (*f)(info + (dict_strlen((Dict_char*) info)+1)
120                              *sizeof(Dict_char), client);
121
122                     hi = DICT_nodir(p)-1;
123                     while (mid < hi)
124                     {
125                         indxp[-mid] = indxp[-mid-1];
126                         mid++;
127                     }
128                     DICT_type(p) = 1;
129                     (DICT_nodir(p))--;
130                     dict_bf_touch(dict->dbf, ptr);
131                     --hi;
132                     mid = lo = 0;
133                     r = 1; /* signal deleted */
134                     /* start again (may not be the most efficient way to go)*/
135                     continue; 
136                 }
137             }
138             else
139             {
140                 /* normal delete: delete if equal */
141                 if (!cmp)
142                 {
143                     hi = DICT_nodir(p)-1;
144                     while (mid < hi)
145                     {
146                         indxp[-mid] = indxp[-mid-1];
147                         mid++;
148                     }
149                     DICT_type(p) = 1;
150                     (DICT_nodir(p))--;
151                     dict_bf_touch(dict->dbf, ptr);
152                     r = 1;
153                     break;
154                 }
155             }
156         }
157         else
158         {
159             Dict_char dc;
160
161             /* Dict_ptr             subptr */
162             /* Dict_char            sub char */
163             /* unsigned char        length of information */
164             /* char *               information */
165             info = (char*)p - indxp[-mid];
166             memcpy(&dc, info+sizeof(Dict_ptr), sizeof(Dict_char));
167             cmp = dc- *str;
168             if (!cmp)
169             {
170                 memcpy(&subptr, info, sizeof(Dict_ptr));
171                 if (*++str == DICT_EOS)
172                 {
173                     if (info[sizeof(Dict_ptr)+sizeof(Dict_char)])
174                     {
175                         /* entry does exist. Wipe it out */
176                         info[sizeof(Dict_ptr)+sizeof(Dict_char)] = 0;
177                         DICT_type(p) = 1;
178                         dict_bf_touch(dict->dbf, ptr);
179
180                         if (f)
181                             (*f)(info+sizeof(Dict_ptr)+sizeof(Dict_char),
182                                  client);
183                         r = 1;
184                     }
185                     if (sub_flag)
186                     {
187                         /* must delete all suffixes (subtrees) as well */
188                         hi = DICT_nodir(p)-1;
189                         while (mid < hi)
190                         {
191                             indxp[-mid] = indxp[-mid-1];
192                             mid++;
193                         }
194                         (DICT_nodir(p))--;
195                         DICT_type(p) = 1;
196                         dict_bf_touch(dict->dbf, ptr);
197                     }
198                 }
199                 else
200                 {
201                     /* subptr may be 0 */
202                     r = dict_del_string(dict, str, subptr, sub_flag, client, f);
203
204                     /* recover */
205                     dict_bf_readp(dict->dbf, ptr, &p);
206                     indxp = (short*)
207                         ((char*) p+DICT_bsize(p)-sizeof(short));
208                     info = (char*)p - indxp[-mid];
209
210                     if (r == 2)
211                     {   /* subptr page is empty and already removed */
212                         hi = DICT_nodir(p)-1;
213                         while (mid < hi)
214                         {
215                             indxp[-mid] = indxp[-mid-1];
216                             mid++;
217                         }
218                         (DICT_nodir(p))--;
219                         dict_bf_touch(dict->dbf, ptr);
220                         r = 1;
221                     }
222                     subptr = 0; /* prevent dict_del_subtree (below) */
223                 }
224                 break;
225             }
226         }
227         if (cmp < 0)
228             lo = mid+1;
229         else
230             hi = mid-1;
231     }
232     if (DICT_nodir(p) == 0 && ptr != dict->head.root)
233     {
234         DICT_backptr(p) = dict->head.freelist;
235         dict->head.freelist = ptr;
236         dict_bf_touch(dict->dbf, ptr);
237         r = 2;
238     }
239     if (subptr && sub_flag)
240         dict_del_subtree(dict, subptr, client, f);
241
242     return r;
243 }
244
245 int dict_delete(Dict dict, const char *p)
246 {
247     return dict_del_string(dict, (const Dict_char*) p, dict->head.root, 0,
248                            0, 0);
249 }
250
251 int dict_delete_subtree(Dict dict, const char *p, void *client,
252                         int (*f)(const char *info, void *client))
253 {
254     return dict_del_string(dict, (const Dict_char*) p, dict->head.root, 1,
255                            client, f);
256 }
257 /*
258  * Local variables:
259  * c-basic-offset: 4
260  * c-file-style: "Stroustrup"
261  * indent-tabs-mode: nil
262  * End:
263  * vim: shiftwidth=4 tabstop=8 expandtab
264  */
265