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 43 static 44 atf_error_t 45 resize(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 66 static 67 atf_error_t 68 prepend_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 97 out_free: 98 free(aux); 99 out: 100 return err; 101 } 102 103 /* --------------------------------------------------------------------- 104 * The "atf_dynstr" type. 105 * --------------------------------------------------------------------- */ 106 107 /* 108 * Constants. 109 */ 110 111 const size_t atf_dynstr_npos = SIZE_MAX; 112 113 /* 114 * Constructors and destructors. 115 */ 116 117 atf_error_t 118 atf_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 133 out: 134 return err; 135 } 136 137 atf_error_t 138 atf_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(); 174 out: 175 POST(atf_is_error(err) || ad->m_data != NULL); 176 return err; 177 } 178 179 atf_error_t 180 atf_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 192 atf_error_t 193 atf_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 215 out: 216 return err; 217 } 218 219 atf_error_t 220 atf_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 241 out: 242 return err; 243 } 244 245 atf_error_t 246 atf_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 258 atf_error_t 259 atf_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 276 void 277 atf_dynstr_fini(atf_dynstr_t *ad) 278 { 279 INV(ad->m_data != NULL); 280 free(ad->m_data); 281 } 282 283 char * 284 atf_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 294 const char * 295 atf_dynstr_cstring(const atf_dynstr_t *ad) 296 { 297 return ad->m_data; 298 } 299 300 size_t 301 atf_dynstr_length(const atf_dynstr_t *ad) 302 { 303 return ad->m_length; 304 } 305 306 size_t 307 atf_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 321 atf_error_t 322 atf_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 334 atf_error_t 335 atf_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 347 void 348 atf_dynstr_clear(atf_dynstr_t *ad) 349 { 350 ad->m_data[0] = '\0'; 351 ad->m_length = 0; 352 } 353 354 atf_error_t 355 atf_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 367 atf_error_t 368 atf_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 384 bool 385 atf_equal_dynstr_cstring(const atf_dynstr_t *ad, const char *str) 386 { 387 return strcmp(ad->m_data, str) == 0; 388 } 389 390 bool 391 atf_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