1 : #define VSTR_SECT_C
2 : /*
3 : * Copyright (C) 2002, 2003 James Antill
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 : *
19 : * email: james@and.org
20 : */
21 : /* functions to manage a Vstr section */
22 : #include "main.h"
23 :
24 : Vstr_sects *vstr_sects_make(unsigned int beg_num)
25 13828 : {
26 13828 : Vstr_sects *sects = VSTR__MK(sizeof(Vstr_sects));
27 13828 : Vstr_sect_node *ptr = NULL;
28 13828 : if (!sects)
29 2 : return (NULL);
30 :
31 13826 : if (beg_num && !(ptr = VSTR__MK(sizeof(Vstr_sect_node) * beg_num)))
32 : {
33 2 : VSTR__F(sects);
34 2 : return (NULL);
35 : }
36 :
37 13824 : VSTR_SECTS_INIT(sects, beg_num, ptr, TRUE);
38 :
39 13824 : return (sects);
40 : }
41 :
42 : void vstr_sects_free(Vstr_sects *sects)
43 13830 : {
44 13830 : if (!sects)
45 10 : return;
46 :
47 13820 : if (sects->free_ptr)
48 13820 : VSTR__F(sects->ptr);
49 :
50 13820 : VSTR__F(sects);
51 : }
52 :
53 : static int vstr__sects_mv(Vstr_sects *sects, unsigned int sz)
54 452 : {
55 452 : struct Vstr_sect_node *tmp_ptr = NULL;
56 :
57 452 : if (!VSTR__MV(sects->ptr, tmp_ptr, sizeof(Vstr_sect_node) * sz))
58 : {
59 18 : sects->malloc_bad = TRUE;
60 18 : return (FALSE);
61 : }
62 434 : sects->sz = sz;
63 :
64 434 : return (TRUE);
65 : }
66 :
67 : static int vstr__sects_add(Vstr_sects *sects)
68 453 : {
69 453 : unsigned int sz = sects->sz;
70 :
71 453 : if (!sz)
72 : {
73 6 : if (!(sects->ptr = VSTR__MK(sizeof(Vstr_sect_node) * 1)))
74 1 : goto malloc_fail;
75 :
76 5 : sects->sz = 1;
77 5 : return (TRUE);
78 : }
79 :
80 447 : if (sects->alloc_double)
81 432 : sz <<= 1;
82 :
83 447 : if (sz <= sects->sz)
84 20 : sz = sects->sz + 1;
85 :
86 447 : if (sz <= sects->sz)
87 5 : goto malloc_fail;
88 :
89 442 : return (vstr__sects_mv(sects, sz));
90 :
91 : malloc_fail:
92 6 : sects->malloc_bad = TRUE;
93 6 : return (FALSE);
94 : }
95 :
96 : static int vstr__sects_del(Vstr_sects *sects)
97 10 : {
98 10 : unsigned int sz = sects->sz;
99 :
100 10 : sz >>= 1;
101 10 : assert(sz >= sects->num);
102 :
103 10 : return (vstr__sects_mv(sects, sz));
104 : }
105 :
106 : int vstr_extern_inline_sects_add(Vstr_sects *sects,
107 : size_t VSTR__ATTR_UNUSED(pos),
108 : size_t VSTR__ATTR_UNUSED(len))
109 453 : {
110 : /* see vstr-extern.h for why */
111 453 : assert(sizeof(struct Vstr_sects) >= sizeof(struct Vstr_sect_node));
112 :
113 453 : return (vstr__sects_add(sects));
114 : }
115 :
116 : int vstr_sects_del(Vstr_sects *sects, unsigned int num)
117 30 : {
118 30 : ASSERT_RET((sects->sz && num), FALSE);
119 30 : ASSERT_RET((sects->num >= num), FALSE);
120 :
121 30 : if (!sects->ptr[num - 1].pos)
122 5 : return (FALSE);
123 :
124 25 : sects->ptr[num - 1].pos = 0;
125 :
126 40 : while (sects->num && !sects->ptr[sects->num - 1].pos)
127 15 : --sects->num;
128 :
129 25 : if (sects->can_del_sz && (sects->num < (sects->sz / 2)))
130 5 : vstr__sects_del(sects); /* can't return this error */
131 :
132 25 : return (TRUE);
133 : }
134 :
135 : unsigned int vstr_sects_srch(Vstr_sects *sects, size_t pos, size_t len)
136 45 : {
137 45 : unsigned int count = 0;
138 :
139 45 : if (!sects->sz)
140 5 : return (0);
141 :
142 145 : while (count++ < sects->num)
143 : {
144 140 : size_t scan_pos = VSTR_SECTS_NUM(sects, count)->pos;
145 140 : size_t scan_len = VSTR_SECTS_NUM(sects, count)->len;
146 :
147 140 : if ((scan_pos == pos) && (scan_len == len))
148 35 : return (count);
149 : }
150 :
151 5 : return (0);
152 : }
153 :
154 : int vstr_sects_foreach(const Vstr_base *base,
155 : Vstr_sects *sects, const unsigned int flags,
156 : unsigned int (*foreach_func)(const Vstr_base *,
157 : size_t, size_t, void *),
158 : void *data)
159 30 : {
160 30 : unsigned int count = 0;
161 30 : unsigned int scan = 0;
162 :
163 30 : if (!sects->sz)
164 5 : return (0);
165 :
166 25 : if (flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD)
167 5 : scan = sects->num;
168 :
169 180 : while ((!(flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD) &&
170 : (scan < sects->num)) ||
171 : ((flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD) && scan))
172 : {
173 160 : size_t pos = 0;
174 160 : size_t len = 0;
175 :
176 160 : if (flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD)
177 5 : --scan;
178 :
179 160 : pos = sects->ptr[scan].pos;
180 160 : len = sects->ptr[scan].len;
181 :
182 160 : if (pos && (len || (flags & VSTR_FLAG_SECTS_FOREACH_ALLOW_NULL)))
183 : {
184 155 : ++count;
185 :
186 155 : switch ((*foreach_func)(base, pos, len, data))
187 : {
188 : case VSTR_TYPE_SECTS_FOREACH_RET:
189 50 : goto shorten_and_return;
190 :
191 : case VSTR_TYPE_SECTS_FOREACH_DEL:
192 50 : sects->ptr[scan].pos = 0;
193 : /* FALL THROUGH */
194 : case VSTR_TYPE_SECTS_FOREACH_DEF:
195 :
196 10 : ASSERT_NO_SWITCH_DEF();
197 : }
198 : }
199 :
200 155 : if (!(flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD))
201 155 : ++scan;
202 : }
203 :
204 : shorten_and_return:
205 75 : while (sects->num && !sects->ptr[sects->num - 1].pos)
206 50 : --sects->num;
207 :
208 25 : if (sects->can_del_sz && (sects->num < (sects->sz / 2)))
209 5 : vstr__sects_del(sects); /* can't return this error */
210 :
211 25 : return (count);
212 : }
213 :
214 : typedef struct Vstr__sects_cache_data
215 : {
216 : unsigned int sz;
217 : unsigned int len;
218 : Vstr_sects *VSTR__STRUCT_HACK_ARRAY(updates);
219 : } Vstr__sects_cache_data;
220 :
221 : static void *vstr__sects_update_cb(const Vstr_base *base,size_t pos, size_t len,
222 : unsigned int type, void *passed_data)
223 55 : {
224 55 : Vstr__sects_cache_data *data = passed_data;
225 55 : unsigned int count = 0;
226 :
227 55 : ASSERT(base->conf->cache_pos_cb_sects);
228 55 : ASSERT(data == vstr_cache_get(base, base->conf->cache_pos_cb_sects));
229 :
230 55 : if (type == VSTR_TYPE_CACHE_FREE)
231 : {
232 5 : VSTR__F(data);
233 5 : return (NULL);
234 : }
235 :
236 50 : if (type == VSTR_TYPE_CACHE_SUB) /* do nothing for substitutions ... */
237 5 : return (data);
238 :
239 90 : while (count < data->len)
240 : {
241 45 : Vstr_sects *sects = data->updates[count];
242 45 : unsigned int scan = 0;
243 :
244 45 : switch (type)
245 : {
246 : case VSTR_TYPE_CACHE_ADD:
247 30 : while (scan < sects->num)
248 : {
249 20 : if (sects->ptr[scan].pos && sects->ptr[scan].len)
250 : {
251 20 : if (pos < sects->ptr[scan].pos)
252 15 : sects->ptr[scan].pos += len;
253 20 : if ((pos >= sects->ptr[scan].pos) &&
254 : (pos < (sects->ptr[scan].pos + sects->ptr[scan].len - 1)))
255 5 : sects->ptr[scan].len += len;
256 : }
257 :
258 20 : ++scan;
259 : }
260 35 : break;
261 :
262 : case VSTR_TYPE_CACHE_DEL:
263 105 : while (scan < sects->num)
264 : {
265 70 : if (sects->ptr[scan].pos && sects->ptr[scan].len)
266 : {
267 65 : if (pos <= sects->ptr[scan].pos)
268 : {
269 30 : size_t tmp = sects->ptr[scan].pos - pos;
270 :
271 30 : if (tmp >= len)
272 10 : sects->ptr[scan].pos -= len;
273 : else
274 : {
275 20 : len -= tmp;
276 20 : if (len >= sects->ptr[scan].len)
277 5 : sects->ptr[scan].pos = 0;
278 : else
279 : {
280 15 : sects->ptr[scan].pos -= tmp;
281 15 : sects->ptr[scan].len -= len;
282 : }
283 : }
284 : }
285 35 : else if ((pos > sects->ptr[scan].pos) &&
286 : (pos <= (sects->ptr[scan].pos + sects->ptr[scan].len - 1)))
287 : {
288 25 : size_t tmp = pos - sects->ptr[scan].pos;
289 :
290 25 : if (len >= (sects->ptr[scan].len - tmp))
291 20 : sects->ptr[scan].len = tmp;
292 : else
293 5 : sects->ptr[scan].len -= len;
294 : }
295 : }
296 :
297 70 : ++scan;
298 : }
299 36 : ASSERT_NO_SWITCH_DEF();
300 : }
301 :
302 45 : ++count;
303 : }
304 :
305 45 : return (data);
306 : }
307 :
308 : static Vstr_sects **vstr__sects_update_srch(Vstr__sects_cache_data *data,
309 : Vstr_sects *sects)
310 31 : {
311 31 : unsigned int count = 0;
312 :
313 56 : while (count < data->len)
314 : {
315 44 : if (data->updates[count] == sects)
316 19 : return (&data->updates[count]);
317 :
318 25 : ++count;
319 : }
320 :
321 12 : return (NULL);
322 : }
323 :
324 : static void vstr__sects_update_del(Vstr__sects_cache_data *data,
325 : Vstr_sects **sects)
326 19 : {
327 19 : Vstr_sects **end = (data->updates + (data->len - 1));
328 :
329 19 : --data->len;
330 :
331 19 : if (sects != end)
332 5 : vstr_wrap_memmove(sects, sects + 1,
333 : (end - sects) * sizeof(Vstr_sects *));
334 : }
335 :
336 : int vstr_sects_update_add(const Vstr_base *base,
337 : Vstr_sects *sects)
338 38 : {
339 38 : Vstr__sects_cache_data *data = NULL;
340 38 : unsigned int sz = 1;
341 :
342 38 : if (!base->conf->cache_pos_cb_sects)
343 : {
344 18 : unsigned int tmp = 0;
345 :
346 18 : tmp = vstr_cache_add(base->conf, "/vstr__/sects/update",
347 : vstr__sects_update_cb);
348 :
349 18 : if (!tmp)
350 4 : goto malloc_bad;
351 :
352 14 : base->conf->cache_pos_cb_sects = tmp;
353 : }
354 :
355 34 : if (!(data = vstr_cache_get(base, base->conf->cache_pos_cb_sects)))
356 : {
357 16 : if (!vstr_cache_set(base, base->conf->cache_pos_cb_sects, NULL))
358 1 : goto malloc_bad;
359 :
360 15 : data = VSTR__MK(sizeof(Vstr__sects_cache_data) +
361 : (sz * sizeof(Vstr_sects *)));
362 15 : if (!data)
363 1 : goto malloc_bad;
364 :
365 14 : data->sz = 1;
366 14 : data->len = 0;
367 :
368 14 : vstr_cache_set(base, base->conf->cache_pos_cb_sects, data);
369 : }
370 :
371 : /* it can't be valid to have the same sects twice */
372 32 : ASSERT(!vstr__sects_update_srch(data, sects));
373 :
374 32 : sz = data->len + 1;
375 :
376 : /* this is basically impossible to test (size overflow)...
377 : * done this way for coverage */
378 32 : ASSERT_RET((sz > data->len) || !(base->conf->malloc_bad = TRUE), FALSE);
379 :
380 32 : ASSERT(data->sz);
381 32 : ASSERT(data->len <= data->sz);
382 :
383 32 : if (data->len >= data->sz)
384 : {
385 18 : Vstr__sects_cache_data *tmp_data = NULL;
386 :
387 18 : if (!(VSTR__MV(data, tmp_data, sizeof(Vstr__sects_cache_data) +
388 : (sz * sizeof(Vstr_sects *)))))
389 0 : goto malloc_bad;
390 :
391 10 : data->sz = data->len + 1;
392 :
393 10 : vstr_cache_set(base, base->conf->cache_pos_cb_sects, data);
394 : }
395 :
396 24 : data->updates[data->len] = sects;
397 24 : ++data->len;
398 :
399 24 : return (TRUE);
400 :
401 : malloc_bad:
402 14 : base->conf->malloc_bad = TRUE;
403 14 : return (FALSE);
404 : }
405 :
406 : int vstr_sects_update_del(const Vstr_base *base,
407 : Vstr_sects *sects)
408 33 : {
409 33 : Vstr__sects_cache_data *data = NULL;
410 33 : Vstr_sects **srch = NULL;
411 :
412 33 : if (!sects)
413 10 : return (FALSE);
414 :
415 23 : ASSERT_RET(base->conf->cache_pos_cb_sects, FALSE);
416 :
417 23 : data = vstr_cache_get(base, base->conf->cache_pos_cb_sects);
418 23 : ASSERT_RET(data, FALSE);
419 :
420 19 : srch = vstr__sects_update_srch(data, sects);
421 19 : ASSERT_RET(srch, FALSE);
422 :
423 19 : vstr__sects_update_del(data, srch);
424 :
425 19 : if (!data->len)
426 : {
427 9 : VSTR__F(data);
428 9 : vstr_cache_set(base, base->conf->cache_pos_cb_sects, NULL);
429 : }
430 :
431 19 : return (TRUE);
432 : }
|