dynstr.c revision 240116
1240116Smarcel/* 2240116Smarcel * Automated Testing Framework (atf) 3240116Smarcel * 4240116Smarcel * Copyright (c) 2008 The NetBSD Foundation, Inc. 5240116Smarcel * All rights reserved. 6240116Smarcel * 7240116Smarcel * Redistribution and use in source and binary forms, with or without 8240116Smarcel * modification, are permitted provided that the following conditions 9240116Smarcel * are met: 10240116Smarcel * 1. Redistributions of source code must retain the above copyright 11240116Smarcel * notice, this list of conditions and the following disclaimer. 12240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13240116Smarcel * notice, this list of conditions and the following disclaimer in the 14240116Smarcel * documentation and/or other materials provided with the distribution. 15240116Smarcel * 16240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27240116Smarcel * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28240116Smarcel */ 29240116Smarcel 30240116Smarcel#include <errno.h> 31240116Smarcel#include <stdarg.h> 32240116Smarcel#include <stdint.h> 33240116Smarcel#include <stdio.h> 34240116Smarcel#include <stdlib.h> 35240116Smarcel#include <string.h> 36240116Smarcel 37240116Smarcel#include "atf-c/error.h" 38240116Smarcel 39240116Smarcel#include "dynstr.h" 40240116Smarcel#include "sanity.h" 41240116Smarcel#include "text.h" 42240116Smarcel 43240116Smarcel/* --------------------------------------------------------------------- 44240116Smarcel * Auxiliary functions. 45240116Smarcel * --------------------------------------------------------------------- */ 46240116Smarcel 47240116Smarcelstatic 48240116Smarcelatf_error_t 49240116Smarcelresize(atf_dynstr_t *ad, size_t newsize) 50240116Smarcel{ 51240116Smarcel char *newdata; 52240116Smarcel atf_error_t err; 53240116Smarcel 54240116Smarcel PRE(newsize > ad->m_datasize); 55240116Smarcel 56240116Smarcel newdata = (char *)malloc(newsize); 57240116Smarcel if (newdata == NULL) { 58240116Smarcel err = atf_no_memory_error(); 59240116Smarcel } else { 60240116Smarcel strcpy(newdata, ad->m_data); 61240116Smarcel free(ad->m_data); 62240116Smarcel ad->m_data = newdata; 63240116Smarcel ad->m_datasize = newsize; 64240116Smarcel err = atf_no_error(); 65240116Smarcel } 66240116Smarcel 67240116Smarcel return err; 68240116Smarcel} 69240116Smarcel 70240116Smarcelstatic 71240116Smarcelatf_error_t 72240116Smarcelprepend_or_append(atf_dynstr_t *ad, const char *fmt, va_list ap, 73240116Smarcel bool prepend) 74240116Smarcel{ 75240116Smarcel char *aux; 76240116Smarcel atf_error_t err; 77240116Smarcel size_t newlen; 78240116Smarcel va_list ap2; 79240116Smarcel 80240116Smarcel va_copy(ap2, ap); 81240116Smarcel err = atf_text_format_ap(&aux, fmt, ap2); 82240116Smarcel va_end(ap2); 83240116Smarcel if (atf_is_error(err)) 84240116Smarcel goto out; 85240116Smarcel newlen = ad->m_length + strlen(aux); 86240116Smarcel 87240116Smarcel if (newlen + sizeof(char) > ad->m_datasize) { 88240116Smarcel err = resize(ad, newlen + sizeof(char)); 89240116Smarcel if (atf_is_error(err)) 90240116Smarcel goto out_free; 91240116Smarcel } 92240116Smarcel 93240116Smarcel if (prepend) { 94240116Smarcel memmove(ad->m_data + strlen(aux), ad->m_data, ad->m_length + 1); 95240116Smarcel memcpy(ad->m_data, aux, strlen(aux)); 96240116Smarcel } else 97240116Smarcel strcpy(ad->m_data + ad->m_length, aux); 98240116Smarcel ad->m_length = newlen; 99240116Smarcel err = atf_no_error(); 100240116Smarcel 101240116Smarcelout_free: 102240116Smarcel free(aux); 103240116Smarcelout: 104240116Smarcel return err; 105240116Smarcel} 106240116Smarcel 107240116Smarcel/* --------------------------------------------------------------------- 108240116Smarcel * The "atf_dynstr" type. 109240116Smarcel * --------------------------------------------------------------------- */ 110240116Smarcel 111240116Smarcel/* 112240116Smarcel * Constants. 113240116Smarcel */ 114240116Smarcel 115240116Smarcelconst size_t atf_dynstr_npos = SIZE_MAX; 116240116Smarcel 117240116Smarcel/* 118240116Smarcel * Constructors and destructors. 119240116Smarcel */ 120240116Smarcel 121240116Smarcelatf_error_t 122240116Smarcelatf_dynstr_init(atf_dynstr_t *ad) 123240116Smarcel{ 124240116Smarcel atf_error_t err; 125240116Smarcel 126240116Smarcel ad->m_data = (char *)malloc(sizeof(char)); 127240116Smarcel if (ad->m_data == NULL) { 128240116Smarcel err = atf_no_memory_error(); 129240116Smarcel goto out; 130240116Smarcel } 131240116Smarcel 132240116Smarcel ad->m_data[0] = '\0'; 133240116Smarcel ad->m_datasize = 1; 134240116Smarcel ad->m_length = 0; 135240116Smarcel err = atf_no_error(); 136240116Smarcel 137240116Smarcelout: 138240116Smarcel return err; 139240116Smarcel} 140240116Smarcel 141240116Smarcelatf_error_t 142240116Smarcelatf_dynstr_init_ap(atf_dynstr_t *ad, const char *fmt, va_list ap) 143240116Smarcel{ 144240116Smarcel atf_error_t err; 145240116Smarcel 146240116Smarcel ad->m_datasize = strlen(fmt) + 1; 147240116Smarcel ad->m_length = 0; 148240116Smarcel 149240116Smarcel do { 150240116Smarcel va_list ap2; 151240116Smarcel int ret; 152240116Smarcel 153240116Smarcel ad->m_datasize *= 2; 154240116Smarcel ad->m_data = (char *)malloc(ad->m_datasize); 155240116Smarcel if (ad->m_data == NULL) { 156240116Smarcel err = atf_no_memory_error(); 157240116Smarcel goto out; 158240116Smarcel } 159240116Smarcel 160240116Smarcel va_copy(ap2, ap); 161240116Smarcel ret = vsnprintf(ad->m_data, ad->m_datasize, fmt, ap2); 162240116Smarcel va_end(ap2); 163240116Smarcel if (ret < 0) { 164240116Smarcel free(ad->m_data); 165240116Smarcel err = atf_libc_error(errno, "Cannot format string"); 166240116Smarcel goto out; 167240116Smarcel } 168240116Smarcel 169240116Smarcel INV(ret >= 0); 170240116Smarcel if ((size_t)ret >= ad->m_datasize) { 171240116Smarcel free(ad->m_data); 172240116Smarcel ad->m_data = NULL; 173240116Smarcel } 174240116Smarcel ad->m_length = ret; 175240116Smarcel } while (ad->m_length >= ad->m_datasize); 176240116Smarcel 177240116Smarcel err = atf_no_error(); 178240116Smarcelout: 179240116Smarcel POST(atf_is_error(err) || ad->m_data != NULL); 180240116Smarcel return err; 181240116Smarcel} 182240116Smarcel 183240116Smarcelatf_error_t 184240116Smarcelatf_dynstr_init_fmt(atf_dynstr_t *ad, const char *fmt, ...) 185240116Smarcel{ 186240116Smarcel va_list ap; 187240116Smarcel atf_error_t err; 188240116Smarcel 189240116Smarcel va_start(ap, fmt); 190240116Smarcel err = atf_dynstr_init_ap(ad, fmt, ap); 191240116Smarcel va_end(ap); 192240116Smarcel 193240116Smarcel return err; 194240116Smarcel} 195240116Smarcel 196240116Smarcelatf_error_t 197240116Smarcelatf_dynstr_init_raw(atf_dynstr_t *ad, const void *mem, size_t memlen) 198240116Smarcel{ 199240116Smarcel atf_error_t err; 200240116Smarcel 201240116Smarcel if (memlen >= SIZE_MAX - 1) { 202240116Smarcel err = atf_no_memory_error(); 203240116Smarcel goto out; 204240116Smarcel } 205240116Smarcel 206240116Smarcel ad->m_data = (char *)malloc(memlen + 1); 207240116Smarcel if (ad->m_data == NULL) { 208240116Smarcel err = atf_no_memory_error(); 209240116Smarcel goto out; 210240116Smarcel } 211240116Smarcel 212240116Smarcel ad->m_datasize = memlen + 1; 213240116Smarcel memcpy(ad->m_data, mem, memlen); 214240116Smarcel ad->m_data[memlen] = '\0'; 215240116Smarcel ad->m_length = strlen(ad->m_data); 216240116Smarcel INV(ad->m_length <= memlen); 217240116Smarcel err = atf_no_error(); 218240116Smarcel 219240116Smarcelout: 220240116Smarcel return err; 221240116Smarcel} 222240116Smarcel 223240116Smarcelatf_error_t 224240116Smarcelatf_dynstr_init_rep(atf_dynstr_t *ad, size_t len, char ch) 225240116Smarcel{ 226240116Smarcel atf_error_t err; 227240116Smarcel 228240116Smarcel if (len == SIZE_MAX) { 229240116Smarcel err = atf_no_memory_error(); 230240116Smarcel goto out; 231240116Smarcel } 232240116Smarcel 233240116Smarcel ad->m_datasize = (len + 1) * sizeof(char); 234240116Smarcel ad->m_data = (char *)malloc(ad->m_datasize); 235240116Smarcel if (ad->m_data == NULL) { 236240116Smarcel err = atf_no_memory_error(); 237240116Smarcel goto out; 238240116Smarcel } 239240116Smarcel 240240116Smarcel memset(ad->m_data, ch, len); 241240116Smarcel ad->m_data[len] = '\0'; 242240116Smarcel ad->m_length = len; 243240116Smarcel err = atf_no_error(); 244240116Smarcel 245240116Smarcelout: 246240116Smarcel return err; 247240116Smarcel} 248240116Smarcel 249240116Smarcelatf_error_t 250240116Smarcelatf_dynstr_init_substr(atf_dynstr_t *ad, const atf_dynstr_t *src, 251240116Smarcel size_t beg, size_t end) 252240116Smarcel{ 253240116Smarcel if (beg > src->m_length) 254240116Smarcel beg = src->m_length; 255240116Smarcel 256240116Smarcel if (end == atf_dynstr_npos || end > src->m_length) 257240116Smarcel end = src->m_length; 258240116Smarcel 259240116Smarcel return atf_dynstr_init_raw(ad, src->m_data + beg, end - beg); 260240116Smarcel} 261240116Smarcel 262240116Smarcelatf_error_t 263240116Smarcelatf_dynstr_copy(atf_dynstr_t *dest, const atf_dynstr_t *src) 264240116Smarcel{ 265240116Smarcel atf_error_t err; 266240116Smarcel 267240116Smarcel dest->m_data = (char *)malloc(src->m_datasize); 268240116Smarcel if (dest->m_data == NULL) 269240116Smarcel err = atf_no_memory_error(); 270240116Smarcel else { 271240116Smarcel memcpy(dest->m_data, src->m_data, src->m_datasize); 272240116Smarcel dest->m_datasize = src->m_datasize; 273240116Smarcel dest->m_length = src->m_length; 274240116Smarcel err = atf_no_error(); 275240116Smarcel } 276240116Smarcel 277240116Smarcel return err; 278240116Smarcel} 279240116Smarcel 280240116Smarcelvoid 281240116Smarcelatf_dynstr_fini(atf_dynstr_t *ad) 282240116Smarcel{ 283240116Smarcel INV(ad->m_data != NULL); 284240116Smarcel free(ad->m_data); 285240116Smarcel} 286240116Smarcel 287240116Smarcelchar * 288240116Smarcelatf_dynstr_fini_disown(atf_dynstr_t *ad) 289240116Smarcel{ 290240116Smarcel INV(ad->m_data != NULL); 291240116Smarcel return ad->m_data; 292240116Smarcel} 293240116Smarcel 294240116Smarcel/* 295240116Smarcel * Getters. 296240116Smarcel */ 297240116Smarcel 298240116Smarcelconst char * 299240116Smarcelatf_dynstr_cstring(const atf_dynstr_t *ad) 300240116Smarcel{ 301240116Smarcel return ad->m_data; 302240116Smarcel} 303240116Smarcel 304240116Smarcelsize_t 305240116Smarcelatf_dynstr_length(const atf_dynstr_t *ad) 306240116Smarcel{ 307240116Smarcel return ad->m_length; 308240116Smarcel} 309240116Smarcel 310240116Smarcelsize_t 311240116Smarcelatf_dynstr_rfind_ch(const atf_dynstr_t *ad, char ch) 312240116Smarcel{ 313240116Smarcel size_t pos; 314240116Smarcel 315240116Smarcel for (pos = ad->m_length; pos > 0 && ad->m_data[pos - 1] != ch; pos--) 316240116Smarcel ; 317240116Smarcel 318240116Smarcel return pos == 0 ? atf_dynstr_npos : pos - 1; 319240116Smarcel} 320240116Smarcel 321240116Smarcel/* 322240116Smarcel * Modifiers. 323240116Smarcel */ 324240116Smarcel 325240116Smarcelatf_error_t 326240116Smarcelatf_dynstr_append_ap(atf_dynstr_t *ad, const char *fmt, va_list ap) 327240116Smarcel{ 328240116Smarcel atf_error_t err; 329240116Smarcel va_list ap2; 330240116Smarcel 331240116Smarcel va_copy(ap2, ap); 332240116Smarcel err = prepend_or_append(ad, fmt, ap2, false); 333240116Smarcel va_end(ap2); 334240116Smarcel 335240116Smarcel return err; 336240116Smarcel} 337240116Smarcel 338240116Smarcelatf_error_t 339240116Smarcelatf_dynstr_append_fmt(atf_dynstr_t *ad, const char *fmt, ...) 340240116Smarcel{ 341240116Smarcel va_list ap; 342240116Smarcel atf_error_t err; 343240116Smarcel 344240116Smarcel va_start(ap, fmt); 345240116Smarcel err = prepend_or_append(ad, fmt, ap, false); 346240116Smarcel va_end(ap); 347240116Smarcel 348240116Smarcel return err; 349240116Smarcel} 350240116Smarcel 351240116Smarcelvoid 352240116Smarcelatf_dynstr_clear(atf_dynstr_t *ad) 353240116Smarcel{ 354240116Smarcel ad->m_data[0] = '\0'; 355240116Smarcel ad->m_length = 0; 356240116Smarcel} 357240116Smarcel 358240116Smarcelatf_error_t 359240116Smarcelatf_dynstr_prepend_ap(atf_dynstr_t *ad, const char *fmt, va_list ap) 360240116Smarcel{ 361240116Smarcel atf_error_t err; 362240116Smarcel va_list ap2; 363240116Smarcel 364240116Smarcel va_copy(ap2, ap); 365240116Smarcel err = prepend_or_append(ad, fmt, ap2, true); 366240116Smarcel va_end(ap2); 367240116Smarcel 368240116Smarcel return err; 369240116Smarcel} 370240116Smarcel 371240116Smarcelatf_error_t 372240116Smarcelatf_dynstr_prepend_fmt(atf_dynstr_t *ad, const char *fmt, ...) 373240116Smarcel{ 374240116Smarcel va_list ap; 375240116Smarcel atf_error_t err; 376240116Smarcel 377240116Smarcel va_start(ap, fmt); 378240116Smarcel err = prepend_or_append(ad, fmt, ap, true); 379240116Smarcel va_end(ap); 380240116Smarcel 381240116Smarcel return err; 382240116Smarcel} 383240116Smarcel 384240116Smarcel/* 385240116Smarcel * Operators. 386240116Smarcel */ 387240116Smarcel 388240116Smarcelbool 389240116Smarcelatf_equal_dynstr_cstring(const atf_dynstr_t *ad, const char *str) 390240116Smarcel{ 391240116Smarcel return strcmp(ad->m_data, str) == 0; 392240116Smarcel} 393240116Smarcel 394240116Smarcelbool 395240116Smarcelatf_equal_dynstr_dynstr(const atf_dynstr_t *s1, const atf_dynstr_t *s2) 396240116Smarcel{ 397240116Smarcel return strcmp(s1->m_data, s2->m_data) == 0; 398240116Smarcel} 399