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