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
vstr_sects_make(unsigned int beg_num)24 Vstr_sects *vstr_sects_make(unsigned int beg_num)
25 {
26 Vstr_sects *sects = VSTR__MK(sizeof(Vstr_sects));
27 Vstr_sect_node *ptr = NULL;
28 if (!sects)
29 return (NULL);
30
31 if (beg_num && !(ptr = VSTR__MK(sizeof(Vstr_sect_node) * beg_num)))
32 {
33 VSTR__F(sects);
34 return (NULL);
35 }
36
37 VSTR_SECTS_INIT(sects, beg_num, ptr, TRUE);
38
39 return (sects);
40 }
41
vstr_sects_free(Vstr_sects * sects)42 void vstr_sects_free(Vstr_sects *sects)
43 {
44 if (!sects)
45 return;
46
47 if (sects->free_ptr)
48 VSTR__F(sects->ptr);
49
50 VSTR__F(sects);
51 }
52
vstr__sects_mv(Vstr_sects * sects,unsigned int sz)53 static int vstr__sects_mv(Vstr_sects *sects, unsigned int sz)
54 {
55 struct Vstr_sect_node *tmp_ptr = NULL;
56
57 if (!VSTR__MV(sects->ptr, tmp_ptr, sizeof(Vstr_sect_node) * sz))
58 {
59 sects->malloc_bad = TRUE;
60 return (FALSE);
61 }
62 sects->sz = sz;
63
64 return (TRUE);
65 }
66
vstr__sects_add(Vstr_sects * sects)67 static int vstr__sects_add(Vstr_sects *sects)
68 {
69 unsigned int sz = sects->sz;
70
71 if (!sz)
72 {
73 if (!(sects->ptr = VSTR__MK(sizeof(Vstr_sect_node) * 1)))
74 goto malloc_fail;
75
76 sects->sz = 1;
77 return (TRUE);
78 }
79
80 if (sects->alloc_double)
81 sz <<= 1;
82
83 if (sz <= sects->sz)
84 sz = sects->sz + 1;
85
86 if (sz <= sects->sz)
87 goto malloc_fail;
88
89 return (vstr__sects_mv(sects, sz));
90
91 malloc_fail:
92 sects->malloc_bad = TRUE;
93 return (FALSE);
94 }
95
vstr__sects_del(Vstr_sects * sects)96 static int vstr__sects_del(Vstr_sects *sects)
97 {
98 unsigned int sz = sects->sz;
99
100 sz >>= 1;
101 assert(sz >= sects->num);
102
103 return (vstr__sects_mv(sects, sz));
104 }
105
vstr_extern_inline_sects_add(Vstr_sects * sects,size_t VSTR__ATTR_UNUSED (pos),size_t VSTR__ATTR_UNUSED (len))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 {
110 /* see vstr-extern.h for why */
111 assert(sizeof(struct Vstr_sects) >= sizeof(struct Vstr_sect_node));
112
113 return (vstr__sects_add(sects));
114 }
115
vstr_sects_del(Vstr_sects * sects,unsigned int num)116 int vstr_sects_del(Vstr_sects *sects, unsigned int num)
117 {
118 ASSERT_RET((sects->sz && num), FALSE);
119 ASSERT_RET((sects->num >= num), FALSE);
120
121 if (!sects->ptr[num - 1].pos)
122 return (FALSE);
123
124 sects->ptr[num - 1].pos = 0;
125
126 while (sects->num && !sects->ptr[sects->num - 1].pos)
127 --sects->num;
128
129 if (sects->can_del_sz && (sects->num < (sects->sz / 2)))
130 vstr__sects_del(sects); /* can't return this error */
131
132 return (TRUE);
133 }
134
vstr_sects_srch(Vstr_sects * sects,size_t pos,size_t len)135 unsigned int vstr_sects_srch(Vstr_sects *sects, size_t pos, size_t len)
136 {
137 unsigned int count = 0;
138
139 if (!sects->sz)
140 return (0);
141
142 while (count++ < sects->num)
143 {
144 size_t scan_pos = VSTR_SECTS_NUM(sects, count)->pos;
145 size_t scan_len = VSTR_SECTS_NUM(sects, count)->len;
146
147 if ((scan_pos == pos) && (scan_len == len))
148 return (count);
149 }
150
151 return (0);
152 }
153
vstr_sects_foreach(const Vstr_base * base,Vstr_sects * sects,const unsigned int flags,unsigned int (* foreach_func)(const Vstr_base *,size_t,size_t,void *),void * data)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 {
160 unsigned int count = 0;
161 unsigned int scan = 0;
162
163 if (!sects->sz)
164 return (0);
165
166 if (flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD)
167 scan = sects->num;
168
169 while ((!(flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD) &&
170 (scan < sects->num)) ||
171 ((flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD) && scan))
172 {
173 size_t pos = 0;
174 size_t len = 0;
175
176 if (flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD)
177 --scan;
178
179 pos = sects->ptr[scan].pos;
180 len = sects->ptr[scan].len;
181
182 if (pos && (len || (flags & VSTR_FLAG_SECTS_FOREACH_ALLOW_NULL)))
183 {
184 ++count;
185
186 switch ((*foreach_func)(base, pos, len, data))
187 {
188 case VSTR_TYPE_SECTS_FOREACH_RET:
189 goto shorten_and_return;
190
191 case VSTR_TYPE_SECTS_FOREACH_DEL:
192 sects->ptr[scan].pos = 0;
193 /* FALL THROUGH */
194 case VSTR_TYPE_SECTS_FOREACH_DEF:
195
196 ASSERT_NO_SWITCH_DEF();
197 }
198 }
199
200 if (!(flags & VSTR_FLAG_SECTS_FOREACH_BACKWARD))
201 ++scan;
202 }
203
204 shorten_and_return:
205 while (sects->num && !sects->ptr[sects->num - 1].pos)
206 --sects->num;
207
208 if (sects->can_del_sz && (sects->num < (sects->sz / 2)))
209 vstr__sects_del(sects); /* can't return this error */
210
211 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
vstr__sects_update_cb(const Vstr_base * base,size_t pos,size_t len,unsigned int type,void * passed_data)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 {
224 Vstr__sects_cache_data *data = passed_data;
225 unsigned int count = 0;
226
227 ASSERT(base->conf->cache_pos_cb_sects);
228 ASSERT(data == vstr_cache_get(base, base->conf->cache_pos_cb_sects));
229
230 if (type == VSTR_TYPE_CACHE_FREE)
231 {
232 VSTR__F(data);
233 return (NULL);
234 }
235
236 if (type == VSTR_TYPE_CACHE_SUB) /* do nothing for substitutions ... */
237 return (data);
238
239 while (count < data->len)
240 {
241 Vstr_sects *sects = data->updates[count];
242 unsigned int scan = 0;
243
244 switch (type)
245 {
246 case VSTR_TYPE_CACHE_ADD:
247 while (scan < sects->num)
248 {
249 if (sects->ptr[scan].pos && sects->ptr[scan].len)
250 {
251 if (pos < sects->ptr[scan].pos)
252 sects->ptr[scan].pos += len;
253 if ((pos >= sects->ptr[scan].pos) &&
254 (pos < (sects->ptr[scan].pos + sects->ptr[scan].len - 1)))
255 sects->ptr[scan].len += len;
256 }
257
258 ++scan;
259 }
260 break;
261
262 case VSTR_TYPE_CACHE_DEL:
263 while (scan < sects->num)
264 {
265 if (sects->ptr[scan].pos && sects->ptr[scan].len)
266 {
267 if (pos <= sects->ptr[scan].pos)
268 {
269 size_t tmp = sects->ptr[scan].pos - pos;
270
271 if (tmp >= len)
272 sects->ptr[scan].pos -= len;
273 else
274 {
275 len -= tmp;
276 if (len >= sects->ptr[scan].len)
277 sects->ptr[scan].pos = 0;
278 else
279 {
280 sects->ptr[scan].pos -= tmp;
281 sects->ptr[scan].len -= len;
282 }
283 }
284 }
285 else if ((pos > sects->ptr[scan].pos) &&
286 (pos <= (sects->ptr[scan].pos + sects->ptr[scan].len - 1)))
287 {
288 size_t tmp = pos - sects->ptr[scan].pos;
289
290 if (len >= (sects->ptr[scan].len - tmp))
291 sects->ptr[scan].len = tmp;
292 else
293 sects->ptr[scan].len -= len;
294 }
295 }
296
297 ++scan;
298 }
299 ASSERT_NO_SWITCH_DEF();
300 }
301
302 ++count;
303 }
304
305 return (data);
306 }
307
vstr__sects_update_srch(Vstr__sects_cache_data * data,Vstr_sects * sects)308 static Vstr_sects **vstr__sects_update_srch(Vstr__sects_cache_data *data,
309 Vstr_sects *sects)
310 {
311 unsigned int count = 0;
312
313 while (count < data->len)
314 {
315 if (data->updates[count] == sects)
316 return (&data->updates[count]);
317
318 ++count;
319 }
320
321 return (NULL);
322 }
323
vstr__sects_update_del(Vstr__sects_cache_data * data,Vstr_sects ** sects)324 static void vstr__sects_update_del(Vstr__sects_cache_data *data,
325 Vstr_sects **sects)
326 {
327 Vstr_sects **end = (data->updates + (data->len - 1));
328
329 --data->len;
330
331 if (sects != end)
332 vstr_wrap_memmove(sects, sects + 1,
333 (end - sects) * sizeof(Vstr_sects *));
334 }
335
vstr_sects_update_add(const Vstr_base * base,Vstr_sects * sects)336 int vstr_sects_update_add(const Vstr_base *base,
337 Vstr_sects *sects)
338 {
339 Vstr__sects_cache_data *data = NULL;
340 unsigned int sz = 1;
341
342 if (!base->conf->cache_pos_cb_sects)
343 {
344 unsigned int tmp = 0;
345
346 tmp = vstr_cache_add(base->conf, "/vstr__/sects/update",
347 vstr__sects_update_cb);
348
349 if (!tmp)
350 goto malloc_bad;
351
352 base->conf->cache_pos_cb_sects = tmp;
353 }
354
355 if (!(data = vstr_cache_get(base, base->conf->cache_pos_cb_sects)))
356 {
357 if (!vstr_cache_set(base, base->conf->cache_pos_cb_sects, NULL))
358 goto malloc_bad;
359
360 data = VSTR__MK(sizeof(Vstr__sects_cache_data) +
361 (sz * sizeof(Vstr_sects *)));
362 if (!data)
363 goto malloc_bad;
364
365 data->sz = 1;
366 data->len = 0;
367
368 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 ASSERT(!vstr__sects_update_srch(data, sects));
373
374 sz = data->len + 1;
375
376 /* this is basically impossible to test (size overflow)...
377 * done this way for coverage */
378 ASSERT_RET((sz > data->len) || !(base->conf->malloc_bad = TRUE), FALSE);
379
380 ASSERT(data->sz);
381 ASSERT(data->len <= data->sz);
382
383 if (data->len >= data->sz)
384 {
385 Vstr__sects_cache_data *tmp_data = NULL;
386
387 if (!(VSTR__MV(data, tmp_data, sizeof(Vstr__sects_cache_data) +
388 (sz * sizeof(Vstr_sects *)))))
389 goto malloc_bad;
390
391 data->sz = data->len + 1;
392
393 vstr_cache_set(base, base->conf->cache_pos_cb_sects, data);
394 }
395
396 data->updates[data->len] = sects;
397 ++data->len;
398
399 return (TRUE);
400
401 malloc_bad:
402 base->conf->malloc_bad = TRUE;
403 return (FALSE);
404 }
405
vstr_sects_update_del(const Vstr_base * base,Vstr_sects * sects)406 int vstr_sects_update_del(const Vstr_base *base,
407 Vstr_sects *sects)
408 {
409 Vstr__sects_cache_data *data = NULL;
410 Vstr_sects **srch = NULL;
411
412 if (!sects)
413 return (FALSE);
414
415 ASSERT_RET(base->conf->cache_pos_cb_sects, FALSE);
416
417 data = vstr_cache_get(base, base->conf->cache_pos_cb_sects);
418 ASSERT_RET(data, FALSE);
419
420 srch = vstr__sects_update_srch(data, sects);
421 ASSERT_RET(srch, FALSE);
422
423 vstr__sects_update_del(data, srch);
424
425 if (!data->len)
426 {
427 VSTR__F(data);
428 vstr_cache_set(base, base->conf->cache_pos_cb_sects, NULL);
429 }
430
431 return (TRUE);
432 }
433 #include "internal_syms_generated/vstr-cpp-symbols_rev.h"
434 VSTR__SYM_ALIAS(extern_inline_sects_add);
435 VSTR__SYM_ALIAS(sects_del);
436 VSTR__SYM_ALIAS(sects_foreach);
437 VSTR__SYM_ALIAS(sects_free);
438 VSTR__SYM_ALIAS(sects_make);
439 VSTR__SYM_ALIAS(sects_srch);
440 VSTR__SYM_ALIAS(sects_update_add);
441 VSTR__SYM_ALIAS(sects_update_del);
442