Deleted Added
full compact
dynstr.c (240120) dynstr.c (273929)
1/*
2 * Automated Testing Framework (atf)
3 *
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
1/* Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29
25
26#include "atf-c/detail/dynstr.h"
27
30#include <errno.h>
31#include <stdarg.h>
32#include <stdint.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36
28#include <errno.h>
29#include <stdarg.h>
30#include <stdint.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35#include "atf-c/detail/sanity.h"
36#include "atf-c/detail/text.h"
37#include "atf-c/error.h"
38
37#include "atf-c/error.h"
38
39#include "dynstr.h"
40#include "sanity.h"
41#include "text.h"
42
43/* ---------------------------------------------------------------------
44 * Auxiliary functions.
45 * --------------------------------------------------------------------- */
46
47static
48atf_error_t
49resize(atf_dynstr_t *ad, size_t newsize)
50{
51 char *newdata;
52 atf_error_t err;
53
54 PRE(newsize > ad->m_datasize);
55
56 newdata = (char *)malloc(newsize);
57 if (newdata == NULL) {
58 err = atf_no_memory_error();
59 } else {
60 strcpy(newdata, ad->m_data);
61 free(ad->m_data);
62 ad->m_data = newdata;
63 ad->m_datasize = newsize;
64 err = atf_no_error();
65 }
66
67 return err;
68}
69
70static
71atf_error_t
72prepend_or_append(atf_dynstr_t *ad, const char *fmt, va_list ap,
73 bool prepend)
74{
75 char *aux;
76 atf_error_t err;
77 size_t newlen;
78 va_list ap2;
79
80 va_copy(ap2, ap);
81 err = atf_text_format_ap(&aux, fmt, ap2);
82 va_end(ap2);
83 if (atf_is_error(err))
84 goto out;
85 newlen = ad->m_length + strlen(aux);
86
87 if (newlen + sizeof(char) > ad->m_datasize) {
88 err = resize(ad, newlen + sizeof(char));
89 if (atf_is_error(err))
90 goto out_free;
91 }
92
93 if (prepend) {
94 memmove(ad->m_data + strlen(aux), ad->m_data, ad->m_length + 1);
95 memcpy(ad->m_data, aux, strlen(aux));
96 } else
97 strcpy(ad->m_data + ad->m_length, aux);
98 ad->m_length = newlen;
99 err = atf_no_error();
100
101out_free:
102 free(aux);
103out:
104 return err;
105}
106
107/* ---------------------------------------------------------------------
108 * The "atf_dynstr" type.
109 * --------------------------------------------------------------------- */
110
111/*
112 * Constants.
113 */
114
115const size_t atf_dynstr_npos = SIZE_MAX;
116
117/*
118 * Constructors and destructors.
119 */
120
121atf_error_t
122atf_dynstr_init(atf_dynstr_t *ad)
123{
124 atf_error_t err;
125
126 ad->m_data = (char *)malloc(sizeof(char));
127 if (ad->m_data == NULL) {
128 err = atf_no_memory_error();
129 goto out;
130 }
131
132 ad->m_data[0] = '\0';
133 ad->m_datasize = 1;
134 ad->m_length = 0;
135 err = atf_no_error();
136
137out:
138 return err;
139}
140
141atf_error_t
142atf_dynstr_init_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
143{
144 atf_error_t err;
145
146 ad->m_datasize = strlen(fmt) + 1;
147 ad->m_length = 0;
148
149 do {
150 va_list ap2;
151 int ret;
152
153 ad->m_datasize *= 2;
154 ad->m_data = (char *)malloc(ad->m_datasize);
155 if (ad->m_data == NULL) {
156 err = atf_no_memory_error();
157 goto out;
158 }
159
160 va_copy(ap2, ap);
161 ret = vsnprintf(ad->m_data, ad->m_datasize, fmt, ap2);
162 va_end(ap2);
163 if (ret < 0) {
164 free(ad->m_data);
165 err = atf_libc_error(errno, "Cannot format string");
166 goto out;
167 }
168
169 INV(ret >= 0);
170 if ((size_t)ret >= ad->m_datasize) {
171 free(ad->m_data);
172 ad->m_data = NULL;
173 }
174 ad->m_length = ret;
175 } while (ad->m_length >= ad->m_datasize);
176
177 err = atf_no_error();
178out:
179 POST(atf_is_error(err) || ad->m_data != NULL);
180 return err;
181}
182
183atf_error_t
184atf_dynstr_init_fmt(atf_dynstr_t *ad, const char *fmt, ...)
185{
186 va_list ap;
187 atf_error_t err;
188
189 va_start(ap, fmt);
190 err = atf_dynstr_init_ap(ad, fmt, ap);
191 va_end(ap);
192
193 return err;
194}
195
196atf_error_t
197atf_dynstr_init_raw(atf_dynstr_t *ad, const void *mem, size_t memlen)
198{
199 atf_error_t err;
200
201 if (memlen >= SIZE_MAX - 1) {
202 err = atf_no_memory_error();
203 goto out;
204 }
205
206 ad->m_data = (char *)malloc(memlen + 1);
207 if (ad->m_data == NULL) {
208 err = atf_no_memory_error();
209 goto out;
210 }
211
212 ad->m_datasize = memlen + 1;
213 memcpy(ad->m_data, mem, memlen);
214 ad->m_data[memlen] = '\0';
215 ad->m_length = strlen(ad->m_data);
216 INV(ad->m_length <= memlen);
217 err = atf_no_error();
218
219out:
220 return err;
221}
222
223atf_error_t
224atf_dynstr_init_rep(atf_dynstr_t *ad, size_t len, char ch)
225{
226 atf_error_t err;
227
228 if (len == SIZE_MAX) {
229 err = atf_no_memory_error();
230 goto out;
231 }
232
233 ad->m_datasize = (len + 1) * sizeof(char);
234 ad->m_data = (char *)malloc(ad->m_datasize);
235 if (ad->m_data == NULL) {
236 err = atf_no_memory_error();
237 goto out;
238 }
239
240 memset(ad->m_data, ch, len);
241 ad->m_data[len] = '\0';
242 ad->m_length = len;
243 err = atf_no_error();
244
245out:
246 return err;
247}
248
249atf_error_t
250atf_dynstr_init_substr(atf_dynstr_t *ad, const atf_dynstr_t *src,
251 size_t beg, size_t end)
252{
253 if (beg > src->m_length)
254 beg = src->m_length;
255
256 if (end == atf_dynstr_npos || end > src->m_length)
257 end = src->m_length;
258
259 return atf_dynstr_init_raw(ad, src->m_data + beg, end - beg);
260}
261
262atf_error_t
263atf_dynstr_copy(atf_dynstr_t *dest, const atf_dynstr_t *src)
264{
265 atf_error_t err;
266
267 dest->m_data = (char *)malloc(src->m_datasize);
268 if (dest->m_data == NULL)
269 err = atf_no_memory_error();
270 else {
271 memcpy(dest->m_data, src->m_data, src->m_datasize);
272 dest->m_datasize = src->m_datasize;
273 dest->m_length = src->m_length;
274 err = atf_no_error();
275 }
276
277 return err;
278}
279
280void
281atf_dynstr_fini(atf_dynstr_t *ad)
282{
283 INV(ad->m_data != NULL);
284 free(ad->m_data);
285}
286
287char *
288atf_dynstr_fini_disown(atf_dynstr_t *ad)
289{
290 INV(ad->m_data != NULL);
291 return ad->m_data;
292}
293
294/*
295 * Getters.
296 */
297
298const char *
299atf_dynstr_cstring(const atf_dynstr_t *ad)
300{
301 return ad->m_data;
302}
303
304size_t
305atf_dynstr_length(const atf_dynstr_t *ad)
306{
307 return ad->m_length;
308}
309
310size_t
311atf_dynstr_rfind_ch(const atf_dynstr_t *ad, char ch)
312{
313 size_t pos;
314
315 for (pos = ad->m_length; pos > 0 && ad->m_data[pos - 1] != ch; pos--)
316 ;
317
318 return pos == 0 ? atf_dynstr_npos : pos - 1;
319}
320
321/*
322 * Modifiers.
323 */
324
325atf_error_t
326atf_dynstr_append_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
327{
328 atf_error_t err;
329 va_list ap2;
330
331 va_copy(ap2, ap);
332 err = prepend_or_append(ad, fmt, ap2, false);
333 va_end(ap2);
334
335 return err;
336}
337
338atf_error_t
339atf_dynstr_append_fmt(atf_dynstr_t *ad, const char *fmt, ...)
340{
341 va_list ap;
342 atf_error_t err;
343
344 va_start(ap, fmt);
345 err = prepend_or_append(ad, fmt, ap, false);
346 va_end(ap);
347
348 return err;
349}
350
351void
352atf_dynstr_clear(atf_dynstr_t *ad)
353{
354 ad->m_data[0] = '\0';
355 ad->m_length = 0;
356}
357
358atf_error_t
359atf_dynstr_prepend_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
360{
361 atf_error_t err;
362 va_list ap2;
363
364 va_copy(ap2, ap);
365 err = prepend_or_append(ad, fmt, ap2, true);
366 va_end(ap2);
367
368 return err;
369}
370
371atf_error_t
372atf_dynstr_prepend_fmt(atf_dynstr_t *ad, const char *fmt, ...)
373{
374 va_list ap;
375 atf_error_t err;
376
377 va_start(ap, fmt);
378 err = prepend_or_append(ad, fmt, ap, true);
379 va_end(ap);
380
381 return err;
382}
383
384/*
385 * Operators.
386 */
387
388bool
389atf_equal_dynstr_cstring(const atf_dynstr_t *ad, const char *str)
390{
391 return strcmp(ad->m_data, str) == 0;
392}
393
394bool
395atf_equal_dynstr_dynstr(const atf_dynstr_t *s1, const atf_dynstr_t *s2)
396{
397 return strcmp(s1->m_data, s2->m_data) == 0;
398}
39/* ---------------------------------------------------------------------
40 * Auxiliary functions.
41 * --------------------------------------------------------------------- */
42
43static
44atf_error_t
45resize(atf_dynstr_t *ad, size_t newsize)
46{
47 char *newdata;
48 atf_error_t err;
49
50 PRE(newsize > ad->m_datasize);
51
52 newdata = (char *)malloc(newsize);
53 if (newdata == NULL) {
54 err = atf_no_memory_error();
55 } else {
56 strcpy(newdata, ad->m_data);
57 free(ad->m_data);
58 ad->m_data = newdata;
59 ad->m_datasize = newsize;
60 err = atf_no_error();
61 }
62
63 return err;
64}
65
66static
67atf_error_t
68prepend_or_append(atf_dynstr_t *ad, const char *fmt, va_list ap,
69 bool prepend)
70{
71 char *aux;
72 atf_error_t err;
73 size_t newlen;
74 va_list ap2;
75
76 va_copy(ap2, ap);
77 err = atf_text_format_ap(&aux, fmt, ap2);
78 va_end(ap2);
79 if (atf_is_error(err))
80 goto out;
81 newlen = ad->m_length + strlen(aux);
82
83 if (newlen + sizeof(char) > ad->m_datasize) {
84 err = resize(ad, newlen + sizeof(char));
85 if (atf_is_error(err))
86 goto out_free;
87 }
88
89 if (prepend) {
90 memmove(ad->m_data + strlen(aux), ad->m_data, ad->m_length + 1);
91 memcpy(ad->m_data, aux, strlen(aux));
92 } else
93 strcpy(ad->m_data + ad->m_length, aux);
94 ad->m_length = newlen;
95 err = atf_no_error();
96
97out_free:
98 free(aux);
99out:
100 return err;
101}
102
103/* ---------------------------------------------------------------------
104 * The "atf_dynstr" type.
105 * --------------------------------------------------------------------- */
106
107/*
108 * Constants.
109 */
110
111const size_t atf_dynstr_npos = SIZE_MAX;
112
113/*
114 * Constructors and destructors.
115 */
116
117atf_error_t
118atf_dynstr_init(atf_dynstr_t *ad)
119{
120 atf_error_t err;
121
122 ad->m_data = (char *)malloc(sizeof(char));
123 if (ad->m_data == NULL) {
124 err = atf_no_memory_error();
125 goto out;
126 }
127
128 ad->m_data[0] = '\0';
129 ad->m_datasize = 1;
130 ad->m_length = 0;
131 err = atf_no_error();
132
133out:
134 return err;
135}
136
137atf_error_t
138atf_dynstr_init_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
139{
140 atf_error_t err;
141
142 ad->m_datasize = strlen(fmt) + 1;
143 ad->m_length = 0;
144
145 do {
146 va_list ap2;
147 int ret;
148
149 ad->m_datasize *= 2;
150 ad->m_data = (char *)malloc(ad->m_datasize);
151 if (ad->m_data == NULL) {
152 err = atf_no_memory_error();
153 goto out;
154 }
155
156 va_copy(ap2, ap);
157 ret = vsnprintf(ad->m_data, ad->m_datasize, fmt, ap2);
158 va_end(ap2);
159 if (ret < 0) {
160 free(ad->m_data);
161 err = atf_libc_error(errno, "Cannot format string");
162 goto out;
163 }
164
165 INV(ret >= 0);
166 if ((size_t)ret >= ad->m_datasize) {
167 free(ad->m_data);
168 ad->m_data = NULL;
169 }
170 ad->m_length = ret;
171 } while (ad->m_length >= ad->m_datasize);
172
173 err = atf_no_error();
174out:
175 POST(atf_is_error(err) || ad->m_data != NULL);
176 return err;
177}
178
179atf_error_t
180atf_dynstr_init_fmt(atf_dynstr_t *ad, const char *fmt, ...)
181{
182 va_list ap;
183 atf_error_t err;
184
185 va_start(ap, fmt);
186 err = atf_dynstr_init_ap(ad, fmt, ap);
187 va_end(ap);
188
189 return err;
190}
191
192atf_error_t
193atf_dynstr_init_raw(atf_dynstr_t *ad, const void *mem, size_t memlen)
194{
195 atf_error_t err;
196
197 if (memlen >= SIZE_MAX - 1) {
198 err = atf_no_memory_error();
199 goto out;
200 }
201
202 ad->m_data = (char *)malloc(memlen + 1);
203 if (ad->m_data == NULL) {
204 err = atf_no_memory_error();
205 goto out;
206 }
207
208 ad->m_datasize = memlen + 1;
209 memcpy(ad->m_data, mem, memlen);
210 ad->m_data[memlen] = '\0';
211 ad->m_length = strlen(ad->m_data);
212 INV(ad->m_length <= memlen);
213 err = atf_no_error();
214
215out:
216 return err;
217}
218
219atf_error_t
220atf_dynstr_init_rep(atf_dynstr_t *ad, size_t len, char ch)
221{
222 atf_error_t err;
223
224 if (len == SIZE_MAX) {
225 err = atf_no_memory_error();
226 goto out;
227 }
228
229 ad->m_datasize = (len + 1) * sizeof(char);
230 ad->m_data = (char *)malloc(ad->m_datasize);
231 if (ad->m_data == NULL) {
232 err = atf_no_memory_error();
233 goto out;
234 }
235
236 memset(ad->m_data, ch, len);
237 ad->m_data[len] = '\0';
238 ad->m_length = len;
239 err = atf_no_error();
240
241out:
242 return err;
243}
244
245atf_error_t
246atf_dynstr_init_substr(atf_dynstr_t *ad, const atf_dynstr_t *src,
247 size_t beg, size_t end)
248{
249 if (beg > src->m_length)
250 beg = src->m_length;
251
252 if (end == atf_dynstr_npos || end > src->m_length)
253 end = src->m_length;
254
255 return atf_dynstr_init_raw(ad, src->m_data + beg, end - beg);
256}
257
258atf_error_t
259atf_dynstr_copy(atf_dynstr_t *dest, const atf_dynstr_t *src)
260{
261 atf_error_t err;
262
263 dest->m_data = (char *)malloc(src->m_datasize);
264 if (dest->m_data == NULL)
265 err = atf_no_memory_error();
266 else {
267 memcpy(dest->m_data, src->m_data, src->m_datasize);
268 dest->m_datasize = src->m_datasize;
269 dest->m_length = src->m_length;
270 err = atf_no_error();
271 }
272
273 return err;
274}
275
276void
277atf_dynstr_fini(atf_dynstr_t *ad)
278{
279 INV(ad->m_data != NULL);
280 free(ad->m_data);
281}
282
283char *
284atf_dynstr_fini_disown(atf_dynstr_t *ad)
285{
286 INV(ad->m_data != NULL);
287 return ad->m_data;
288}
289
290/*
291 * Getters.
292 */
293
294const char *
295atf_dynstr_cstring(const atf_dynstr_t *ad)
296{
297 return ad->m_data;
298}
299
300size_t
301atf_dynstr_length(const atf_dynstr_t *ad)
302{
303 return ad->m_length;
304}
305
306size_t
307atf_dynstr_rfind_ch(const atf_dynstr_t *ad, char ch)
308{
309 size_t pos;
310
311 for (pos = ad->m_length; pos > 0 && ad->m_data[pos - 1] != ch; pos--)
312 ;
313
314 return pos == 0 ? atf_dynstr_npos : pos - 1;
315}
316
317/*
318 * Modifiers.
319 */
320
321atf_error_t
322atf_dynstr_append_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
323{
324 atf_error_t err;
325 va_list ap2;
326
327 va_copy(ap2, ap);
328 err = prepend_or_append(ad, fmt, ap2, false);
329 va_end(ap2);
330
331 return err;
332}
333
334atf_error_t
335atf_dynstr_append_fmt(atf_dynstr_t *ad, const char *fmt, ...)
336{
337 va_list ap;
338 atf_error_t err;
339
340 va_start(ap, fmt);
341 err = prepend_or_append(ad, fmt, ap, false);
342 va_end(ap);
343
344 return err;
345}
346
347void
348atf_dynstr_clear(atf_dynstr_t *ad)
349{
350 ad->m_data[0] = '\0';
351 ad->m_length = 0;
352}
353
354atf_error_t
355atf_dynstr_prepend_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
356{
357 atf_error_t err;
358 va_list ap2;
359
360 va_copy(ap2, ap);
361 err = prepend_or_append(ad, fmt, ap2, true);
362 va_end(ap2);
363
364 return err;
365}
366
367atf_error_t
368atf_dynstr_prepend_fmt(atf_dynstr_t *ad, const char *fmt, ...)
369{
370 va_list ap;
371 atf_error_t err;
372
373 va_start(ap, fmt);
374 err = prepend_or_append(ad, fmt, ap, true);
375 va_end(ap);
376
377 return err;
378}
379
380/*
381 * Operators.
382 */
383
384bool
385atf_equal_dynstr_cstring(const atf_dynstr_t *ad, const char *str)
386{
387 return strcmp(ad->m_data, str) == 0;
388}
389
390bool
391atf_equal_dynstr_dynstr(const atf_dynstr_t *s1, const atf_dynstr_t *s2)
392{
393 return strcmp(s1->m_data, s2->m_data) == 0;
394}