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