1 : #define VSTR_SUB_C
2 : /*
3 : * Copyright (C) 2001, 2002, 2003, 2004 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 substitute data in a vstr */
22 : #include "main.h"
23 :
24 : #define VSTR__SUB_BUF() do { \
25 : if (tmp > buf_len) \
26 : tmp = buf_len; \
27 : \
28 : vstr_wrap_memcpy((((Vstr_node_buf *)scan)->buf) + pos, buf, tmp); \
29 : buf_len -= tmp; \
30 : buf = ((char *)buf) + tmp; \
31 : } while (FALSE)
32 :
33 : static int vstr__sub_buf_fast(Vstr_base *base, size_t pos, size_t len,
34 : const void *buf)
35 32345 : {
36 32345 : Vstr_iter iter[1];
37 32345 : size_t buf_len = len;
38 :
39 32345 : if (!vstr_iter_fwd_beg(base, pos, len, iter))
40 8 : return (FALSE);
41 :
42 32421 : do
43 : {
44 32421 : const size_t tmp = iter->len;
45 :
46 32421 : assert(iter->node->type == VSTR_TYPE_NODE_BUF);
47 :
48 32421 : vstr_wrap_memcpy((char *)iter->ptr, buf, tmp);
49 32421 : buf = ((char *)buf) + tmp;
50 32421 : } while (vstr_iter_fwd_nxt(iter));
51 :
52 32337 : vstr_cache_cb_sub(base, pos, buf_len);
53 :
54 32337 : return (TRUE);
55 : }
56 :
57 : static int vstr__sub_buf_slow(Vstr_base *base, size_t pos, size_t len,
58 : const void *buf, size_t buf_len)
59 22441 : {
60 22441 : Vstr_iter iter[1];
61 22441 : size_t orig_pos = pos;
62 22441 : size_t orig_buf_len = buf_len;
63 22441 : size_t sub_add_len = 0;
64 22441 : size_t add_len = 0;
65 22441 : size_t del_len = 0;
66 22441 : size_t real_pos = 0;
67 22441 : int ret = FALSE;
68 :
69 22441 : assert(vstr__check_spare_nodes(base->conf));
70 22441 : assert(vstr__check_real_nodes(base));
71 :
72 22441 : if (len > buf_len)
73 : {
74 184 : del_len = len - buf_len;
75 184 : len = buf_len;
76 : }
77 : else
78 22257 : add_len = buf_len - len;
79 :
80 22441 : ret = vstr_iter_fwd_beg(base, pos, len, iter);
81 22441 : ASSERT_RET(ret, FALSE);
82 :
83 22490 : do
84 : {
85 22490 : size_t tmp = iter->len;
86 :
87 22490 : ASSERT(tmp <= buf_len); /* iter is capped to buffer length */
88 :
89 22490 : if (iter->node->type != VSTR_TYPE_NODE_BUF)
90 13850 : sub_add_len += tmp;
91 :
92 22490 : buf_len -= tmp;
93 22490 : } while (buf_len && vstr_iter_fwd_nxt(iter));
94 :
95 22441 : buf_len = orig_buf_len;
96 :
97 22441 : if ((sub_add_len == buf_len) || (sub_add_len == len))
98 : { /* no _BUF nodes, so we can't optimise it anyway ... */
99 13826 : ret = vstr_add_buf(base, pos - 1, buf, buf_len);
100 :
101 13826 : if (!ret)
102 4 : return (FALSE);
103 :
104 13822 : ret = vstr_del(base, pos + buf_len, len + del_len);
105 13822 : ASSERT(ret || !buf_len); /* if stuff added, then split happened ... so
106 : * can't fail */
107 :
108 13822 : return (ret);
109 : }
110 :
111 8615 : add_len += sub_add_len;
112 :
113 8615 : if (add_len)
114 : {
115 : /* allocate extra _BUF nodes needed, all other are ok -- no splits will
116 : * happen on non _BUF nodes */
117 151 : unsigned int num = (add_len / base->conf->buf_sz) + 2;
118 151 : if (!vstr_cntl_conf(base->conf, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BUF,
119 : num, UINT_MAX))
120 2 : return (FALSE);
121 : }
122 :
123 8613 : if (sub_add_len)
124 : { /* loop again removing any non _BUF nodes */
125 10 : int nxt_iter = FALSE;
126 :
127 10 : ret = vstr_iter_fwd_beg(base, pos, len, iter);
128 10 : ASSERT_RET(ret, FALSE);
129 :
130 20 : do
131 : {
132 20 : size_t tmp_len = iter->len;
133 20 : unsigned int tmp_type = iter->node->type;
134 :
135 20 : nxt_iter = vstr_iter_fwd_nxt(iter);
136 :
137 20 : if (tmp_type != VSTR_TYPE_NODE_BUF)
138 : {
139 10 : vstr_del(base, pos, tmp_len);
140 10 : len -= tmp_len;
141 : }
142 :
143 20 : pos += tmp_len;
144 20 : } while (buf_len && nxt_iter);
145 : }
146 :
147 8613 : vstr__sub_buf_fast(base, orig_pos, len, buf);
148 :
149 8613 : real_pos = orig_pos + len;
150 8613 : buf_len -= len;
151 8613 : buf = ((char *)buf) + len;
152 :
153 8613 : if (del_len)
154 140 : vstr_del(base, real_pos, del_len);
155 :
156 8613 : if (buf_len)
157 149 : vstr_add_buf(base, real_pos - 1, buf, buf_len);
158 :
159 8613 : assert(vstr__check_spare_nodes(base->conf));
160 8613 : assert(vstr__check_real_nodes(base));
161 :
162 8613 : return (TRUE);
163 : }
164 :
165 : int vstr_sub_buf(Vstr_base *base, size_t pos, size_t len,
166 : const void *buf, size_t buf_len)
167 46192 : {
168 46192 : ASSERT_RET(base, FALSE);
169 :
170 46188 : if (!len)
171 10 : return (vstr_add_buf(base, pos - 1, buf, buf_len));
172 :
173 46178 : if (!buf_len)
174 5 : return (vstr_del(base, pos, len));
175 :
176 46173 : if ((len == buf_len) &&
177 : !base->node_non_used &&
178 : !base->node_ptr_used &&
179 : !base->node_ref_used)
180 23732 : return (vstr__sub_buf_fast(base, pos, len, buf));
181 :
182 22441 : return (vstr__sub_buf_slow(base, pos, len, buf, buf_len));
183 : }
184 :
185 : int vstr_sub_non(Vstr_base *base, size_t pos, size_t len, size_t non_len)
186 120 : {
187 120 : int ret = vstr_add_non(base, pos - 1, non_len);
188 :
189 120 : if (!ret)
190 2 : return (FALSE);
191 :
192 118 : ret = vstr_del(base, pos + non_len, len);
193 118 : ASSERT(ret || !non_len); /* if stuff added, then split happened ... so
194 : * can't fail */
195 :
196 118 : return (ret);
197 : }
198 :
199 : int vstr_sub_ptr(Vstr_base *base, size_t pos, size_t len,
200 : const void *ptr, size_t ptr_len)
201 79 : {
202 79 : int ret = FALSE;
203 79 : Vstr_iter iter[1];
204 :
205 79 : if (!len || !ptr_len)
206 5 : goto simple_sub;
207 :
208 60 : if (!(ret = vstr_iter_fwd_beg(base, pos, len, iter)))
209 8 : return (FALSE);
210 :
211 52 : if ((ptr_len <= VSTR_MAX_NODE_ALL) && VSTR__ITER_EQ_ALL_NODE(base, iter))
212 : {
213 42 : Vstr_node_ptr *ptr_node = NULL;
214 :
215 42 : if (iter->node->type == VSTR_TYPE_NODE_PTR)
216 21 : ptr_node = (Vstr_node_ptr *)iter->node;
217 : else
218 : {
219 21 : if (!vstr_cntl_conf(base->conf,
220 : VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_PTR, 1, UINT_MAX))
221 1 : return (FALSE);
222 20 : --base->conf->spare_ptr_num;
223 20 : ptr_node = base->conf->spare_ptr_beg;
224 20 : base->conf->spare_ptr_beg = (Vstr_node_ptr *)ptr_node->s.next;
225 : }
226 :
227 41 : if (ptr_len < len)
228 : {
229 5 : size_t diff_len = len - ptr_len;
230 :
231 5 : len -= diff_len;
232 5 : iter->node->len -= diff_len;
233 5 : base->len -= diff_len;
234 5 : vstr__cache_del(base, pos, diff_len);
235 : }
236 :
237 41 : ptr_node->s.len = len;
238 41 : ptr_node->ptr = (void *)ptr;
239 :
240 41 : if (iter->node->type == VSTR_TYPE_NODE_PTR)
241 21 : vstr__cache_iovec_reset_node(base, &ptr_node->s, iter->num);
242 : else
243 20 : vstr__swap_node_X_X(base, pos, &ptr_node->s);
244 :
245 41 : vstr_cache_cb_sub(base, pos, ptr_len);
246 :
247 41 : if (ptr_len > len)
248 : {
249 10 : size_t diff_len = ptr_len - len;
250 :
251 10 : ptr_node->s.len += diff_len;
252 10 : base->len += diff_len;
253 :
254 10 : vstr__cache_iovec_reset_node(base, &ptr_node->s, iter->num);
255 10 : vstr__cache_add(base, pos, diff_len);
256 : }
257 :
258 41 : assert(vstr__check_spare_nodes(base->conf));
259 41 : assert(vstr__check_real_nodes(base));
260 41 : return (TRUE);
261 : }
262 :
263 : simple_sub:
264 29 : ret = vstr_add_ptr(base, pos - 1, ptr, ptr_len);
265 :
266 29 : if (!ret)
267 4 : return (FALSE);
268 :
269 25 : ret = vstr_del(base, pos + ptr_len, len);
270 25 : ASSERT(ret || !ptr_len); /* if stuff added, then split happened ... so
271 : * can't fail */
272 :
273 25 : return (ret);
274 : }
275 :
276 : int vstr_sub_ref(Vstr_base *base, size_t pos, size_t len,
277 : Vstr_ref *ref, size_t off, size_t ref_len)
278 51 : {
279 51 : int ret = FALSE;
280 51 : Vstr_iter iter[1];
281 :
282 51 : if (!len || !ref_len)
283 5 : goto simple_sub;
284 :
285 46 : if (!(ret = vstr_iter_fwd_beg(base, pos, len, iter)))
286 12 : return (FALSE);
287 :
288 34 : if ((ref_len <= VSTR_MAX_NODE_ALL) && VSTR__ITER_EQ_ALL_NODE(base, iter))
289 : {
290 25 : Vstr_node_ref *ref_node = NULL;
291 :
292 25 : vstr_ref_add(ref);
293 :
294 25 : if (iter->node->type == VSTR_TYPE_NODE_REF)
295 11 : ref_node = (Vstr_node_ref *)iter->node;
296 : else
297 : {
298 14 : if (!vstr_cntl_conf(base->conf,
299 : VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_REF, 1, UINT_MAX))
300 4 : return (FALSE);
301 10 : --base->conf->spare_ref_num;
302 10 : ref_node = base->conf->spare_ref_beg;
303 10 : base->conf->spare_ref_beg = (Vstr_node_ref *)ref_node->s.next;
304 10 : ref_node->ref = NULL;
305 : }
306 :
307 21 : if (ref_len < len)
308 : {
309 5 : size_t diff_len = len - ref_len;
310 :
311 5 : len -= diff_len;
312 5 : iter->node->len -= diff_len;
313 5 : base->len -= diff_len;
314 5 : vstr__cache_del(base, pos, diff_len);
315 : }
316 :
317 21 : vstr_ref_del(ref_node->ref);
318 :
319 21 : ref_node->s.len = len;
320 21 : ref_node->ref = ref;
321 21 : ref_node->off = off;
322 :
323 21 : if (iter->node->type == VSTR_TYPE_NODE_REF)
324 11 : vstr__cache_iovec_reset_node(base, &ref_node->s, iter->num);
325 : else
326 10 : vstr__swap_node_X_X(base, pos, &ref_node->s);
327 :
328 21 : vstr_cache_cb_sub(base, pos, ref_len);
329 :
330 21 : if (ref_len > len)
331 : {
332 10 : size_t diff_len = ref_len - len;
333 :
334 10 : ref_node->s.len += diff_len;
335 10 : base->len += diff_len;
336 :
337 10 : vstr__cache_iovec_reset_node(base, &ref_node->s, iter->num);
338 10 : vstr__cache_add(base, pos, diff_len);
339 : }
340 :
341 21 : assert(vstr__check_spare_nodes(base->conf));
342 21 : assert(vstr__check_real_nodes(base));
343 21 : return (TRUE);
344 : }
345 :
346 : simple_sub:
347 14 : ret = vstr_add_ref(base, pos - 1, ref, off, ref_len);
348 :
349 14 : if (!ret)
350 5 : return (FALSE);
351 :
352 9 : ret = vstr_del(base, pos + ref_len, len);
353 9 : ASSERT(ret || !ref_len); /* if stuff added, then split happened ... so
354 : * can't fail */
355 :
356 9 : return (ret);
357 : }
358 :
359 : int vstr_sub_vstr(Vstr_base *base, size_t pos, size_t len,
360 : const Vstr_base *from_base,
361 : size_t from_pos, size_t from_len, unsigned int type)
362 67 : { /* TODO: this is inefficient compared to vstr_sub_buf() because of atomic
363 : * guarantees - could be made to work with _ALL_BUF */
364 67 : int ret = TRUE;
365 :
366 67 : assert(pos && from_pos);
367 :
368 67 : ret = vstr_add_vstr(base, pos - 1, from_base, from_pos, from_len, type);
369 :
370 67 : if (!ret)
371 2 : return (FALSE);
372 :
373 65 : ret = vstr_del(base, pos + from_len, len);
374 65 : ASSERT(ret || !from_len); /* if stuff added, then split happened ... so
375 : * can't fail */
376 :
377 65 : return (ret);
378 : }
379 :
380 : int vstr_sub_rep_chr(Vstr_base *base, size_t pos, size_t len,
381 : char chr, size_t rep_len)
382 61 : {
383 61 : int ret = TRUE;
384 :
385 61 : ASSERT_RET(ret, FALSE);
386 :
387 61 : if (!len && !rep_len)
388 5 : return (TRUE);
389 :
390 56 : if (rep_len == 1)
391 10 : return (vstr_sub_buf(base, pos, len, &chr, 1));
392 :
393 : /* TODO: this is a simple opt. */
394 46 : if ((len == rep_len) &&
395 : !base->node_non_used &&
396 : !base->node_ptr_used &&
397 : !base->node_ref_used)
398 : {
399 13 : Vstr_iter iter[1];
400 :
401 13 : if (!(ret = vstr_iter_fwd_beg(base, pos, len, iter)))
402 8 : return (FALSE);
403 :
404 5 : do
405 : {
406 5 : const size_t tmp = iter->len;
407 :
408 5 : assert(iter->node->type == VSTR_TYPE_NODE_BUF);
409 :
410 5 : vstr_wrap_memset((char *)iter->ptr, chr, tmp);
411 5 : } while (vstr_iter_fwd_nxt(iter));
412 :
413 5 : vstr_cache_cb_sub(base, pos, rep_len);
414 :
415 5 : return (TRUE);
416 : }
417 : /* need something like vstr_sub_buf() so mostly _BUF strings can
418 : * be quick here */
419 :
420 33 : ret = vstr_add_rep_chr(base, pos - 1, chr, rep_len);
421 :
422 33 : if (!ret)
423 5 : return (FALSE);
424 :
425 28 : ret = vstr_del(base, pos + rep_len, len);
426 28 : ASSERT(ret || !rep_len); /* if stuff added, then split happened ... so
427 : * can't fail */
428 :
429 28 : return (ret);
430 : }
|