137131Sbrian/*
237131Sbrian * Automated Testing Framework (atf)
337131Sbrian *
437131Sbrian * Copyright (c) 2008 The NetBSD Foundation, Inc.
537131Sbrian * All rights reserved.
637131Sbrian *
737131Sbrian * Redistribution and use in source and binary forms, with or without
837131Sbrian * modification, are permitted provided that the following conditions
937131Sbrian * are met:
1037131Sbrian * 1. Redistributions of source code must retain the above copyright
1137131Sbrian *    notice, this list of conditions and the following disclaimer.
1237131Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1337131Sbrian *    notice, this list of conditions and the following disclaimer in the
1437131Sbrian *    documentation and/or other materials provided with the distribution.
1537131Sbrian *
1637131Sbrian * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
1737131Sbrian * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
1837131Sbrian * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1937131Sbrian * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2037131Sbrian * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
2137131Sbrian * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2237131Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2337131Sbrian * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2437131Sbrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2537131Sbrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2637131Sbrian * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
2737131Sbrian * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2837131Sbrian */
2984195Sdillon
3084195Sdillon#include <errno.h>
3184195Sdillon#include <stdarg.h>
32124621Sphk#include <stdint.h>
3337131Sbrian#include <stdio.h>
3437131Sbrian#include <stdlib.h>
3537131Sbrian#include <string.h>
3637131Sbrian
3737131Sbrian#include "atf-c/error.h"
3837131Sbrian
3937131Sbrian#include "dynstr.h"
4037131Sbrian#include "sanity.h"
4137131Sbrian#include "text.h"
4237131Sbrian
43127094Sdes/* ---------------------------------------------------------------------
44127094Sdes * Auxiliary functions.
45127094Sdes * --------------------------------------------------------------------- */
46127094Sdes
47127094Sdesstatic
48127094Sdesatf_error_t
49127094Sdesresize(atf_dynstr_t *ad, size_t newsize)
50127094Sdes{
51127094Sdes    char *newdata;
52127094Sdes    atf_error_t err;
5337131Sbrian
5437131Sbrian    PRE(newsize > ad->m_datasize);
5537131Sbrian
5637131Sbrian    newdata = (char *)malloc(newsize);
57127094Sdes    if (newdata == NULL) {
58127094Sdes        err = atf_no_memory_error();
59127094Sdes    } else {
60127094Sdes        strcpy(newdata, ad->m_data);
6137131Sbrian        free(ad->m_data);
6237131Sbrian        ad->m_data = newdata;
6337131Sbrian        ad->m_datasize = newsize;
6437131Sbrian        err = atf_no_error();
65127094Sdes    }
66127094Sdes
67127094Sdes    return err;
6837131Sbrian}
6937131Sbrian
7037131Sbrianstatic
71124621Sphkatf_error_t
7237131Sbrianprepend_or_append(atf_dynstr_t *ad, const char *fmt, va_list ap,
73127094Sdes                  bool prepend)
7437131Sbrian{
75127094Sdes    char *aux;
76127094Sdes    atf_error_t err;
77127094Sdes    size_t newlen;
78127094Sdes    va_list ap2;
7937131Sbrian
80127094Sdes    va_copy(ap2, ap);
81127094Sdes    err = atf_text_format_ap(&aux, fmt, ap2);
82127094Sdes    va_end(ap2);
8337131Sbrian    if (atf_is_error(err))
84127094Sdes        goto out;
85127094Sdes    newlen = ad->m_length + strlen(aux);
8699207Sbrian
8737131Sbrian    if (newlen + sizeof(char) > ad->m_datasize) {
88127094Sdes        err = resize(ad, newlen + sizeof(char));
89127094Sdes        if (atf_is_error(err))
9037131Sbrian            goto out_free;
91127094Sdes    }
9237131Sbrian
9337131Sbrian    if (prepend) {
9437131Sbrian        memmove(ad->m_data + strlen(aux), ad->m_data, ad->m_length + 1);
95124621Sphk        memcpy(ad->m_data, aux, strlen(aux));
9637131Sbrian    } else
97127094Sdes        strcpy(ad->m_data + ad->m_length, aux);
98127094Sdes    ad->m_length = newlen;
99127094Sdes    err = atf_no_error();
100127094Sdes
101127094Sdesout_free:
102127094Sdes    free(aux);
103127094Sdesout:
10437131Sbrian    return err;
105127094Sdes}
106127094Sdes
107127094Sdes/* ---------------------------------------------------------------------
108127094Sdes * The "atf_dynstr" type.
109127094Sdes * --------------------------------------------------------------------- */
110127094Sdes
11137131Sbrian/*
112127094Sdes * Constants.
113127094Sdes */
114127094Sdes
115127094Sdesconst size_t atf_dynstr_npos = SIZE_MAX;
116127094Sdes
117127094Sdes/*
118127094Sdes * Constructors and destructors.
119127094Sdes */
120127094Sdes
121127094Sdesatf_error_t
122127094Sdesatf_dynstr_init(atf_dynstr_t *ad)
12337131Sbrian{
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}
399