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