Sun, 11 Feb 2024 22:06:23 +0100
initial newapi GTK port
174 | 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 | |
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
37 | unsigned const cx_printf_sbo_size = CX_PRINTF_SBO_SIZE; |
174 | 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) { | |
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
64 | va_end(ap2); |
174 | 65 | return ret; |
66 | } else if (ret < CX_PRINTF_SBO_SIZE) { | |
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
67 | va_end(ap2); |
174 | 68 | return (int) wfc(buf, 1, ret, stream); |
69 | } else { | |
70 | int len = ret + 1; | |
71 | char *newbuf = malloc(len); | |
72 | if (!newbuf) { | |
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
73 | va_end(ap2); |
174 | 74 | return -1; |
75 | } | |
76 | ||
77 | ret = vsnprintf(newbuf, len, fmt, ap2); | |
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
78 | va_end(ap2); |
174 | 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); | |
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
94 | cxmutstr ret = cx_vasprintf_a(allocator, fmt, ap); |
174 | 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); | |
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
111 | if (ret >= 0 && ret < CX_PRINTF_SBO_SIZE) { |
174 | 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 | } | |
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
131 | va_end(ap2); |
174 | 132 | return s; |
133 | } | |
134 | ||
253
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
135 | int cx_sprintf_a(CxAllocator *alloc, char **str, size_t len, const char *fmt, ... ) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
136 | va_list ap; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
137 | va_start(ap, fmt); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
138 | int ret = cx_vsprintf_a(alloc, str, len, fmt, ap); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
139 | va_end(ap); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
140 | return ret; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
141 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
142 | |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
143 | int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t len, const char *fmt, va_list ap) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
144 | va_list ap2; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
145 | va_copy(ap2, ap); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
146 | int ret = vsnprintf(*str, len, fmt, ap); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
147 | if ((unsigned) ret >= len) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
148 | unsigned newlen = ret + 1; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
149 | char *ptr = cxRealloc(alloc, *str, newlen); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
150 | if (ptr) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
151 | int newret = vsnprintf(ptr, newlen, fmt, ap2); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
152 | if (newret < 0) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
153 | cxFree(alloc, ptr); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
154 | } else { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
155 | *str = ptr; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
156 | ret = newret; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
157 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
158 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
159 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
160 | va_end(ap2); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
161 | return ret; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
162 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
163 | |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
164 | int cx_sprintf_sa(CxAllocator *alloc, char *buf, size_t len, char **str, const char *fmt, ... ) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
165 | va_list ap; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
166 | va_start(ap, fmt); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
167 | int ret = cx_vsprintf_sa(alloc, buf, len, str, fmt, ap); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
168 | va_end(ap); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
169 | return ret; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
170 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
171 | |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
172 | int cx_vsprintf_sa(CxAllocator *alloc, char *buf, size_t len, char **str, const char *fmt, va_list ap) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
173 | va_list ap2; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
174 | va_copy(ap2, ap); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
175 | int ret = vsnprintf(buf, len, fmt, ap); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
176 | *str = buf; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
177 | if ((unsigned) ret >= len) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
178 | unsigned newlen = ret + 1; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
179 | char *ptr = cxMalloc(alloc, newlen); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
180 | if (ptr) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
181 | int newret = vsnprintf(ptr, newlen, fmt, ap2); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
182 | if (newret < 0) { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
183 | cxFree(alloc, ptr); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
184 | } else { |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
185 | *str = ptr; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
186 | ret = newret; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
187 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
188 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
189 | } |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
190 | va_end(ap2); |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
191 | return ret; |
087cc9216f28
initial newapi GTK port
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
174
diff
changeset
|
192 | } |