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