137131Sbrian/* 237131Sbrian * Automated Testing Framework (atf) 337131Sbrian * 437131Sbrian * Copyright (c) 2008 The NetBSD Foundation, Inc. 537131Sbrian * All rights reserved. 637131Sbrian * 737131Sbrian * Redistribution and use in source and binary forms, with or without 837131Sbrian * modification, are permitted provided that the following conditions 937131Sbrian * are met: 1037131Sbrian * 1. Redistributions of source code must retain the above copyright 1137131Sbrian * notice, this list of conditions and the following disclaimer. 1237131Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1337131Sbrian * notice, this list of conditions and the following disclaimer in the 1437131Sbrian * documentation and/or other materials provided with the distribution. 1537131Sbrian * 1637131Sbrian * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 1737131Sbrian * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 1837131Sbrian * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1937131Sbrian * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2037131Sbrian * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 2137131Sbrian * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2237131Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 2337131Sbrian * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2437131Sbrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 2537131Sbrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2637131Sbrian * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 2737131Sbrian * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2837131Sbrian */ 2984195Sdillon 3084195Sdillon#include <errno.h> 3184195Sdillon#include <stdarg.h> 32124621Sphk#include <stdint.h> 3337131Sbrian#include <stdio.h> 3437131Sbrian#include <stdlib.h> 3537131Sbrian#include <string.h> 3637131Sbrian 3737131Sbrian#include "atf-c/error.h" 3837131Sbrian 3937131Sbrian#include "dynstr.h" 4037131Sbrian#include "sanity.h" 4137131Sbrian#include "text.h" 4237131Sbrian 43127094Sdes/* --------------------------------------------------------------------- 44127094Sdes * Auxiliary functions. 45127094Sdes * --------------------------------------------------------------------- */ 46127094Sdes 47127094Sdesstatic 48127094Sdesatf_error_t 49127094Sdesresize(atf_dynstr_t *ad, size_t newsize) 50127094Sdes{ 51127094Sdes char *newdata; 52127094Sdes atf_error_t err; 5337131Sbrian 5437131Sbrian PRE(newsize > ad->m_datasize); 5537131Sbrian 5637131Sbrian newdata = (char *)malloc(newsize); 57127094Sdes if (newdata == NULL) { 58127094Sdes err = atf_no_memory_error(); 59127094Sdes } else { 60127094Sdes strcpy(newdata, ad->m_data); 6137131Sbrian free(ad->m_data); 6237131Sbrian ad->m_data = newdata; 6337131Sbrian ad->m_datasize = newsize; 6437131Sbrian err = atf_no_error(); 65127094Sdes } 66127094Sdes 67127094Sdes return err; 6837131Sbrian} 6937131Sbrian 7037131Sbrianstatic 71124621Sphkatf_error_t 7237131Sbrianprepend_or_append(atf_dynstr_t *ad, const char *fmt, va_list ap, 73127094Sdes bool prepend) 7437131Sbrian{ 75127094Sdes char *aux; 76127094Sdes atf_error_t err; 77127094Sdes size_t newlen; 78127094Sdes va_list ap2; 7937131Sbrian 80127094Sdes va_copy(ap2, ap); 81127094Sdes err = atf_text_format_ap(&aux, fmt, ap2); 82127094Sdes va_end(ap2); 8337131Sbrian if (atf_is_error(err)) 84127094Sdes goto out; 85127094Sdes newlen = ad->m_length + strlen(aux); 8699207Sbrian 8737131Sbrian if (newlen + sizeof(char) > ad->m_datasize) { 88127094Sdes err = resize(ad, newlen + sizeof(char)); 89127094Sdes if (atf_is_error(err)) 9037131Sbrian goto out_free; 91127094Sdes } 9237131Sbrian 9337131Sbrian if (prepend) { 9437131Sbrian memmove(ad->m_data + strlen(aux), ad->m_data, ad->m_length + 1); 95124621Sphk memcpy(ad->m_data, aux, strlen(aux)); 9637131Sbrian } else 97127094Sdes strcpy(ad->m_data + ad->m_length, aux); 98127094Sdes ad->m_length = newlen; 99127094Sdes err = atf_no_error(); 100127094Sdes 101127094Sdesout_free: 102127094Sdes free(aux); 103127094Sdesout: 10437131Sbrian return err; 105127094Sdes} 106127094Sdes 107127094Sdes/* --------------------------------------------------------------------- 108127094Sdes * The "atf_dynstr" type. 109127094Sdes * --------------------------------------------------------------------- */ 110127094Sdes 11137131Sbrian/* 112127094Sdes * Constants. 113127094Sdes */ 114127094Sdes 115127094Sdesconst size_t atf_dynstr_npos = SIZE_MAX; 116127094Sdes 117127094Sdes/* 118127094Sdes * Constructors and destructors. 119127094Sdes */ 120127094Sdes 121127094Sdesatf_error_t 122127094Sdesatf_dynstr_init(atf_dynstr_t *ad) 12337131Sbrian{ 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