1 : /* Copyright (c) 2007 Paul Rosenfeld
2 : James Antill -- See LICENSE file for terms. */
3 : #ifndef USTR_REPLACE_H
4 : #error " Include ustr-replace.h before this file."
5 : #endif
6 :
7 : USTR_CONF_i_PROTO
8 : size_t ustrp__replace_inline_buf(struct Ustr_pool *p, struct Ustr **ps1,
9 : const void *optr, size_t olen,
10 : const void *nptr, size_t nlen, size_t lim)
11 24 : { /* "fast path" ... we can't fail, so ignore the return values */
12 24 : size_t num = 0;
13 24 : size_t pos = 0;
14 :
15 12 : USTR_ASSERT(ustr_owner(*ps1));
16 14 : USTR_ASSERT((nlen == olen) || !ustr_alloc(*ps1));
17 :
18 60 : while ((pos = ustr_srch_buf_fwd(*ps1, pos, optr, olen)))
19 : {
20 19 : USTR_ASSERT((nlen == olen) ||
21 : (ustr_fixed(*ps1) &&
22 : (ustr_size(*ps1) >= (ustr_len(*ps1) + (nlen - olen)))));
23 :
24 32 : ustrp__sc_sub_buf(p, ps1, pos, olen, nptr, nlen);
25 32 : pos += nlen - 1;
26 :
27 32 : ++num;
28 32 : if (lim && (num == lim))
29 8 : break;
30 : }
31 :
32 24 : if (!num)
33 4 : errno = 0; /* only way to tell between FAILURE and NO REPLACEMENTS */
34 24 : return (num);
35 : }
36 :
37 :
38 : USTR_CONF_i_PROTO
39 : size_t ustrp__replace_buf(struct Ustr_pool *p, struct Ustr **ps1,
40 : const void *optr, size_t olen,
41 : const void *nptr, size_t nlen, size_t lim)
42 97 : {
43 97 : size_t num = 0;
44 97 : size_t tlen = 0;
45 97 : size_t pos = 0;
46 97 : struct Ustr *ret = USTR_NULL;
47 : const char *rptr;
48 97 : size_t lpos = 0;
49 97 : size_t roff = 0;
50 :
51 48 : USTR_ASSERT(ps1 && ustrp__assert_valid(!!p, *ps1));
52 :
53 97 : if ((nlen == olen) && ustr_owner(*ps1))
54 20 : return (ustrp__replace_inline_buf(p, ps1, optr, olen, nptr, nlen, lim));
55 :
56 : /* pre-calc size, and do single alloc and then memcpy.
57 : * Using dup()/ustr_sc_sub() is much simpler but very slow
58 : * for large strings. */
59 77 : tlen = ustr_len(*ps1);
60 335 : while ((pos = ustr_srch_buf_fwd(*ps1, pos, optr, olen)))
61 : {
62 190 : pos += olen - 1;
63 :
64 190 : if (nlen < olen) /* can go up or down */
65 48 : tlen -= (olen - nlen);
66 : else
67 : {
68 142 : if (tlen > (tlen + (nlen - olen)))
69 : {
70 1 : errno = USTR__ENOMEM;
71 1 : return (0);
72 : }
73 141 : tlen += (nlen - olen);
74 : }
75 :
76 189 : ++num;
77 189 : if (lim && (num == lim))
78 8 : break;
79 : }
80 :
81 76 : if (!num) /* minor speed hack */
82 : {
83 12 : errno = 0; /* only way to tell between FAILURE and NO REPLACEMENTS */
84 12 : return (0);
85 : }
86 :
87 64 : if (!tlen) /* minor speed hack */
88 5 : return (ustrp__del(p, ps1, ustr_len(*ps1)) ? num : 0);
89 :
90 92 : if (ustr_fixed(*ps1) && ((num <= 2) || ustr_limited(*ps1)))
91 : { /* if we will have to memmove() a lot, double copy */
92 12 : if (tlen <= ustr_size(*ps1))
93 4 : return (ustrp__replace_inline_buf(p, ps1, optr, olen, nptr, nlen, lim));
94 12 : if (ustr_limited(*ps1))
95 4 : goto fail_alloc;
96 : }
97 :
98 200 : if (!(ret = ustrp__dupx_undef(p, USTR__DUPX_FROM(*ps1), tlen)))
99 8 : goto fail_alloc;
100 :
101 44 : rptr = ustr_cstr(*ps1);
102 44 : lpos = 1;
103 44 : roff = 0;
104 44 : pos = 0;
105 44 : num = 0;
106 212 : while ((pos = ustr_srch_buf_fwd(*ps1, pos, optr, olen)))
107 : {
108 132 : const char *tptr = rptr + roff;
109 132 : size_t blen = pos - (roff + 1);
110 :
111 132 : pos += olen - 1;
112 66 : USTR_ASSERT(pos == (roff + blen + olen));
113 :
114 132 : ustrp__sub_buf(p, &ret, lpos, tptr, blen); lpos += blen;
115 132 : ustrp__sub_buf(p, &ret, lpos, nptr, nlen); lpos += nlen;
116 :
117 132 : roff = pos;
118 :
119 132 : ++num;
120 132 : if (lim && (num == lim))
121 8 : break;
122 : }
123 55 : ustrp__sub_buf(p, &ret, lpos, rptr + roff, ustr_len(*ps1) - roff);
124 :
125 106 : if (!ustr_fixed(*ps1) || (tlen > ustr_size(*ps1)))
126 40 : ustrp__sc_free2(p, ps1, ret);
127 : else
128 : { /* fixed buffer, with multiple replacements ... but fits */
129 4 : ustrp__set(p, ps1, ret);
130 4 : ustrp__free(p, ret);
131 : }
132 :
133 44 : return (num);
134 :
135 12 : fail_alloc:
136 12 : ustr_setf_enomem_err(*ps1);
137 12 : return (0);
138 : }
139 :
140 : USTR_CONF_I_PROTO
141 : size_t ustr_replace_buf(struct Ustr **ps1, const void *optr, size_t olen,
142 : const void *nptr, size_t nlen, size_t lim)
143 60 : { return (ustrp__replace_buf(0, ps1, optr, olen, nptr, nlen, lim)); }
144 : USTR_CONF_I_PROTO
145 : size_t ustrp_replace_buf(struct Ustr_pool *p, struct Ustrp **ps1,
146 : const void *optr, size_t olen,
147 : const void *nptr, size_t nlen, size_t lim)
148 16 : {
149 16 : struct Ustr *tmp = &(*ps1)->s;
150 16 : int ret = ustrp__replace_buf(p, &tmp, optr, olen, nptr, nlen, lim);
151 16 : *ps1 = USTRP(tmp);
152 16 : return (ret);
153 : }
154 :
155 : USTR_CONF_i_PROTO
156 : size_t ustrp__replace(struct Ustr_pool *p, struct Ustr **ps1,
157 : const struct Ustr *srch,
158 : const struct Ustr *repl, size_t lim)
159 21 : {
160 21 : struct Ustr *t1 = USTR_NULL;
161 21 : struct Ustr *t2 = USTR_NULL;
162 21 : size_t ret = 0;
163 :
164 10 : USTR_ASSERT(ustrp__assert_valid(!!p, srch));
165 10 : USTR_ASSERT(ustrp__assert_valid(!!p, repl));
166 :
167 21 : if (srch == *ps1) srch = t1 = ustrp__dup(p, *ps1);
168 21 : if (repl == *ps1) repl = t2 = ustrp__dup(p, *ps1);
169 :
170 21 : if (srch && repl)
171 21 : ret = ustrp__replace_buf(p, ps1,
172 : ustr_cstr(srch), ustr_len(srch),
173 : ustr_cstr(repl), ustr_len(repl), lim);
174 :
175 21 : ustrp__free(p, t1);
176 21 : ustrp__free(p, t2);
177 :
178 21 : return (ret);
179 : }
180 : USTR_CONF_I_PROTO
181 : size_t ustr_replace(struct Ustr **ps1, const struct Ustr *srch,
182 : const struct Ustr *repl, size_t lim)
183 17 : { return (ustrp__replace(0, ps1, srch, repl, lim)); }
184 : USTR_CONF_I_PROTO
185 : size_t ustrp_replace(struct Ustr_pool *p, struct Ustrp **ps1,
186 : const struct Ustrp *srch,
187 : const struct Ustrp *repl, size_t lim)
188 4 : {
189 4 : struct Ustr *tmp = &(*ps1)->s;
190 4 : int ret = ustrp__replace(p, &tmp, &srch->s, &repl->s, lim);
191 4 : *ps1 = USTRP(tmp);
192 4 : return (ret);
193 : }
194 :
195 : USTR_CONF_i_PROTO
196 : size_t ustrp__replace_inline_rep_chr(struct Ustr_pool *p, struct Ustr **ps1,
197 : char odata, size_t olen,
198 : char ndata, size_t nlen, size_t lim)
199 24 : { /* "fast path" ... as we can't fail after we are the owner(). In theory
200 : * we can do nlen <= olen, but then we'll spend a lot of time calling
201 : * memmove(). Which might be painful, so let that fall through to dupx(). */
202 24 : size_t num = 0;
203 24 : size_t pos = 0;
204 :
205 12 : USTR_ASSERT(ustr_owner(*ps1));
206 14 : USTR_ASSERT((nlen == olen) || !ustr_alloc(*ps1));
207 :
208 68 : while ((pos = ustr_srch_rep_chr_fwd(*ps1, pos, odata, olen)))
209 : {
210 21 : USTR_ASSERT((nlen == olen) ||
211 : (ustr_fixed(*ps1) &&
212 : (ustr_size(*ps1) >= (ustr_len(*ps1) + (nlen - olen)))));
213 :
214 36 : ustrp__sc_sub_rep_chr(p, ps1, pos, olen, ndata, nlen);
215 36 : pos += nlen - 1;
216 :
217 36 : ++num;
218 36 : if (lim && (num == lim))
219 4 : break;
220 : }
221 :
222 24 : if (!num)
223 4 : errno = 0; /* only way to tell between FAILURE and NO REPLACEMENTS */
224 24 : return (num);
225 : }
226 :
227 : USTR_CONF_i_PROTO
228 : size_t ustrp__replace_rep_chr(struct Ustr_pool *p, struct Ustr **ps1,
229 : char odata, size_t olen,
230 : char ndata, size_t nlen, size_t lim)
231 85 : {
232 85 : size_t num = 0;
233 85 : size_t tlen = 0;
234 85 : size_t pos = 0;
235 85 : struct Ustr *ret = USTR_NULL;
236 : const char *rptr;
237 85 : size_t lpos = 0;
238 85 : size_t roff = 0;
239 :
240 42 : USTR_ASSERT(ps1 && ustrp__assert_valid(!!p, *ps1));
241 :
242 85 : if ((nlen == olen) && ustr_owner(*ps1))
243 20 : return (ustrp__replace_inline_rep_chr(p, ps1, odata,olen, ndata,nlen, lim));
244 :
245 : /* pre-calc size, and do single alloc and then memcpy.
246 : * Using dup()/ustr_sc_sub() is much simpler but very slow
247 : * for large strings. */
248 65 : tlen = ustr_len(*ps1);
249 278 : while ((pos = ustr_srch_rep_chr_fwd(*ps1, pos, odata, olen)))
250 : {
251 153 : pos += olen - 1;
252 :
253 153 : if (nlen < olen) /* can go up or down */
254 48 : tlen -= (olen - nlen);
255 : else
256 : {
257 105 : if (tlen > (tlen + (nlen - olen)))
258 : {
259 1 : errno = USTR__ENOMEM;
260 1 : return (0);
261 : }
262 104 : tlen += (nlen - olen);
263 : }
264 :
265 152 : ++num;
266 152 : if (lim && (num == lim))
267 4 : break;
268 : }
269 :
270 64 : if (!num) /* minor speed hack */
271 : {
272 8 : errno = 0; /* only way to tell between FAILURE and NO REPLACEMENTS */
273 8 : return (0);
274 : }
275 :
276 56 : if (!tlen) /* minor speed hack */
277 5 : return (ustrp__del(p, ps1, ustr_len(*ps1)) ? num : 0);
278 :
279 80 : if (ustr_fixed(*ps1) && ((num <= 2) || ustr_limited(*ps1)))
280 : { /* if we will have to memmove() a lot, double copy */
281 8 : if (tlen <= ustr_size(*ps1))
282 4 : return (ustrp__replace_inline_rep_chr(p, ps1, odata,olen,ndata,nlen,lim));
283 :
284 6 : if (ustr_limited(*ps1))
285 4 : goto fail_alloc;
286 : }
287 :
288 162 : if (!(ret = ustrp__dupx_undef(p, USTR__DUPX_FROM(*ps1), tlen)))
289 8 : goto fail_alloc;
290 :
291 36 : rptr = ustr_cstr(*ps1);
292 36 : lpos = 1;
293 36 : roff = 0;
294 36 : pos = 0;
295 36 : num = 0;
296 164 : while ((pos = ustr_srch_rep_chr_fwd(*ps1, pos, odata, olen)))
297 : {
298 96 : const char *tptr = rptr + roff;
299 96 : size_t blen = pos - (roff + 1);
300 :
301 96 : pos += olen - 1;
302 48 : USTR_ASSERT(pos == (roff + blen + olen));
303 :
304 96 : ustrp__sub_buf(p, &ret, lpos, tptr, blen); lpos += blen;
305 96 : ustrp__sub_rep_chr(p, &ret, lpos, ndata, nlen); lpos += nlen;
306 :
307 96 : roff = pos;
308 :
309 96 : ++num;
310 96 : if (lim && (num == lim))
311 4 : break;
312 : }
313 45 : ustrp__sub_buf(p, &ret, lpos, rptr + roff, ustr_len(*ps1) - roff);
314 :
315 86 : if (!ustr_fixed(*ps1) || (tlen > ustr_size(*ps1)))
316 32 : ustrp__sc_free2(p, ps1, ret);
317 : else
318 : { /* fixed buffer, with multiple replacements ... but fits */
319 4 : ustrp__set(p, ps1, ret);
320 4 : ustrp__free(p, ret);
321 : }
322 :
323 36 : return (num);
324 :
325 12 : fail_alloc:
326 12 : ustr_setf_enomem_err(*ps1);
327 12 : return (0);
328 : }
329 : USTR_CONF_I_PROTO
330 : size_t ustr_replace_rep_chr(struct Ustr **ps1, char odata, size_t olen,
331 : char ndata, size_t nlen, size_t lim)
332 69 : { return (ustrp__replace_rep_chr(0, ps1, odata, olen, ndata, nlen, lim)); }
333 : USTR_CONF_I_PROTO
334 : size_t ustrp_replace_rep_chr(struct Ustr_pool *p, struct Ustrp **ps1,
335 : char odata, size_t olen,
336 : char ndata, size_t nlen, size_t lim)
337 16 : {
338 16 : struct Ustr *tmp = &(*ps1)->s;
339 16 : int ret = ustrp__replace_rep_chr(p, &tmp, odata, olen, ndata, nlen, lim);
340 16 : *ps1 = USTRP(tmp);
341 16 : return (ret);
342 : }
|