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