/* * 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 #include #ifndef CX_PRINTF_SBO_SIZE #define CX_PRINTF_SBO_SIZE 512 #endif int cx_fprintf( void *stream, cx_write_func wfc, char const *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, char const *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) { return ret; } else if (ret < CX_PRINTF_SBO_SIZE) { return (int) wfc(buf, 1, ret, stream); } else { int len = ret + 1; char *newbuf = malloc(len); if (!newbuf) { return -1; } ret = vsnprintf(newbuf, len, fmt, ap2); if (ret > 0) { ret = (int) wfc(newbuf, 1, ret, stream); } free(newbuf); } return ret; } cxmutstr cx_asprintf_a( CxAllocator const *allocator, char const *fmt, ... ) { va_list ap; cxmutstr ret; va_start(ap, fmt); ret = cx_vasprintf_a(allocator, fmt, ap); va_end(ap); return ret; } cxmutstr cx_vasprintf_a( CxAllocator const *a, char const *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; } } } return s; }