1/* 2 * Automated Testing Framework (atf) 3 * 4 * Copyright (c) 2008, 2009, 2010 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 47static 48atf_error_t 49resize(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 70static 71atf_error_t 72prepend_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 101out_free: 102 free(aux); 103out: 104 return err; 105} 106 107/* --------------------------------------------------------------------- 108 * The "atf_dynstr" type. 109 * --------------------------------------------------------------------- */ 110 111/* 112 * Constants. 113 */ 114 115const size_t atf_dynstr_npos = SIZE_MAX; 116 117/* 118 * Constructors and destructors. 119 */ 120 121atf_error_t 122atf_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 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