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 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 70ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0) 71static 72atf_error_t 73prepend_or_append(atf_dynstr_t *ad, const char *fmt, va_list ap, 74 bool prepend) 75{ 76 char *aux; 77 atf_error_t err; 78 size_t newlen; 79 va_list ap2; 80 81 va_copy(ap2, ap); 82 err = atf_text_format_ap(&aux, fmt, ap2); 83 va_end(ap2); 84 if (atf_is_error(err)) 85 goto out; 86 newlen = ad->m_length + strlen(aux); 87 88 if (newlen + sizeof(char) > ad->m_datasize) { 89 err = resize(ad, newlen + sizeof(char)); 90 if (atf_is_error(err)) 91 goto out_free; 92 } 93 94 if (prepend) { 95 memmove(ad->m_data + strlen(aux), ad->m_data, ad->m_length + 1); 96 memcpy(ad->m_data, aux, strlen(aux)); 97 } else 98 strcpy(ad->m_data + ad->m_length, aux); 99 ad->m_length = newlen; 100 err = atf_no_error(); 101 102out_free: 103 free(aux); 104out: 105 return err; 106} 107 108/* --------------------------------------------------------------------- 109 * The "atf_dynstr" type. 110 * --------------------------------------------------------------------- */ 111 112/* 113 * Constants. 114 */ 115 116const size_t atf_dynstr_npos = SIZE_MAX; 117 118/* 119 * Constructors and destructors. 120 */ 121 122atf_error_t 123atf_dynstr_init(atf_dynstr_t *ad) 124{ 125 atf_error_t err; 126 127 ad->m_data = (char *)malloc(sizeof(char)); 128 if (ad->m_data == NULL) { 129 err = atf_no_memory_error(); 130 goto out; 131 } 132 133 ad->m_data[0] = '\0'; 134 ad->m_datasize = 1; 135 ad->m_length = 0; 136 err = atf_no_error(); 137 138out: 139 return err; 140} 141 142atf_error_t 143atf_dynstr_init_ap(atf_dynstr_t *ad, const char *fmt, va_list ap) 144{ 145 atf_error_t err; 146 147 ad->m_datasize = strlen(fmt) + 1; 148 ad->m_length = 0; 149 150 do { 151 va_list ap2; 152 int ret; 153 154 ad->m_datasize *= 2; 155 ad->m_data = (char *)malloc(ad->m_datasize); 156 if (ad->m_data == NULL) { 157 err = atf_no_memory_error(); 158 goto out; 159 } 160 161 va_copy(ap2, ap); 162 ret = vsnprintf(ad->m_data, ad->m_datasize, fmt, ap2); 163 va_end(ap2); 164 if (ret < 0) { 165 free(ad->m_data); 166 err = atf_libc_error(errno, "Cannot format string"); 167 goto out; 168 } 169 170 INV(ret >= 0); 171 if ((size_t)ret >= ad->m_datasize) { 172 free(ad->m_data); 173 ad->m_data = NULL; 174 } 175 ad->m_length = ret; 176 } while (ad->m_length >= ad->m_datasize); 177 178 err = atf_no_error(); 179out: 180 POST(atf_is_error(err) || ad->m_data != NULL); 181 return err; 182} 183 184atf_error_t 185atf_dynstr_init_fmt(atf_dynstr_t *ad, const char *fmt, ...) 186{ 187 va_list ap; 188 atf_error_t err; 189 190 va_start(ap, fmt); 191 err = atf_dynstr_init_ap(ad, fmt, ap); 192 va_end(ap); 193 194 return err; 195} 196 197atf_error_t 198atf_dynstr_init_raw(atf_dynstr_t *ad, const void *mem, size_t memlen) 199{ 200 atf_error_t err; 201 202 if (memlen >= SIZE_MAX - 1) { 203 err = atf_no_memory_error(); 204 goto out; 205 } 206 207 ad->m_data = (char *)malloc(memlen + 1); 208 if (ad->m_data == NULL) { 209 err = atf_no_memory_error(); 210 goto out; 211 } 212 213 ad->m_datasize = memlen + 1; 214 memcpy(ad->m_data, mem, memlen); 215 ad->m_data[memlen] = '\0'; 216 ad->m_length = strlen(ad->m_data); 217 INV(ad->m_length <= memlen); 218 err = atf_no_error(); 219 220out: 221 return err; 222} 223 224atf_error_t 225atf_dynstr_init_rep(atf_dynstr_t *ad, size_t len, char ch) 226{ 227 atf_error_t err; 228 229 if (len == SIZE_MAX) { 230 err = atf_no_memory_error(); 231 goto out; 232 } 233 234 ad->m_datasize = (len + 1) * sizeof(char); 235 ad->m_data = (char *)malloc(ad->m_datasize); 236 if (ad->m_data == NULL) { 237 err = atf_no_memory_error(); 238 goto out; 239 } 240 241 memset(ad->m_data, ch, len); 242 ad->m_data[len] = '\0'; 243 ad->m_length = len; 244 err = atf_no_error(); 245 246out: 247 return err; 248} 249 250atf_error_t 251atf_dynstr_init_substr(atf_dynstr_t *ad, const atf_dynstr_t *src, 252 size_t beg, size_t end) 253{ 254 if (beg > src->m_length) 255 beg = src->m_length; 256 257 if (end == atf_dynstr_npos || end > src->m_length) 258 end = src->m_length; 259 260 return atf_dynstr_init_raw(ad, src->m_data + beg, end - beg); 261} 262 263atf_error_t 264atf_dynstr_copy(atf_dynstr_t *dest, const atf_dynstr_t *src) 265{ 266 atf_error_t err; 267 268 dest->m_data = (char *)malloc(src->m_datasize); 269 if (dest->m_data == NULL) 270 err = atf_no_memory_error(); 271 else { 272 memcpy(dest->m_data, src->m_data, src->m_datasize); 273 dest->m_datasize = src->m_datasize; 274 dest->m_length = src->m_length; 275 err = atf_no_error(); 276 } 277 278 return err; 279} 280 281void 282atf_dynstr_fini(atf_dynstr_t *ad) 283{ 284 INV(ad->m_data != NULL); 285 free(ad->m_data); 286} 287 288char * 289atf_dynstr_fini_disown(atf_dynstr_t *ad) 290{ 291 INV(ad->m_data != NULL); 292 return ad->m_data; 293} 294 295/* 296 * Getters. 297 */ 298 299const char * 300atf_dynstr_cstring(const atf_dynstr_t *ad) 301{ 302 return ad->m_data; 303} 304 305size_t 306atf_dynstr_length(const atf_dynstr_t *ad) 307{ 308 return ad->m_length; 309} 310 311size_t 312atf_dynstr_rfind_ch(const atf_dynstr_t *ad, char ch) 313{ 314 size_t pos; 315 316 for (pos = ad->m_length; pos > 0 && ad->m_data[pos - 1] != ch; pos--) 317 ; 318 319 return pos == 0 ? atf_dynstr_npos : pos - 1; 320} 321 322/* 323 * Modifiers. 324 */ 325 326atf_error_t 327atf_dynstr_append_ap(atf_dynstr_t *ad, const char *fmt, va_list ap) 328{ 329 atf_error_t err; 330 va_list ap2; 331 332 va_copy(ap2, ap); 333 err = prepend_or_append(ad, fmt, ap2, false); 334 va_end(ap2); 335 336 return err; 337} 338 339atf_error_t 340atf_dynstr_append_fmt(atf_dynstr_t *ad, const char *fmt, ...) 341{ 342 va_list ap; 343 atf_error_t err; 344 345 va_start(ap, fmt); 346 err = prepend_or_append(ad, fmt, ap, false); 347 va_end(ap); 348 349 return err; 350} 351 352void 353atf_dynstr_clear(atf_dynstr_t *ad) 354{ 355 ad->m_data[0] = '\0'; 356 ad->m_length = 0; 357} 358 359atf_error_t 360atf_dynstr_prepend_ap(atf_dynstr_t *ad, const char *fmt, va_list ap) 361{ 362 atf_error_t err; 363 va_list ap2; 364 365 va_copy(ap2, ap); 366 err = prepend_or_append(ad, fmt, ap2, true); 367 va_end(ap2); 368 369 return err; 370} 371 372atf_error_t 373atf_dynstr_prepend_fmt(atf_dynstr_t *ad, const char *fmt, ...) 374{ 375 va_list ap; 376 atf_error_t err; 377 378 va_start(ap, fmt); 379 err = prepend_or_append(ad, fmt, ap, true); 380 va_end(ap); 381 382 return err; 383} 384 385/* 386 * Operators. 387 */ 388 389bool 390atf_equal_dynstr_cstring(const atf_dynstr_t *ad, const char *str) 391{ 392 return strcmp(ad->m_data, str) == 0; 393} 394 395bool 396atf_equal_dynstr_dynstr(const atf_dynstr_t *s1, const atf_dynstr_t *s2) 397{ 398 return strcmp(s1->m_data, s2->m_data) == 0; 399} 400