1273929Sjmmv/* Copyright (c) 2008 The NetBSD Foundation, Inc.
2240116Smarcel * All rights reserved.
3240116Smarcel *
4240116Smarcel * Redistribution and use in source and binary forms, with or without
5240116Smarcel * modification, are permitted provided that the following conditions
6240116Smarcel * are met:
7240116Smarcel * 1. Redistributions of source code must retain the above copyright
8240116Smarcel *    notice, this list of conditions and the following disclaimer.
9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel *    notice, this list of conditions and the following disclaimer in the
11240116Smarcel *    documentation and/or other materials provided with the distribution.
12240116Smarcel *
13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24273929Sjmmv * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25240116Smarcel
26273929Sjmmv#include "atf-c/detail/dynstr.h"
27273929Sjmmv
28240116Smarcel#include <errno.h>
29240116Smarcel#include <stdarg.h>
30240116Smarcel#include <stdint.h>
31240116Smarcel#include <stdio.h>
32240116Smarcel#include <stdlib.h>
33240116Smarcel#include <string.h>
34240116Smarcel
35273929Sjmmv#include "atf-c/detail/sanity.h"
36273929Sjmmv#include "atf-c/detail/text.h"
37240116Smarcel#include "atf-c/error.h"
38240116Smarcel
39240116Smarcel/* ---------------------------------------------------------------------
40240116Smarcel * Auxiliary functions.
41240116Smarcel * --------------------------------------------------------------------- */
42240116Smarcel
43240116Smarcelstatic
44240116Smarcelatf_error_t
45240116Smarcelresize(atf_dynstr_t *ad, size_t newsize)
46240116Smarcel{
47240116Smarcel    char *newdata;
48240116Smarcel    atf_error_t err;
49240116Smarcel
50240116Smarcel    PRE(newsize > ad->m_datasize);
51240116Smarcel
52240116Smarcel    newdata = (char *)malloc(newsize);
53240116Smarcel    if (newdata == NULL) {
54240116Smarcel        err = atf_no_memory_error();
55240116Smarcel    } else {
56240116Smarcel        strcpy(newdata, ad->m_data);
57240116Smarcel        free(ad->m_data);
58240116Smarcel        ad->m_data = newdata;
59240116Smarcel        ad->m_datasize = newsize;
60240116Smarcel        err = atf_no_error();
61240116Smarcel    }
62240116Smarcel
63240116Smarcel    return err;
64240116Smarcel}
65240116Smarcel
66240116Smarcelstatic
67240116Smarcelatf_error_t
68240116Smarcelprepend_or_append(atf_dynstr_t *ad, const char *fmt, va_list ap,
69240116Smarcel                  bool prepend)
70240116Smarcel{
71240116Smarcel    char *aux;
72240116Smarcel    atf_error_t err;
73240116Smarcel    size_t newlen;
74240116Smarcel    va_list ap2;
75240116Smarcel
76240116Smarcel    va_copy(ap2, ap);
77240116Smarcel    err = atf_text_format_ap(&aux, fmt, ap2);
78240116Smarcel    va_end(ap2);
79240116Smarcel    if (atf_is_error(err))
80240116Smarcel        goto out;
81240116Smarcel    newlen = ad->m_length + strlen(aux);
82240116Smarcel
83240116Smarcel    if (newlen + sizeof(char) > ad->m_datasize) {
84240116Smarcel        err = resize(ad, newlen + sizeof(char));
85240116Smarcel        if (atf_is_error(err))
86240116Smarcel            goto out_free;
87240116Smarcel    }
88240116Smarcel
89240116Smarcel    if (prepend) {
90240116Smarcel        memmove(ad->m_data + strlen(aux), ad->m_data, ad->m_length + 1);
91240116Smarcel        memcpy(ad->m_data, aux, strlen(aux));
92240116Smarcel    } else
93240116Smarcel        strcpy(ad->m_data + ad->m_length, aux);
94240116Smarcel    ad->m_length = newlen;
95240116Smarcel    err = atf_no_error();
96240116Smarcel
97240116Smarcelout_free:
98240116Smarcel    free(aux);
99240116Smarcelout:
100240116Smarcel    return err;
101240116Smarcel}
102240116Smarcel
103240116Smarcel/* ---------------------------------------------------------------------
104240116Smarcel * The "atf_dynstr" type.
105240116Smarcel * --------------------------------------------------------------------- */
106240116Smarcel
107240116Smarcel/*
108240116Smarcel * Constants.
109240116Smarcel */
110240116Smarcel
111240116Smarcelconst size_t atf_dynstr_npos = SIZE_MAX;
112240116Smarcel
113240116Smarcel/*
114240116Smarcel * Constructors and destructors.
115240116Smarcel */
116240116Smarcel
117240116Smarcelatf_error_t
118240116Smarcelatf_dynstr_init(atf_dynstr_t *ad)
119240116Smarcel{
120240116Smarcel    atf_error_t err;
121240116Smarcel
122240116Smarcel    ad->m_data = (char *)malloc(sizeof(char));
123240116Smarcel    if (ad->m_data == NULL) {
124240116Smarcel        err = atf_no_memory_error();
125240116Smarcel        goto out;
126240116Smarcel    }
127240116Smarcel
128240116Smarcel    ad->m_data[0] = '\0';
129240116Smarcel    ad->m_datasize = 1;
130240116Smarcel    ad->m_length = 0;
131240116Smarcel    err = atf_no_error();
132240116Smarcel
133240116Smarcelout:
134240116Smarcel    return err;
135240116Smarcel}
136240116Smarcel
137240116Smarcelatf_error_t
138240116Smarcelatf_dynstr_init_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
139240116Smarcel{
140240116Smarcel    atf_error_t err;
141240116Smarcel
142240116Smarcel    ad->m_datasize = strlen(fmt) + 1;
143240116Smarcel    ad->m_length = 0;
144240116Smarcel
145240116Smarcel    do {
146240116Smarcel        va_list ap2;
147240116Smarcel        int ret;
148240116Smarcel
149240116Smarcel        ad->m_datasize *= 2;
150240116Smarcel        ad->m_data = (char *)malloc(ad->m_datasize);
151240116Smarcel        if (ad->m_data == NULL) {
152240116Smarcel            err = atf_no_memory_error();
153240116Smarcel            goto out;
154240116Smarcel        }
155240116Smarcel
156240116Smarcel        va_copy(ap2, ap);
157240116Smarcel        ret = vsnprintf(ad->m_data, ad->m_datasize, fmt, ap2);
158240116Smarcel        va_end(ap2);
159240116Smarcel        if (ret < 0) {
160240116Smarcel            free(ad->m_data);
161240116Smarcel            err = atf_libc_error(errno, "Cannot format string");
162240116Smarcel            goto out;
163240116Smarcel        }
164240116Smarcel
165240116Smarcel        INV(ret >= 0);
166240116Smarcel        if ((size_t)ret >= ad->m_datasize) {
167240116Smarcel            free(ad->m_data);
168240116Smarcel            ad->m_data = NULL;
169240116Smarcel        }
170240116Smarcel        ad->m_length = ret;
171240116Smarcel    } while (ad->m_length >= ad->m_datasize);
172240116Smarcel
173240116Smarcel    err = atf_no_error();
174240116Smarcelout:
175240116Smarcel    POST(atf_is_error(err) || ad->m_data != NULL);
176240116Smarcel    return err;
177240116Smarcel}
178240116Smarcel
179240116Smarcelatf_error_t
180240116Smarcelatf_dynstr_init_fmt(atf_dynstr_t *ad, const char *fmt, ...)
181240116Smarcel{
182240116Smarcel    va_list ap;
183240116Smarcel    atf_error_t err;
184240116Smarcel
185240116Smarcel    va_start(ap, fmt);
186240116Smarcel    err = atf_dynstr_init_ap(ad, fmt, ap);
187240116Smarcel    va_end(ap);
188240116Smarcel
189240116Smarcel    return err;
190240116Smarcel}
191240116Smarcel
192240116Smarcelatf_error_t
193240116Smarcelatf_dynstr_init_raw(atf_dynstr_t *ad, const void *mem, size_t memlen)
194240116Smarcel{
195240116Smarcel    atf_error_t err;
196240116Smarcel
197240116Smarcel    if (memlen >= SIZE_MAX - 1) {
198240116Smarcel        err = atf_no_memory_error();
199240116Smarcel        goto out;
200240116Smarcel    }
201240116Smarcel
202240116Smarcel    ad->m_data = (char *)malloc(memlen + 1);
203240116Smarcel    if (ad->m_data == NULL) {
204240116Smarcel        err = atf_no_memory_error();
205240116Smarcel        goto out;
206240116Smarcel    }
207240116Smarcel
208240116Smarcel    ad->m_datasize = memlen + 1;
209240116Smarcel    memcpy(ad->m_data, mem, memlen);
210240116Smarcel    ad->m_data[memlen] = '\0';
211240116Smarcel    ad->m_length = strlen(ad->m_data);
212240116Smarcel    INV(ad->m_length <= memlen);
213240116Smarcel    err = atf_no_error();
214240116Smarcel
215240116Smarcelout:
216240116Smarcel    return err;
217240116Smarcel}
218240116Smarcel
219240116Smarcelatf_error_t
220240116Smarcelatf_dynstr_init_rep(atf_dynstr_t *ad, size_t len, char ch)
221240116Smarcel{
222240116Smarcel    atf_error_t err;
223240116Smarcel
224240116Smarcel    if (len == SIZE_MAX) {
225240116Smarcel        err = atf_no_memory_error();
226240116Smarcel        goto out;
227240116Smarcel    }
228240116Smarcel
229240116Smarcel    ad->m_datasize = (len + 1) * sizeof(char);
230240116Smarcel    ad->m_data = (char *)malloc(ad->m_datasize);
231240116Smarcel    if (ad->m_data == NULL) {
232240116Smarcel        err = atf_no_memory_error();
233240116Smarcel        goto out;
234240116Smarcel    }
235240116Smarcel
236240116Smarcel    memset(ad->m_data, ch, len);
237240116Smarcel    ad->m_data[len] = '\0';
238240116Smarcel    ad->m_length = len;
239240116Smarcel    err = atf_no_error();
240240116Smarcel
241240116Smarcelout:
242240116Smarcel    return err;
243240116Smarcel}
244240116Smarcel
245240116Smarcelatf_error_t
246240116Smarcelatf_dynstr_init_substr(atf_dynstr_t *ad, const atf_dynstr_t *src,
247240116Smarcel                       size_t beg, size_t end)
248240116Smarcel{
249240116Smarcel    if (beg > src->m_length)
250240116Smarcel        beg = src->m_length;
251240116Smarcel
252240116Smarcel    if (end == atf_dynstr_npos || end > src->m_length)
253240116Smarcel        end = src->m_length;
254240116Smarcel
255240116Smarcel    return atf_dynstr_init_raw(ad, src->m_data + beg, end - beg);
256240116Smarcel}
257240116Smarcel
258240116Smarcelatf_error_t
259240116Smarcelatf_dynstr_copy(atf_dynstr_t *dest, const atf_dynstr_t *src)
260240116Smarcel{
261240116Smarcel    atf_error_t err;
262240116Smarcel
263240116Smarcel    dest->m_data = (char *)malloc(src->m_datasize);
264240116Smarcel    if (dest->m_data == NULL)
265240116Smarcel        err = atf_no_memory_error();
266240116Smarcel    else {
267240116Smarcel        memcpy(dest->m_data, src->m_data, src->m_datasize);
268240116Smarcel        dest->m_datasize = src->m_datasize;
269240116Smarcel        dest->m_length = src->m_length;
270240116Smarcel        err = atf_no_error();
271240116Smarcel    }
272240116Smarcel
273240116Smarcel    return err;
274240116Smarcel}
275240116Smarcel
276240116Smarcelvoid
277240116Smarcelatf_dynstr_fini(atf_dynstr_t *ad)
278240116Smarcel{
279240116Smarcel    INV(ad->m_data != NULL);
280240116Smarcel    free(ad->m_data);
281240116Smarcel}
282240116Smarcel
283240116Smarcelchar *
284240116Smarcelatf_dynstr_fini_disown(atf_dynstr_t *ad)
285240116Smarcel{
286240116Smarcel    INV(ad->m_data != NULL);
287240116Smarcel    return ad->m_data;
288240116Smarcel}
289240116Smarcel
290240116Smarcel/*
291240116Smarcel * Getters.
292240116Smarcel */
293240116Smarcel
294240116Smarcelconst char *
295240116Smarcelatf_dynstr_cstring(const atf_dynstr_t *ad)
296240116Smarcel{
297240116Smarcel    return ad->m_data;
298240116Smarcel}
299240116Smarcel
300240116Smarcelsize_t
301240116Smarcelatf_dynstr_length(const atf_dynstr_t *ad)
302240116Smarcel{
303240116Smarcel    return ad->m_length;
304240116Smarcel}
305240116Smarcel
306240116Smarcelsize_t
307240116Smarcelatf_dynstr_rfind_ch(const atf_dynstr_t *ad, char ch)
308240116Smarcel{
309240116Smarcel    size_t pos;
310240116Smarcel
311240116Smarcel    for (pos = ad->m_length; pos > 0 && ad->m_data[pos - 1] != ch; pos--)
312240116Smarcel        ;
313240116Smarcel
314240116Smarcel    return pos == 0 ? atf_dynstr_npos : pos - 1;
315240116Smarcel}
316240116Smarcel
317240116Smarcel/*
318240116Smarcel * Modifiers.
319240116Smarcel */
320240116Smarcel
321240116Smarcelatf_error_t
322240116Smarcelatf_dynstr_append_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
323240116Smarcel{
324240116Smarcel    atf_error_t err;
325240116Smarcel    va_list ap2;
326240116Smarcel
327240116Smarcel    va_copy(ap2, ap);
328240116Smarcel    err = prepend_or_append(ad, fmt, ap2, false);
329240116Smarcel    va_end(ap2);
330240116Smarcel
331240116Smarcel    return err;
332240116Smarcel}
333240116Smarcel
334240116Smarcelatf_error_t
335240116Smarcelatf_dynstr_append_fmt(atf_dynstr_t *ad, const char *fmt, ...)
336240116Smarcel{
337240116Smarcel    va_list ap;
338240116Smarcel    atf_error_t err;
339240116Smarcel
340240116Smarcel    va_start(ap, fmt);
341240116Smarcel    err = prepend_or_append(ad, fmt, ap, false);
342240116Smarcel    va_end(ap);
343240116Smarcel
344240116Smarcel    return err;
345240116Smarcel}
346240116Smarcel
347240116Smarcelvoid
348240116Smarcelatf_dynstr_clear(atf_dynstr_t *ad)
349240116Smarcel{
350240116Smarcel    ad->m_data[0] = '\0';
351240116Smarcel    ad->m_length = 0;
352240116Smarcel}
353240116Smarcel
354240116Smarcelatf_error_t
355240116Smarcelatf_dynstr_prepend_ap(atf_dynstr_t *ad, const char *fmt, va_list ap)
356240116Smarcel{
357240116Smarcel    atf_error_t err;
358240116Smarcel    va_list ap2;
359240116Smarcel
360240116Smarcel    va_copy(ap2, ap);
361240116Smarcel    err = prepend_or_append(ad, fmt, ap2, true);
362240116Smarcel    va_end(ap2);
363240116Smarcel
364240116Smarcel    return err;
365240116Smarcel}
366240116Smarcel
367240116Smarcelatf_error_t
368240116Smarcelatf_dynstr_prepend_fmt(atf_dynstr_t *ad, const char *fmt, ...)
369240116Smarcel{
370240116Smarcel    va_list ap;
371240116Smarcel    atf_error_t err;
372240116Smarcel
373240116Smarcel    va_start(ap, fmt);
374240116Smarcel    err = prepend_or_append(ad, fmt, ap, true);
375240116Smarcel    va_end(ap);
376240116Smarcel
377240116Smarcel    return err;
378240116Smarcel}
379240116Smarcel
380240116Smarcel/*
381240116Smarcel * Operators.
382240116Smarcel */
383240116Smarcel
384240116Smarcelbool
385240116Smarcelatf_equal_dynstr_cstring(const atf_dynstr_t *ad, const char *str)
386240116Smarcel{
387240116Smarcel    return strcmp(ad->m_data, str) == 0;
388240116Smarcel}
389240116Smarcel
390240116Smarcelbool
391240116Smarcelatf_equal_dynstr_dynstr(const atf_dynstr_t *s1, const atf_dynstr_t *s2)
392240116Smarcel{
393240116Smarcel    return strcmp(s1->m_data, s2->m_data) == 0;
394240116Smarcel}
395