]>
Commit | Line | Data |
---|---|---|
d02b48c6 | 1 | /* crypto/bio/b_print.c */ |
58964a49 | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
d02b48c6 RE |
3 | * All rights reserved. |
4 | * | |
5 | * This package is an SSL implementation written | |
6 | * by Eric Young (eay@cryptsoft.com). | |
7 | * The implementation was written so as to conform with Netscapes SSL. | |
0f113f3e | 8 | * |
d02b48c6 RE |
9 | * This library is free for commercial and non-commercial use as long as |
10 | * the following conditions are aheared to. The following conditions | |
11 | * apply to all code found in this distribution, be it the RC4, RSA, | |
12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation | |
13 | * included with this distribution is covered by the same copyright terms | |
14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | |
0f113f3e | 15 | * |
d02b48c6 RE |
16 | * Copyright remains Eric Young's, and as such any Copyright notices in |
17 | * the code are not to be removed. | |
18 | * If this package is used in a product, Eric Young should be given attribution | |
19 | * as the author of the parts of the library used. | |
20 | * This can be in the form of a textual message at program startup or | |
21 | * in documentation (online or textual) provided with the package. | |
0f113f3e | 22 | * |
d02b48c6 RE |
23 | * Redistribution and use in source and binary forms, with or without |
24 | * modification, are permitted provided that the following conditions | |
25 | * are met: | |
26 | * 1. Redistributions of source code must retain the copyright | |
27 | * notice, this list of conditions and the following disclaimer. | |
28 | * 2. Redistributions in binary form must reproduce the above copyright | |
29 | * notice, this list of conditions and the following disclaimer in the | |
30 | * documentation and/or other materials provided with the distribution. | |
31 | * 3. All advertising materials mentioning features or use of this software | |
32 | * must display the following acknowledgement: | |
33 | * "This product includes cryptographic software written by | |
34 | * Eric Young (eay@cryptsoft.com)" | |
35 | * The word 'cryptographic' can be left out if the rouines from the library | |
36 | * being used are not cryptographic related :-). | |
0f113f3e | 37 | * 4. If you include any Windows specific code (or a derivative thereof) from |
d02b48c6 RE |
38 | * the apps directory (application code) you must include an acknowledgement: |
39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
0f113f3e | 40 | * |
d02b48c6 RE |
41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
45 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
46 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
47 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 | * SUCH DAMAGE. | |
0f113f3e | 52 | * |
d02b48c6 RE |
53 | * The licence and distribution terms for any publically available version or |
54 | * derivative of this code cannot be changed. i.e. this code cannot simply be | |
55 | * copied and put under another distribution licence | |
56 | * [including the GNU Public Licence.] | |
57 | */ | |
58 | ||
60e5f36d BM |
59 | /* disable assert() unless BIO_DEBUG has been defined */ |
60 | #ifndef BIO_DEBUG | |
61 | # ifndef NDEBUG | |
62 | # define NDEBUG | |
63 | # endif | |
64 | #endif | |
65 | ||
0f113f3e | 66 | /* |
d02b48c6 RE |
67 | * Stolen from tjh's ssl/ssl_trc.c stuff. |
68 | */ | |
69 | ||
70 | #include <stdio.h> | |
b478e91f UM |
71 | #include <string.h> |
72 | #include <ctype.h> | |
5ee0d9c4 RL |
73 | #include <assert.h> |
74 | #include <limits.h> | |
d02b48c6 | 75 | #include "cryptlib.h" |
a1990dd7 | 76 | #ifndef NO_SYS_TYPES_H |
0f113f3e | 77 | # include <sys/types.h> |
a1990dd7 | 78 | #endif |
347177e0 | 79 | #include <openssl/bn.h> /* To get BN_LLONG properly defined */ |
ec577822 | 80 | #include <openssl/bio.h> |
d02b48c6 | 81 | |
77519b51 | 82 | #if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT) |
b478e91f | 83 | # ifndef HAVE_LONG_LONG |
96723a3a | 84 | # define HAVE_LONG_LONG 1 |
b478e91f UM |
85 | # endif |
86 | #endif | |
87 | ||
e5c84d51 | 88 | /***************************************************************************/ |
d02b48c6 | 89 | |
9fd4ee5d UM |
90 | /* |
91 | * Copyright Patrick Powell 1995 | |
b478e91f | 92 | * This code is based on code written by Patrick Powell <papowell@astart.com> |
9fd4ee5d | 93 | * It may be used for any purpose as long as this notice remains intact |
b478e91f | 94 | * on all source code distributions. |
9fd4ee5d UM |
95 | */ |
96 | ||
1d97c843 | 97 | /*- |
b478e91f UM |
98 | * This code contains numerious changes and enhancements which were |
99 | * made by lots of contributors over the last years to Patrick Powell's | |
100 | * original code: | |
101 | * | |
102 | * o Patrick Powell <papowell@astart.com> (1995) | |
103 | * o Brandon Long <blong@fiction.net> (1996, for Mutt) | |
104 | * o Thomas Roessler <roessler@guug.de> (1998, for Mutt) | |
105 | * o Michael Elkins <me@cs.hmc.edu> (1998, for Mutt) | |
106 | * o Andrew Tridgell <tridge@samba.org> (1998, for Samba) | |
107 | * o Luke Mewburn <lukem@netbsd.org> (1999, for LukemFTP) | |
108 | * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth) | |
e5c84d51 | 109 | * o ... (for OpenSSL) |
9fd4ee5d UM |
110 | */ |
111 | ||
ba8fb521 | 112 | #ifdef HAVE_LONG_DOUBLE |
0f113f3e | 113 | # define LDOUBLE long double |
b478e91f | 114 | #else |
0f113f3e | 115 | # define LDOUBLE double |
b478e91f UM |
116 | #endif |
117 | ||
209b1281 | 118 | #ifdef HAVE_LONG_LONG |
77519b51 | 119 | # if defined(_WIN32) && !defined(__GNUC__) |
0f113f3e | 120 | # define LLONG __int64 |
c2e45f6d | 121 | # else |
0f113f3e | 122 | # define LLONG long long |
c2e45f6d | 123 | # endif |
b478e91f | 124 | #else |
0f113f3e | 125 | # define LLONG long |
b478e91f UM |
126 | #endif |
127 | ||
0f113f3e MC |
128 | static void fmtstr(char **, char **, size_t *, size_t *, |
129 | const char *, int, int, int); | |
130 | static void fmtint(char **, char **, size_t *, size_t *, | |
131 | LLONG, int, int, int, int); | |
132 | static void fmtfp(char **, char **, size_t *, size_t *, | |
133 | LDOUBLE, int, int, int); | |
134 | static void doapr_outch(char **, char **, size_t *, size_t *, int); | |
827dbcb1 | 135 | static void _dopr(char **sbuffer, char **buffer, |
0f113f3e MC |
136 | size_t *maxlen, size_t *retlen, int *truncated, |
137 | const char *format, va_list args); | |
b478e91f | 138 | |
9fd4ee5d | 139 | /* format read states */ |
b478e91f UM |
140 | #define DP_S_DEFAULT 0 |
141 | #define DP_S_FLAGS 1 | |
142 | #define DP_S_MIN 2 | |
143 | #define DP_S_DOT 3 | |
144 | #define DP_S_MAX 4 | |
145 | #define DP_S_MOD 5 | |
146 | #define DP_S_CONV 6 | |
147 | #define DP_S_DONE 7 | |
9fd4ee5d UM |
148 | |
149 | /* format flags - Bits */ | |
b478e91f UM |
150 | #define DP_F_MINUS (1 << 0) |
151 | #define DP_F_PLUS (1 << 1) | |
152 | #define DP_F_SPACE (1 << 2) | |
153 | #define DP_F_NUM (1 << 3) | |
154 | #define DP_F_ZERO (1 << 4) | |
155 | #define DP_F_UP (1 << 5) | |
156 | #define DP_F_UNSIGNED (1 << 6) | |
157 | ||
158 | /* conversion flags */ | |
159 | #define DP_C_SHORT 1 | |
160 | #define DP_C_LONG 2 | |
161 | #define DP_C_LDOUBLE 3 | |
162 | #define DP_C_LLONG 4 | |
163 | ||
164 | /* some handy macros */ | |
9fd4ee5d | 165 | #define char_to_int(p) (p - '0') |
99b1aaf2 | 166 | #define OSSL_MAX(p,q) ((p >= q) ? p : q) |
9fd4ee5d | 167 | |
5ee0d9c4 | 168 | static void |
0f113f3e MC |
169 | _dopr(char **sbuffer, |
170 | char **buffer, | |
171 | size_t *maxlen, | |
172 | size_t *retlen, int *truncated, const char *format, va_list args) | |
9fd4ee5d | 173 | { |
b478e91f UM |
174 | char ch; |
175 | LLONG value; | |
176 | LDOUBLE fvalue; | |
177 | char *strvalue; | |
178 | int min; | |
179 | int max; | |
180 | int state; | |
181 | int flags; | |
182 | int cflags; | |
183 | size_t currlen; | |
184 | ||
185 | state = DP_S_DEFAULT; | |
186 | flags = currlen = cflags = min = 0; | |
187 | max = -1; | |
188 | ch = *format++; | |
189 | ||
190 | while (state != DP_S_DONE) { | |
827dbcb1 | 191 | if (ch == '\0' || (buffer == NULL && currlen >= *maxlen)) |
b478e91f UM |
192 | state = DP_S_DONE; |
193 | ||
194 | switch (state) { | |
195 | case DP_S_DEFAULT: | |
196 | if (ch == '%') | |
197 | state = DP_S_FLAGS; | |
198 | else | |
0f113f3e | 199 | doapr_outch(sbuffer, buffer, &currlen, maxlen, ch); |
b478e91f UM |
200 | ch = *format++; |
201 | break; | |
202 | case DP_S_FLAGS: | |
203 | switch (ch) { | |
204 | case '-': | |
205 | flags |= DP_F_MINUS; | |
206 | ch = *format++; | |
207 | break; | |
208 | case '+': | |
209 | flags |= DP_F_PLUS; | |
210 | ch = *format++; | |
211 | break; | |
212 | case ' ': | |
213 | flags |= DP_F_SPACE; | |
214 | ch = *format++; | |
215 | break; | |
216 | case '#': | |
217 | flags |= DP_F_NUM; | |
218 | ch = *format++; | |
219 | break; | |
220 | case '0': | |
221 | flags |= DP_F_ZERO; | |
222 | ch = *format++; | |
223 | break; | |
224 | default: | |
225 | state = DP_S_MIN; | |
226 | break; | |
227 | } | |
228 | break; | |
229 | case DP_S_MIN: | |
230 | if (isdigit((unsigned char)ch)) { | |
231 | min = 10 * min + char_to_int(ch); | |
232 | ch = *format++; | |
233 | } else if (ch == '*') { | |
234 | min = va_arg(args, int); | |
235 | ch = *format++; | |
236 | state = DP_S_DOT; | |
237 | } else | |
238 | state = DP_S_DOT; | |
239 | break; | |
240 | case DP_S_DOT: | |
241 | if (ch == '.') { | |
242 | state = DP_S_MAX; | |
243 | ch = *format++; | |
244 | } else | |
245 | state = DP_S_MOD; | |
246 | break; | |
247 | case DP_S_MAX: | |
248 | if (isdigit((unsigned char)ch)) { | |
249 | if (max < 0) | |
250 | max = 0; | |
251 | max = 10 * max + char_to_int(ch); | |
252 | ch = *format++; | |
253 | } else if (ch == '*') { | |
254 | max = va_arg(args, int); | |
255 | ch = *format++; | |
256 | state = DP_S_MOD; | |
257 | } else | |
258 | state = DP_S_MOD; | |
259 | break; | |
260 | case DP_S_MOD: | |
261 | switch (ch) { | |
262 | case 'h': | |
263 | cflags = DP_C_SHORT; | |
264 | ch = *format++; | |
265 | break; | |
266 | case 'l': | |
267 | if (*format == 'l') { | |
268 | cflags = DP_C_LLONG; | |
269 | format++; | |
270 | } else | |
271 | cflags = DP_C_LONG; | |
272 | ch = *format++; | |
273 | break; | |
274 | case 'q': | |
275 | cflags = DP_C_LLONG; | |
276 | ch = *format++; | |
277 | break; | |
278 | case 'L': | |
279 | cflags = DP_C_LDOUBLE; | |
280 | ch = *format++; | |
281 | break; | |
282 | default: | |
283 | break; | |
284 | } | |
285 | state = DP_S_CONV; | |
286 | break; | |
287 | case DP_S_CONV: | |
288 | switch (ch) { | |
289 | case 'd': | |
290 | case 'i': | |
291 | switch (cflags) { | |
292 | case DP_C_SHORT: | |
1b7aee1d | 293 | value = (short int)va_arg(args, int); |
b478e91f UM |
294 | break; |
295 | case DP_C_LONG: | |
296 | value = va_arg(args, long int); | |
297 | break; | |
298 | case DP_C_LLONG: | |
299 | value = va_arg(args, LLONG); | |
300 | break; | |
301 | default: | |
302 | value = va_arg(args, int); | |
303 | break; | |
304 | } | |
827dbcb1 | 305 | fmtint(sbuffer, buffer, &currlen, maxlen, |
e5c84d51 | 306 | value, 10, min, max, flags); |
b478e91f UM |
307 | break; |
308 | case 'X': | |
309 | flags |= DP_F_UP; | |
310 | /* FALLTHROUGH */ | |
311 | case 'x': | |
312 | case 'o': | |
313 | case 'u': | |
314 | flags |= DP_F_UNSIGNED; | |
315 | switch (cflags) { | |
316 | case DP_C_SHORT: | |
42a9af38 | 317 | value = (unsigned short int)va_arg(args, unsigned int); |
b478e91f UM |
318 | break; |
319 | case DP_C_LONG: | |
0f113f3e | 320 | value = (LLONG) va_arg(args, unsigned long int); |
b478e91f UM |
321 | break; |
322 | case DP_C_LLONG: | |
323 | value = va_arg(args, unsigned LLONG); | |
324 | break; | |
325 | default: | |
0f113f3e | 326 | value = (LLONG) va_arg(args, unsigned int); |
b478e91f UM |
327 | break; |
328 | } | |
827dbcb1 | 329 | fmtint(sbuffer, buffer, &currlen, maxlen, value, |
b478e91f UM |
330 | ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), |
331 | min, max, flags); | |
332 | break; | |
333 | case 'f': | |
334 | if (cflags == DP_C_LDOUBLE) | |
335 | fvalue = va_arg(args, LDOUBLE); | |
336 | else | |
337 | fvalue = va_arg(args, double); | |
827dbcb1 | 338 | fmtfp(sbuffer, buffer, &currlen, maxlen, |
e5c84d51 | 339 | fvalue, min, max, flags); |
b478e91f UM |
340 | break; |
341 | case 'E': | |
342 | flags |= DP_F_UP; | |
343 | case 'e': | |
344 | if (cflags == DP_C_LDOUBLE) | |
345 | fvalue = va_arg(args, LDOUBLE); | |
346 | else | |
347 | fvalue = va_arg(args, double); | |
348 | break; | |
349 | case 'G': | |
350 | flags |= DP_F_UP; | |
351 | case 'g': | |
352 | if (cflags == DP_C_LDOUBLE) | |
353 | fvalue = va_arg(args, LDOUBLE); | |
354 | else | |
355 | fvalue = va_arg(args, double); | |
356 | break; | |
357 | case 'c': | |
827dbcb1 | 358 | doapr_outch(sbuffer, buffer, &currlen, maxlen, |
0f113f3e | 359 | va_arg(args, int)); |
b478e91f UM |
360 | break; |
361 | case 's': | |
362 | strvalue = va_arg(args, char *); | |
827dbcb1 | 363 | if (max < 0) { |
0f113f3e MC |
364 | if (buffer) |
365 | max = INT_MAX; | |
366 | else | |
367 | max = *maxlen; | |
368 | } | |
827dbcb1 | 369 | fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue, |
e5c84d51 | 370 | flags, min, max); |
b478e91f UM |
371 | break; |
372 | case 'p': | |
373 | value = (long)va_arg(args, void *); | |
827dbcb1 | 374 | fmtint(sbuffer, buffer, &currlen, maxlen, |
0f113f3e | 375 | value, 16, min, max, flags | DP_F_NUM); |
b478e91f | 376 | break; |
0f113f3e | 377 | case 'n': /* XXX */ |
b478e91f UM |
378 | if (cflags == DP_C_SHORT) { |
379 | short int *num; | |
380 | num = va_arg(args, short int *); | |
381 | *num = currlen; | |
382 | } else if (cflags == DP_C_LONG) { /* XXX */ | |
383 | long int *num; | |
384 | num = va_arg(args, long int *); | |
0f113f3e | 385 | *num = (long int)currlen; |
b478e91f UM |
386 | } else if (cflags == DP_C_LLONG) { /* XXX */ |
387 | LLONG *num; | |
388 | num = va_arg(args, LLONG *); | |
389 | *num = (LLONG) currlen; | |
390 | } else { | |
0f113f3e | 391 | int *num; |
b478e91f UM |
392 | num = va_arg(args, int *); |
393 | *num = currlen; | |
394 | } | |
395 | break; | |
396 | case '%': | |
827dbcb1 | 397 | doapr_outch(sbuffer, buffer, &currlen, maxlen, ch); |
b478e91f UM |
398 | break; |
399 | case 'w': | |
400 | /* not supported yet, treat as next char */ | |
401 | ch = *format++; | |
402 | break; | |
403 | default: | |
404 | /* unknown, skip */ | |
405 | break; | |
406 | } | |
407 | ch = *format++; | |
408 | state = DP_S_DEFAULT; | |
409 | flags = cflags = min = 0; | |
410 | max = -1; | |
411 | break; | |
412 | case DP_S_DONE: | |
413 | break; | |
414 | default: | |
415 | break; | |
9fd4ee5d | 416 | } |
9fd4ee5d | 417 | } |
e5c84d51 BM |
418 | *truncated = (currlen > *maxlen - 1); |
419 | if (*truncated) | |
5ee0d9c4 | 420 | currlen = *maxlen - 1; |
827dbcb1 RL |
421 | doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'); |
422 | *retlen = currlen - 1; | |
b478e91f | 423 | return; |
9fd4ee5d UM |
424 | } |
425 | ||
b478e91f | 426 | static void |
0f113f3e MC |
427 | fmtstr(char **sbuffer, |
428 | char **buffer, | |
429 | size_t *currlen, | |
430 | size_t *maxlen, const char *value, int flags, int min, int max) | |
9fd4ee5d | 431 | { |
b478e91f UM |
432 | int padlen, strln; |
433 | int cnt = 0; | |
434 | ||
435 | if (value == 0) | |
436 | value = "<NULL>"; | |
0f113f3e | 437 | for (strln = 0; value[strln]; ++strln) ; |
b478e91f UM |
438 | padlen = min - strln; |
439 | if (padlen < 0) | |
440 | padlen = 0; | |
441 | if (flags & DP_F_MINUS) | |
442 | padlen = -padlen; | |
443 | ||
444 | while ((padlen > 0) && (cnt < max)) { | |
827dbcb1 | 445 | doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); |
b478e91f UM |
446 | --padlen; |
447 | ++cnt; | |
448 | } | |
449 | while (*value && (cnt < max)) { | |
827dbcb1 | 450 | doapr_outch(sbuffer, buffer, currlen, maxlen, *value++); |
b478e91f UM |
451 | ++cnt; |
452 | } | |
453 | while ((padlen < 0) && (cnt < max)) { | |
827dbcb1 | 454 | doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); |
b478e91f UM |
455 | ++padlen; |
456 | ++cnt; | |
457 | } | |
9fd4ee5d UM |
458 | } |
459 | ||
b478e91f | 460 | static void |
0f113f3e MC |
461 | fmtint(char **sbuffer, |
462 | char **buffer, | |
463 | size_t *currlen, | |
464 | size_t *maxlen, LLONG value, int base, int min, int max, int flags) | |
9fd4ee5d | 465 | { |
b478e91f | 466 | int signvalue = 0; |
70f34a58 | 467 | const char *prefix = ""; |
b478e91f | 468 | unsigned LLONG uvalue; |
0f113f3e | 469 | char convert[DECIMAL_SIZE(value) + 3]; |
b478e91f UM |
470 | int place = 0; |
471 | int spadlen = 0; | |
472 | int zpadlen = 0; | |
473 | int caps = 0; | |
474 | ||
475 | if (max < 0) | |
476 | max = 0; | |
477 | uvalue = value; | |
478 | if (!(flags & DP_F_UNSIGNED)) { | |
479 | if (value < 0) { | |
480 | signvalue = '-'; | |
481 | uvalue = -value; | |
482 | } else if (flags & DP_F_PLUS) | |
483 | signvalue = '+'; | |
484 | else if (flags & DP_F_SPACE) | |
485 | signvalue = ' '; | |
9fd4ee5d | 486 | } |
c433d725 | 487 | if (flags & DP_F_NUM) { |
0f113f3e MC |
488 | if (base == 8) |
489 | prefix = "0"; | |
490 | if (base == 16) | |
491 | prefix = "0x"; | |
c433d725 | 492 | } |
b478e91f UM |
493 | if (flags & DP_F_UP) |
494 | caps = 1; | |
495 | do { | |
0f113f3e MC |
496 | convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") |
497 | [uvalue % (unsigned)base]; | |
498 | uvalue = (uvalue / (unsigned)base); | |
8a66d178 GT |
499 | } while (uvalue && (place < (int)sizeof(convert))); |
500 | if (place == sizeof(convert)) | |
b478e91f UM |
501 | place--; |
502 | convert[place] = 0; | |
503 | ||
504 | zpadlen = max - place; | |
0f113f3e MC |
505 | spadlen = |
506 | min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix); | |
b478e91f UM |
507 | if (zpadlen < 0) |
508 | zpadlen = 0; | |
509 | if (spadlen < 0) | |
510 | spadlen = 0; | |
511 | if (flags & DP_F_ZERO) { | |
99b1aaf2 | 512 | zpadlen = OSSL_MAX(zpadlen, spadlen); |
b478e91f | 513 | spadlen = 0; |
9fd4ee5d | 514 | } |
b478e91f UM |
515 | if (flags & DP_F_MINUS) |
516 | spadlen = -spadlen; | |
9fd4ee5d | 517 | |
b478e91f UM |
518 | /* spaces */ |
519 | while (spadlen > 0) { | |
827dbcb1 | 520 | doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); |
b478e91f UM |
521 | --spadlen; |
522 | } | |
9fd4ee5d | 523 | |
b478e91f UM |
524 | /* sign */ |
525 | if (signvalue) | |
827dbcb1 | 526 | doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); |
9fd4ee5d | 527 | |
c433d725 RL |
528 | /* prefix */ |
529 | while (*prefix) { | |
0f113f3e MC |
530 | doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix); |
531 | prefix++; | |
c433d725 RL |
532 | } |
533 | ||
b478e91f UM |
534 | /* zeros */ |
535 | if (zpadlen > 0) { | |
536 | while (zpadlen > 0) { | |
827dbcb1 | 537 | doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); |
b478e91f UM |
538 | --zpadlen; |
539 | } | |
540 | } | |
541 | /* digits */ | |
542 | while (place > 0) | |
827dbcb1 | 543 | doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]); |
b478e91f UM |
544 | |
545 | /* left justified spaces */ | |
546 | while (spadlen < 0) { | |
827dbcb1 | 547 | doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); |
b478e91f UM |
548 | ++spadlen; |
549 | } | |
550 | return; | |
9fd4ee5d UM |
551 | } |
552 | ||
0f113f3e | 553 | static LDOUBLE abs_val(LDOUBLE value) |
9fd4ee5d | 554 | { |
b478e91f UM |
555 | LDOUBLE result = value; |
556 | if (value < 0) | |
557 | result = -value; | |
558 | return result; | |
9fd4ee5d UM |
559 | } |
560 | ||
0f113f3e | 561 | static LDOUBLE pow_10(int in_exp) |
9fd4ee5d | 562 | { |
b478e91f | 563 | LDOUBLE result = 1; |
d8ec0dcf | 564 | while (in_exp) { |
b478e91f | 565 | result *= 10; |
d8ec0dcf | 566 | in_exp--; |
b478e91f UM |
567 | } |
568 | return result; | |
9fd4ee5d UM |
569 | } |
570 | ||
0f113f3e | 571 | static long roundv(LDOUBLE value) |
9fd4ee5d | 572 | { |
b478e91f | 573 | long intpart; |
0f113f3e | 574 | intpart = (long)value; |
b478e91f UM |
575 | value = value - intpart; |
576 | if (value >= 0.5) | |
577 | intpart++; | |
578 | return intpart; | |
579 | } | |
9fd4ee5d | 580 | |
b478e91f | 581 | static void |
0f113f3e MC |
582 | fmtfp(char **sbuffer, |
583 | char **buffer, | |
584 | size_t *currlen, | |
585 | size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags) | |
b478e91f UM |
586 | { |
587 | int signvalue = 0; | |
588 | LDOUBLE ufvalue; | |
589 | char iconvert[20]; | |
590 | char fconvert[20]; | |
591 | int iplace = 0; | |
592 | int fplace = 0; | |
593 | int padlen = 0; | |
594 | int zpadlen = 0; | |
b478e91f UM |
595 | long intpart; |
596 | long fracpart; | |
032c3ecb | 597 | long max10; |
b478e91f UM |
598 | |
599 | if (max < 0) | |
600 | max = 6; | |
601 | ufvalue = abs_val(fvalue); | |
602 | if (fvalue < 0) | |
603 | signvalue = '-'; | |
604 | else if (flags & DP_F_PLUS) | |
605 | signvalue = '+'; | |
606 | else if (flags & DP_F_SPACE) | |
607 | signvalue = ' '; | |
608 | ||
609 | intpart = (long)ufvalue; | |
610 | ||
0f113f3e MC |
611 | /* |
612 | * sorry, we only support 9 digits past the decimal because of our | |
613 | * conversion method | |
614 | */ | |
b478e91f UM |
615 | if (max > 9) |
616 | max = 9; | |
617 | ||
0f113f3e MC |
618 | /* |
619 | * we "cheat" by converting the fractional part to integer by multiplying | |
620 | * by a factor of 10 | |
621 | */ | |
2c288b2a NL |
622 | max10 = roundv(pow_10(max)); |
623 | fracpart = roundv(pow_10(max) * (ufvalue - intpart)); | |
b478e91f | 624 | |
032c3ecb | 625 | if (fracpart >= max10) { |
b478e91f | 626 | intpart++; |
032c3ecb | 627 | fracpart -= max10; |
b478e91f | 628 | } |
9fd4ee5d | 629 | |
b478e91f UM |
630 | /* convert integer part */ |
631 | do { | |
b7573c59 | 632 | iconvert[iplace++] = "0123456789"[intpart % 10]; |
b478e91f | 633 | intpart = (intpart / 10); |
a2b0de98 RL |
634 | } while (intpart && (iplace < (int)sizeof(iconvert))); |
635 | if (iplace == sizeof iconvert) | |
b478e91f UM |
636 | iplace--; |
637 | iconvert[iplace] = 0; | |
638 | ||
639 | /* convert fractional part */ | |
640 | do { | |
b7573c59 | 641 | fconvert[fplace++] = "0123456789"[fracpart % 10]; |
b478e91f | 642 | fracpart = (fracpart / 10); |
bf401a2a | 643 | } while (fplace < max); |
a2b0de98 | 644 | if (fplace == sizeof fconvert) |
b478e91f UM |
645 | fplace--; |
646 | fconvert[fplace] = 0; | |
647 | ||
648 | /* -1 for decimal point, another -1 if we are printing a sign */ | |
649 | padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); | |
650 | zpadlen = max - fplace; | |
651 | if (zpadlen < 0) | |
652 | zpadlen = 0; | |
653 | if (padlen < 0) | |
654 | padlen = 0; | |
655 | if (flags & DP_F_MINUS) | |
656 | padlen = -padlen; | |
657 | ||
658 | if ((flags & DP_F_ZERO) && (padlen > 0)) { | |
659 | if (signvalue) { | |
827dbcb1 | 660 | doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); |
b478e91f UM |
661 | --padlen; |
662 | signvalue = 0; | |
663 | } | |
664 | while (padlen > 0) { | |
827dbcb1 | 665 | doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); |
b478e91f UM |
666 | --padlen; |
667 | } | |
668 | } | |
669 | while (padlen > 0) { | |
827dbcb1 | 670 | doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); |
b478e91f UM |
671 | --padlen; |
672 | } | |
673 | if (signvalue) | |
827dbcb1 | 674 | doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue); |
9fd4ee5d | 675 | |
b478e91f | 676 | while (iplace > 0) |
827dbcb1 | 677 | doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]); |
9fd4ee5d | 678 | |
b478e91f UM |
679 | /* |
680 | * Decimal point. This should probably use locale to find the correct | |
681 | * char to print out. | |
682 | */ | |
c433d725 | 683 | if (max > 0 || (flags & DP_F_NUM)) { |
827dbcb1 | 684 | doapr_outch(sbuffer, buffer, currlen, maxlen, '.'); |
9fd4ee5d | 685 | |
b478e91f | 686 | while (fplace > 0) |
827dbcb1 | 687 | doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]); |
b478e91f UM |
688 | } |
689 | while (zpadlen > 0) { | |
827dbcb1 | 690 | doapr_outch(sbuffer, buffer, currlen, maxlen, '0'); |
b478e91f | 691 | --zpadlen; |
9fd4ee5d | 692 | } |
b478e91f UM |
693 | |
694 | while (padlen < 0) { | |
827dbcb1 | 695 | doapr_outch(sbuffer, buffer, currlen, maxlen, ' '); |
b478e91f | 696 | ++padlen; |
9fd4ee5d | 697 | } |
9fd4ee5d UM |
698 | } |
699 | ||
5ee0d9c4 | 700 | static void |
0f113f3e MC |
701 | doapr_outch(char **sbuffer, |
702 | char **buffer, size_t *currlen, size_t *maxlen, int c) | |
9fd4ee5d | 703 | { |
827dbcb1 RL |
704 | /* If we haven't at least one buffer, someone has doe a big booboo */ |
705 | assert(*sbuffer != NULL || buffer != NULL); | |
706 | ||
707 | if (buffer) { | |
0f113f3e MC |
708 | while (*currlen >= *maxlen) { |
709 | if (*buffer == NULL) { | |
710 | if (*maxlen == 0) | |
711 | *maxlen = 1024; | |
712 | *buffer = OPENSSL_malloc(*maxlen); | |
61986d32 | 713 | if (!*buffer) { |
918bb865 MC |
714 | /* Panic! Can't really do anything sensible. Just return */ |
715 | return; | |
716 | } | |
0f113f3e MC |
717 | if (*currlen > 0) { |
718 | assert(*sbuffer != NULL); | |
719 | memcpy(*buffer, *sbuffer, *currlen); | |
720 | } | |
721 | *sbuffer = NULL; | |
722 | } else { | |
723 | *maxlen += 1024; | |
724 | *buffer = OPENSSL_realloc(*buffer, *maxlen); | |
61986d32 | 725 | if (!*buffer) { |
918bb865 MC |
726 | /* Panic! Can't really do anything sensible. Just return */ |
727 | return; | |
728 | } | |
0f113f3e MC |
729 | } |
730 | } | |
731 | /* What to do if *buffer is NULL? */ | |
732 | assert(*sbuffer != NULL || *buffer != NULL); | |
5ee0d9c4 | 733 | } |
827dbcb1 RL |
734 | |
735 | if (*currlen < *maxlen) { | |
0f113f3e MC |
736 | if (*sbuffer) |
737 | (*sbuffer)[(*currlen)++] = (char)c; | |
738 | else | |
739 | (*buffer)[(*currlen)++] = (char)c; | |
5ee0d9c4 | 740 | } |
5ee0d9c4 | 741 | |
b478e91f | 742 | return; |
9fd4ee5d | 743 | } |
e5c84d51 BM |
744 | |
745 | /***************************************************************************/ | |
746 | ||
0f113f3e MC |
747 | int BIO_printf(BIO *bio, const char *format, ...) |
748 | { | |
749 | va_list args; | |
750 | int ret; | |
751 | ||
752 | va_start(args, format); | |
753 | ||
754 | ret = BIO_vprintf(bio, format, args); | |
755 | ||
756 | va_end(args); | |
757 | return (ret); | |
758 | } | |
759 | ||
760 | int BIO_vprintf(BIO *bio, const char *format, va_list args) | |
761 | { | |
762 | int ret; | |
763 | size_t retlen; | |
764 | char hugebuf[1024 * 2]; /* Was previously 10k, which is unreasonable | |
765 | * in small-stack environments, like threads | |
766 | * or DOS programs. */ | |
767 | char *hugebufp = hugebuf; | |
768 | size_t hugebufsize = sizeof(hugebuf); | |
769 | char *dynbuf = NULL; | |
770 | int ignored; | |
771 | ||
772 | dynbuf = NULL; | |
773 | CRYPTO_push_info("doapr()"); | |
774 | _dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format, args); | |
775 | if (dynbuf) { | |
776 | ret = BIO_write(bio, dynbuf, (int)retlen); | |
777 | OPENSSL_free(dynbuf); | |
778 | } else { | |
779 | ret = BIO_write(bio, hugebuf, (int)retlen); | |
780 | } | |
781 | CRYPTO_pop_info(); | |
782 | return (ret); | |
783 | } | |
784 | ||
785 | /* | |
786 | * As snprintf is not available everywhere, we provide our own | |
787 | * implementation. This function has nothing to do with BIOs, but it's | |
788 | * closely related to BIO_printf, and we need *some* name prefix ... (XXX the | |
789 | * function should be renamed, but to what?) | |
790 | */ | |
e5c84d51 | 791 | int BIO_snprintf(char *buf, size_t n, const char *format, ...) |
0f113f3e MC |
792 | { |
793 | va_list args; | |
794 | int ret; | |
e6629837 | 795 | |
0f113f3e | 796 | va_start(args, format); |
e6629837 | 797 | |
0f113f3e | 798 | ret = BIO_vsnprintf(buf, n, format, args); |
e6629837 | 799 | |
0f113f3e MC |
800 | va_end(args); |
801 | return (ret); | |
802 | } | |
e6629837 RL |
803 | |
804 | int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) | |
0f113f3e MC |
805 | { |
806 | size_t retlen; | |
807 | int truncated; | |
808 | ||
809 | _dopr(&buf, NULL, &n, &retlen, &truncated, format, args); | |
810 | ||
811 | if (truncated) | |
812 | /* | |
813 | * In case of truncation, return -1 like traditional snprintf. | |
814 | * (Current drafts for ISO/IEC 9899 say snprintf should return the | |
815 | * number of characters that would have been written, had the buffer | |
816 | * been large enough.) | |
817 | */ | |
818 | return -1; | |
819 | else | |
820 | return (retlen <= INT_MAX) ? (int)retlen : -1; | |
821 | } |