1 /*
2 * snprintf() / vsnprintf() re-implementation by Frank Denis <j@pureftpd.org>
3 *
4 * These functions understand :
5 * - characters ("%c") .
6 * - space padding ("%3d", "%-3s") .
7 * - zero padding ("%04d") .
8 * - explicit '+' ("%+d", "%+3.2f") .
9 * - length restrictions ("%.30s", "%-42.30s", "%.4d") .
10 * - int, long, long long types ("%lld", "%-3ld", "%i") .
11 * - unsigned int, long, long long types ("%llu", "%-3lu", "%u") .
12 * - hex and octal unsigned types ("%llX", "%04x", "%-3o") .
13 * - double and long double types ("%f", "%Lf") .
14 * - floating point frac restrictions ("%.2f") .
15 * - combinations of everything ("%-8.5llo") .
16 *
17 * Nothing more. Return value is <size> if an overflow occured, or the
18 * copied size if no overflow occured (mostly compatible with C99
19 * snprintf() behavior, except that it doesn't return any value larger
20 * than <size>).
21 *
22 * These functions are portable, they are twice faster than their BSD and GNU
23 * implementations, and they don't tamper with errno. But they only know
24 * a limited subset of what a full-implementation is supposed to do.
25 *
26 * It's enough for Blogbench, though.
27 */
28
29 #include <config.h>
30
31 #include "blogbench.h"
32
33 #ifdef WITH_DMALLOC
34 # include <dmalloc.h>
wolfCrypt_PIE_last_function(void)35 #endif
36
37 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
38
39 /*
40 * add a string to the buffer
41 * \param zero if this is non-zero, we pad with zeroes, else we pad
42 * with a blank.
43 * \param maxlen sets the maximum size of the string to be added
44 */
45
46 static void fakesnprintf_addstr(char **str, size_t *size, const char *pnt,
47 size_t maxlen, size_t padlen,
48 unsigned char zero, unsigned char minuspad)
49 {
50 size_t maxlenc;
51
52 /* prepare to cut off string if longer than maxlen */
53 maxlenc = strlen(pnt);
54 if (maxlen > 0U && maxlen < maxlenc) {
55 maxlenc = maxlen;
56 }
57 if (padlen > 0U && minuspad == 0U && padlen > maxlenc) {
58 size_t maxlenp = padlen - maxlenc;
59
60 if (maxlenp > *size) {
61 maxlenp = *size;
62 }
63 if (maxlenp > 0U) {
64 memset(*str, zero != 0 ? '0' : ' ', maxlenp);
65 (*size) -= maxlenp;
66 (*str) += maxlenp;
67 }
68 }
69 if (maxlenc > *size) {
70 maxlenc = *size;
71 }
72 if (maxlenc > 0U) {
73 memcpy(*str, pnt, maxlenc);
74 (*size) -= maxlenc;
75 (*str) += maxlenc;
76 }
77 if (padlen > 0U && minuspad > 0U && padlen > maxlenc) {
78 size_t maxlenp = padlen - maxlenc;
79
80 if (maxlenp > *size) {
81 maxlenp = *size;
82 }
83 if (maxlenp > 0U) {
84 memset(*str, ' ', maxlenp);
85 (*size) -= maxlenp;
86 (*str) += maxlenp;
87 }
88 }
89 }
90
91 int fakesnprintf_vsnprintf(char * const str_, const size_t size_,
92 const char *format, va_list va)
93 {
94 char *str;
95 size_t size;
96 size_t maxlen;
97 size_t padlen;
98 unsigned char longs;
99 unsigned char zero;
100 unsigned char minuspad;
101 unsigned char hasmaxlen;
102 unsigned char plussign;
103
104 str = str_;
105 size = size_;
106 str_[size_ - 1U] = 1;
107 while (size > 0U && *format != 0) {
108 if (*format != '%') {
109 *str++ = *format++;
110 size--;
111 continue;
112 }
113 longs = 0U;
114 zero = 0U;
115 minuspad = 0U;
116 maxlen = 0U;
117 padlen = 0U;
118 hasmaxlen = 0U;
119 plussign = 0U;
120
121 for (;;) {
122 breakpoint_nextspecial_inc:
123 format++;
124 breakpoint_nextspecial_noinc:
125 switch (*format) {
126 case 0:
127 goto breakpoint_end;
128 case '%':
129 *str++ = '%';
130 size--;
131 goto breakpoint_nextspecial_inc;
132 case 'c': {
133 int val;
134
135 val = va_arg(va, int);
136 *str++ = (char) val;
137 size--;
138 goto breakpoint_nextspecial_inc;
139 }
140 case 'l': case 'L':
141 longs++;
142 goto breakpoint_nextspecial_inc;
143 case '0':
144 zero++;
145 goto breakpoint_nextspecial_inc;
146 case '.':
147 format++;
148 hasmaxlen = 1U;
149 while ((unsigned char) *format >= '0' &&
150 (unsigned char) *format <= '9') {
151 maxlen *= 10U;
152 maxlen += (*format - '0');
153 format++;
154 }
155 goto breakpoint_nextspecial_noinc;
156 case '1': case '2': case '3': case '4': case '5':
157 case '6': case '7': case '8': case '9':
158 do {
159 padlen *= 10U;
160 padlen += *format - '0';
161 format++;
162 } while ((unsigned char) *format >= '0' &&
163 (unsigned char) *format <= '9');
164 goto breakpoint_nextspecial_noinc;
165 case '-':
166 minuspad++;
167 format++;
168 goto breakpoint_nextspecial_noinc;
169 case '+':
170 plussign++;
171 format++;
172 goto breakpoint_nextspecial_noinc;
173 case 's': {
174 const char *pnt;
175
176 pnt = va_arg(va, const char *);
177 if (pnt == NULL) {
178 pnt = "<NULL>";
179 }
180 fakesnprintf_addstr(&str, &size, pnt, maxlen, padlen,
181 zero, minuspad);
182 goto breakpoint_next;
183 }
184 case 'u': case 'o': case 'x': case 'X': {
185 unsigned long long val;
186 char vals[256];
187 char *valspnt = vals + sizeof vals;
188 const char *basics;
189 unsigned int base;
190
191 switch (longs) {
192 case 2:
193 val = va_arg(va, unsigned long long);
194 break;
195 case 1:
196 val = (unsigned long long) va_arg(va, unsigned long);
197 break;
198 default:
199 val = (unsigned long long) va_arg(va, unsigned int);
200 }
201 basics = "0123456789abcdef";
202 switch (*format) {
203 case 'o':
204 base = 8U;
205 break;
206 case 'X':
207 basics = "0123456789ABCDEF";
208 case 'x':
209 base = 16U;
210 break;
211 default:
212 base = 10U;
213 }
214 *--valspnt = 0;
215 do {
216 *--valspnt = basics[val % base];
217 val /= base;
218 } while (valspnt != &vals[0] && val > 0ULL);
219 fakesnprintf_addstr(&str, &size, valspnt, maxlen, padlen,
220 zero, minuspad);
221 goto breakpoint_next;
222 }
223 case 'd': case 'i': {
224 long long val;
225 unsigned char minussign = 0U;
226 char vals[256];
227 char *valspnt = vals + sizeof vals;
228
229 switch (longs) {
230 case 2:
231 val = va_arg(va, long long);
232 break;
233 case 1:
234 val = (long long) va_arg(va, long);
235 break;
236 default:
237 val = (long long) va_arg(va, int);
238 }
239 if (val < 0LL) {
240 minussign++;
241 val = -val;
242 }
243 *--valspnt = 0;
244 do {
245 *--valspnt = "0123456789"[val % 10LL];
246 val /= 10LL;
247 } while (valspnt != &vals[1] && val > 0LL);
248 if (minussign != 0) {
249 *--valspnt = '-';
250 } else if (plussign != 0) {
251 *--valspnt = '+';
252 }
253 fakesnprintf_addstr(&str, &size, valspnt, maxlen, padlen,
254 zero, minuspad);
255 goto breakpoint_next;
256 }
257 case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': {
258 unsigned int nfrac = 6U;
259 long double val;
260 unsigned long long vali;
261 unsigned char minussign = 0U;
262 char vals[512];
263 char *valspnt = vals + sizeof vals / 2U;
264 char *valsleft;
265
266 if (longs != 0) {
267 val = va_arg(va, long double);
268 } else {
269 val = va_arg(va, double);
270 }
271 if (val < 0.0L) {
272 minussign++;
273 val = -val;
274 }
275 vali = (unsigned long long) val;
276 do {
277 *--valspnt = '0' + vali % 10ULL;
278 vali /= 10ULL;
279 } while (valspnt != &vals[1] && vali > 0ULL);
280 if (minussign != 0) {
281 *--valspnt = '-';
282 } else if (plussign != 0) {
283 *--valspnt = '+';
284 }
285 valsleft = valspnt;
286 valspnt = vals + sizeof vals / 2U;
287 if (maxlen > (sizeof vals / 2U) - 3U) {
288 nfrac = (sizeof vals / 2U) - 3U;
289 } else if (hasmaxlen != 0U) {
290 nfrac = maxlen;
291 }
292 if (nfrac > 0U) {
293 *valspnt++ = '.';
294 }
295 while (nfrac > 0U) {
296 nfrac--;
297 val *= 10.0L;
298 *valspnt++ = '0' + (((unsigned long long) val) % 10U);
299 }
300 *valspnt = 0;
301 fakesnprintf_addstr(&str, &size, valsleft, sizeof vals,
302 padlen, zero, minuspad);
303 goto breakpoint_next;
304 }
305 }
306 }
307 breakpoint_next:
308 format++;
309 }
310 breakpoint_end:
311 if (str_[size_ - 1U] != 1) {
312 str_[size_ - 1U] = 0;
313 return (int) size_;
314 }
315 *str = 0;
316
317 return (int) (size_ - size);
318 }
319
320 int fakesnprintf_snprintf(char * const str, const size_t size,
321 const char * const format, ...)
322 {
323 int ret;
324 va_list va;
325
326 va_start(va, format);
327 ret = fakesnprintf_vsnprintf(str, size, format, va);
328 va_end(va);
329
330 return ret;
331 }
332
333 #endif /* !HAVE_SNPRINTF */
334