]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/atf/atf-c/detail/dynstr.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / atf / atf-c / detail / dynstr.c
1 /*
2  * Automated Testing Framework (atf)
3  *
4  * 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
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
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
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
47 static
48 atf_error_t
49 resize(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
70 static
71 atf_error_t
72 prepend_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
101 out_free:
102     free(aux);
103 out:
104     return err;
105 }
106
107 /* ---------------------------------------------------------------------
108  * The "atf_dynstr" type.
109  * --------------------------------------------------------------------- */
110
111 /*
112  * Constants.
113  */
114
115 const size_t atf_dynstr_npos = SIZE_MAX;
116
117 /*
118  * Constructors and destructors.
119  */
120
121 atf_error_t
122 atf_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
137 out:
138     return err;
139 }
140
141 atf_error_t
142 atf_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();
178 out:
179     POST(atf_is_error(err) || ad->m_data != NULL);
180     return err;
181 }
182
183 atf_error_t
184 atf_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
196 atf_error_t
197 atf_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
219 out:
220     return err;
221 }
222
223 atf_error_t
224 atf_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
245 out:
246     return err;
247 }
248
249 atf_error_t
250 atf_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
262 atf_error_t
263 atf_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
280 void
281 atf_dynstr_fini(atf_dynstr_t *ad)
282 {
283     INV(ad->m_data != NULL);
284     free(ad->m_data);
285 }
286
287 char *
288 atf_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
298 const char *
299 atf_dynstr_cstring(const atf_dynstr_t *ad)
300 {
301     return ad->m_data;
302 }
303
304 size_t
305 atf_dynstr_length(const atf_dynstr_t *ad)
306 {
307     return ad->m_length;
308 }
309
310 size_t
311 atf_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
325 atf_error_t
326 atf_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
338 atf_error_t
339 atf_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
351 void
352 atf_dynstr_clear(atf_dynstr_t *ad)
353 {
354     ad->m_data[0] = '\0';
355     ad->m_length = 0;
356 }
357
358 atf_error_t
359 atf_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
371 atf_error_t
372 atf_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
388 bool
389 atf_equal_dynstr_cstring(const atf_dynstr_t *ad, const char *str)
390 {
391     return strcmp(ad->m_data, str) == 0;
392 }
393
394 bool
395 atf_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 }