dynstr.c revision 275988
1/* Copyright (c) 2008 The NetBSD Foundation, Inc.
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
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25
26#include "atf-c/detail/dynstr.h"
27
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
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}
395