Fri, 20 Dec 2024 13:13:38 +0100
add advice to set the size of a buffer initialized with existing data
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "cx/printf.h" #include <stdio.h> #include <string.h> #ifndef CX_PRINTF_SBO_SIZE #define CX_PRINTF_SBO_SIZE 512 #endif const unsigned cx_printf_sbo_size = CX_PRINTF_SBO_SIZE; int cx_fprintf( void *stream, cx_write_func wfc, const char *fmt, ... ) { int ret; va_list ap; va_start(ap, fmt); ret = cx_vfprintf(stream, wfc, fmt, ap); va_end(ap); return ret; } int cx_vfprintf( void *stream, cx_write_func wfc, const char *fmt, va_list ap ) { char buf[CX_PRINTF_SBO_SIZE]; va_list ap2; va_copy(ap2, ap); int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap); if (ret < 0) { va_end(ap2); return ret; } else if (ret < CX_PRINTF_SBO_SIZE) { va_end(ap2); return (int) wfc(buf, 1, ret, stream); } else { int len = ret + 1; char *newbuf = malloc(len); if (!newbuf) { va_end(ap2); return -1; } ret = vsnprintf(newbuf, len, fmt, ap2); va_end(ap2); if (ret > 0) { ret = (int) wfc(newbuf, 1, ret, stream); } free(newbuf); } return ret; } cxmutstr cx_asprintf_a( const CxAllocator *allocator, const char *fmt, ... ) { va_list ap; va_start(ap, fmt); cxmutstr ret = cx_vasprintf_a(allocator, fmt, ap); va_end(ap); return ret; } cxmutstr cx_vasprintf_a( const CxAllocator *a, const char *fmt, va_list ap ) { cxmutstr s; s.ptr = NULL; s.length = 0; char buf[CX_PRINTF_SBO_SIZE]; va_list ap2; va_copy(ap2, ap); int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap); if (ret >= 0 && ret < CX_PRINTF_SBO_SIZE) { s.ptr = cxMalloc(a, ret + 1); if (s.ptr) { s.length = (size_t) ret; memcpy(s.ptr, buf, ret); s.ptr[s.length] = '\0'; } } else { int len = ret + 1; s.ptr = cxMalloc(a, len); if (s.ptr) { ret = vsnprintf(s.ptr, len, fmt, ap2); if (ret < 0) { free(s.ptr); s.ptr = NULL; } else { s.length = (size_t) ret; } } } va_end(ap2); return s; } int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, ... ) { va_list ap; va_start(ap, fmt); int ret = cx_vsprintf_a(alloc, str, len, fmt, ap); va_end(ap); return ret; } int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap) { va_list ap2; va_copy(ap2, ap); int ret = vsnprintf(*str, *len, fmt, ap); if ((unsigned) ret >= *len) { unsigned newlen = ret + 1; char *ptr = cxRealloc(alloc, *str, newlen); if (ptr) { int newret = vsnprintf(ptr, newlen, fmt, ap2); if (newret < 0) { cxFree(alloc, ptr); } else { *len = newlen; *str = ptr; ret = newret; } } } va_end(ap2); return ret; } int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ... ) { va_list ap; va_start(ap, fmt); int ret = cx_vsprintf_sa(alloc, buf, len, str, fmt, ap); va_end(ap); return ret; } int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap) { va_list ap2; va_copy(ap2, ap); int ret = vsnprintf(buf, *len, fmt, ap); *str = buf; if ((unsigned) ret >= *len) { unsigned newlen = ret + 1; char *ptr = cxMalloc(alloc, newlen); if (ptr) { int newret = vsnprintf(ptr, newlen, fmt, ap2); if (newret < 0) { cxFree(alloc, ptr); } else { *len = newlen; *str = ptr; ret = newret; } } } va_end(ap2); return ret; }