| 339 | #define INIT_SZ 128 |
| 340 | |
| 341 | int vasprintf(char** str, const char* fmt, va_list ap) |
| 342 | { |
| 343 | int ret; |
| 344 | va_list ap2; |
| 345 | char *string, *newstr; |
| 346 | size_t len; |
| 347 | |
| 348 | if ((string = malloc(INIT_SZ)) == NULL) |
| 349 | goto fail; |
| 350 | |
| 351 | VA_COPY(ap2, ap); |
| 352 | ret = vsnprintf(string, INIT_SZ, fmt, ap2); |
| 353 | va_end(ap2); |
| 354 | if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */ |
| 355 | *str = string; |
| 356 | } else if (ret == INT_MAX || ret < 0) { /* Bad length */ |
| 357 | free(string); |
| 358 | goto fail; |
| 359 | } else { /* bigger than initial, realloc allowing for nul */ |
| 360 | len = (size_t)ret + 1; |
| 361 | if ((newstr = realloc(string, len)) == NULL) { |
| 362 | free(string); |
| 363 | goto fail; |
| 364 | } |
| 365 | VA_COPY(ap2, ap); |
| 366 | ret = vsnprintf(newstr, len, fmt, ap2); |
| 367 | va_end(ap2); |
| 368 | if (ret < 0 || (size_t)ret >= len) { /* failed with realloc'ed string */ |
| 369 | free(newstr); |
| 370 | goto fail; |
| 371 | } |
| 372 | *str = newstr; |
| 373 | } |
| 374 | return (ret); |
| 375 | |
| 376 | fail: |
| 377 | *str = NULL; |
| 378 | errno = ENOMEM; |
| 379 | return (-1); |
| 380 | } |
| 381 | |
| 382 | int _asprintf(char** str, const char* fmt, ...) |
| 383 | { |