UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "cx/printf.h" 30 31 #include <stdio.h> 32 #include <string.h> 33 34 #ifndef CX_PRINTF_SBO_SIZE 35 #define CX_PRINTF_SBO_SIZE 512 36 #endif 37 unsigned const cx_printf_sbo_size = CX_PRINTF_SBO_SIZE; 38 39 int cx_fprintf( 40 void *stream, 41 cx_write_func wfc, 42 char const *fmt, 43 ... 44 ) { 45 int ret; 46 va_list ap; 47 va_start(ap, fmt); 48 ret = cx_vfprintf(stream, wfc, fmt, ap); 49 va_end(ap); 50 return ret; 51 } 52 53 int cx_vfprintf( 54 void *stream, 55 cx_write_func wfc, 56 char const *fmt, 57 va_list ap 58 ) { 59 char buf[CX_PRINTF_SBO_SIZE]; 60 va_list ap2; 61 va_copy(ap2, ap); 62 int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap); 63 if (ret < 0) { 64 va_end(ap2); 65 return ret; 66 } else if (ret < CX_PRINTF_SBO_SIZE) { 67 va_end(ap2); 68 return (int) wfc(buf, 1, ret, stream); 69 } else { 70 int len = ret + 1; 71 char *newbuf = malloc(len); 72 if (!newbuf) { 73 va_end(ap2); 74 return -1; 75 } 76 77 ret = vsnprintf(newbuf, len, fmt, ap2); 78 va_end(ap2); 79 if (ret > 0) { 80 ret = (int) wfc(newbuf, 1, ret, stream); 81 } 82 free(newbuf); 83 } 84 return ret; 85 } 86 87 cxmutstr cx_asprintf_a( 88 CxAllocator const *allocator, 89 char const *fmt, 90 ... 91 ) { 92 va_list ap; 93 va_start(ap, fmt); 94 cxmutstr ret = cx_vasprintf_a(allocator, fmt, ap); 95 va_end(ap); 96 return ret; 97 } 98 99 cxmutstr cx_vasprintf_a( 100 CxAllocator const *a, 101 char const *fmt, 102 va_list ap 103 ) { 104 cxmutstr s; 105 s.ptr = NULL; 106 s.length = 0; 107 char buf[CX_PRINTF_SBO_SIZE]; 108 va_list ap2; 109 va_copy(ap2, ap); 110 int ret = vsnprintf(buf, CX_PRINTF_SBO_SIZE, fmt, ap); 111 if (ret >= 0 && ret < CX_PRINTF_SBO_SIZE) { 112 s.ptr = cxMalloc(a, ret + 1); 113 if (s.ptr) { 114 s.length = (size_t) ret; 115 memcpy(s.ptr, buf, ret); 116 s.ptr[s.length] = '\0'; 117 } 118 } else { 119 int len = ret + 1; 120 s.ptr = cxMalloc(a, len); 121 if (s.ptr) { 122 ret = vsnprintf(s.ptr, len, fmt, ap2); 123 if (ret < 0) { 124 free(s.ptr); 125 s.ptr = NULL; 126 } else { 127 s.length = (size_t) ret; 128 } 129 } 130 } 131 va_end(ap2); 132 return s; 133 } 134 135 int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, ... ) { 136 va_list ap; 137 va_start(ap, fmt); 138 int ret = cx_vsprintf_a(alloc, str, len, fmt, ap); 139 va_end(ap); 140 return ret; 141 } 142 143 int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap) { 144 va_list ap2; 145 va_copy(ap2, ap); 146 int ret = vsnprintf(*str, *len, fmt, ap); 147 if ((unsigned) ret >= *len) { 148 unsigned newlen = ret + 1; 149 char *ptr = cxRealloc(alloc, *str, newlen); 150 if (ptr) { 151 int newret = vsnprintf(ptr, newlen, fmt, ap2); 152 if (newret < 0) { 153 cxFree(alloc, ptr); 154 } else { 155 *len = newlen; 156 *str = ptr; 157 ret = newret; 158 } 159 } 160 } 161 va_end(ap2); 162 return ret; 163 } 164 165 int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ... ) { 166 va_list ap; 167 va_start(ap, fmt); 168 int ret = cx_vsprintf_sa(alloc, buf, len, str, fmt, ap); 169 va_end(ap); 170 return ret; 171 } 172 173 int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap) { 174 va_list ap2; 175 va_copy(ap2, ap); 176 int ret = vsnprintf(buf, *len, fmt, ap); 177 *str = buf; 178 if ((unsigned) ret >= *len) { 179 unsigned newlen = ret + 1; 180 char *ptr = cxMalloc(alloc, newlen); 181 if (ptr) { 182 int newret = vsnprintf(ptr, newlen, fmt, ap2); 183 if (newret < 0) { 184 cxFree(alloc, ptr); 185 } else { 186 *len = newlen; 187 *str = ptr; 188 ret = newret; 189 } 190 } 191 } 192 va_end(ap2); 193 return ret; 194 } 195