Typo corrected.
[openssl.git] / crypto / bio / b_print.c
1 /* crypto/bio/b_print.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
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.
8  * 
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).
15  * 
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.
22  * 
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 :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from 
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  * 
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.
52  * 
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
59 /* 
60  * Stolen from tjh's ssl/ssl_trc.c stuff.
61  */
62
63 #include <stdio.h>
64 #include <stdarg.h>
65 #include <string.h>
66 #include <ctype.h>
67 #include "cryptlib.h"
68 #ifndef NO_SYS_TYPES_H
69 #include <sys/types.h>
70 #endif
71 #include <openssl/bio.h>
72
73 #ifdef BN_LLONG
74 # ifndef HAVE_LONG_LONG
75 #  define HAVE_LONG_LONG
76 # endif
77 #endif
78
79 static void dopr (char *buffer, size_t maxlen, size_t *retlen,
80         const char *format, va_list args);
81
82 int BIO_printf (BIO *bio, ...)
83         {
84         va_list args;
85         char *format;
86         int ret;
87         size_t retlen;
88         MS_STATIC char hugebuf[1024*2]; /* 10k in one chunk is the limit */
89
90         va_start(args, bio);
91         format=va_arg(args, char *);
92
93         hugebuf[0]='\0';
94         dopr(hugebuf, sizeof(hugebuf), &retlen, format, args);
95         ret=BIO_write(bio, hugebuf, (int)retlen);
96
97         va_end(args);
98         return(ret);
99         }
100
101 /*
102  * Copyright Patrick Powell 1995
103  * This code is based on code written by Patrick Powell <papowell@astart.com>
104  * It may be used for any purpose as long as this notice remains intact
105  * on all source code distributions.
106  */
107
108 /*
109  * This code contains numerious changes and enhancements which were
110  * made by lots of contributors over the last years to Patrick Powell's
111  * original code:
112  *
113  * o Patrick Powell <papowell@astart.com>      (1995)
114  * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
115  * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
116  * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
117  * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
118  * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
119  * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
120  */
121
122 #if HAVE_LONG_DOUBLE
123 #define LDOUBLE long double
124 #else
125 #define LDOUBLE double
126 #endif
127
128 #if HAVE_LONG_LONG
129 #define LLONG long long
130 #else
131 #define LLONG long
132 #endif
133
134 static void fmtstr     (char *, size_t *, size_t, char *, int, int, int);
135 static void fmtint     (char *, size_t *, size_t, LLONG, int, int, int, int);
136 static void fmtfp      (char *, size_t *, size_t, LDOUBLE, int, int, int);
137 static void dopr_outch (char *, size_t *, size_t, int);
138
139 /* format read states */
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
148
149 /* format flags - Bits */
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 */
165 #define char_to_int(p) (p - '0')
166 #define MAX(p,q) ((p >= q) ? p : q)
167
168 static void
169 dopr(
170     char *buffer,
171     size_t maxlen,
172     size_t *retlen,
173     const char *format,
174     va_list args)
175 {
176     char ch;
177     LLONG value;
178     LDOUBLE fvalue;
179     char *strvalue;
180     int min;
181     int max;
182     int state;
183     int flags;
184     int cflags;
185     size_t currlen;
186
187     state = DP_S_DEFAULT;
188     flags = currlen = cflags = min = 0;
189     max = -1;
190     ch = *format++;
191
192     while (state != DP_S_DONE) {
193         if ((ch == '\0') || (currlen >= maxlen))
194             state = DP_S_DONE;
195
196         switch (state) {
197         case DP_S_DEFAULT:
198             if (ch == '%')
199                 state = DP_S_FLAGS;
200             else
201                 dopr_outch(buffer, &currlen, maxlen, ch);
202             ch = *format++;
203             break;
204         case DP_S_FLAGS:
205             switch (ch) {
206             case '-':
207                 flags |= DP_F_MINUS;
208                 ch = *format++;
209                 break;
210             case '+':
211                 flags |= DP_F_PLUS;
212                 ch = *format++;
213                 break;
214             case ' ':
215                 flags |= DP_F_SPACE;
216                 ch = *format++;
217                 break;
218             case '#':
219                 flags |= DP_F_NUM;
220                 ch = *format++;
221                 break;
222             case '0':
223                 flags |= DP_F_ZERO;
224                 ch = *format++;
225                 break;
226             default:
227                 state = DP_S_MIN;
228                 break;
229             }
230             break;
231         case DP_S_MIN:
232             if (isdigit((unsigned char)ch)) {
233                 min = 10 * min + char_to_int(ch);
234                 ch = *format++;
235             } else if (ch == '*') {
236                 min = va_arg(args, int);
237                 ch = *format++;
238                 state = DP_S_DOT;
239             } else
240                 state = DP_S_DOT;
241             break;
242         case DP_S_DOT:
243             if (ch == '.') {
244                 state = DP_S_MAX;
245                 ch = *format++;
246             } else
247                 state = DP_S_MOD;
248             break;
249         case DP_S_MAX:
250             if (isdigit((unsigned char)ch)) {
251                 if (max < 0)
252                     max = 0;
253                 max = 10 * max + char_to_int(ch);
254                 ch = *format++;
255             } else if (ch == '*') {
256                 max = va_arg(args, int);
257                 ch = *format++;
258                 state = DP_S_MOD;
259             } else
260                 state = DP_S_MOD;
261             break;
262         case DP_S_MOD:
263             switch (ch) {
264             case 'h':
265                 cflags = DP_C_SHORT;
266                 ch = *format++;
267                 break;
268             case 'l':
269                 if (*format == 'l') {
270                     cflags = DP_C_LLONG;
271                     format++;
272                 } else
273                     cflags = DP_C_LONG;
274                 ch = *format++;
275                 break;
276             case 'q':
277                 cflags = DP_C_LLONG;
278                 ch = *format++;
279                 break;
280             case 'L':
281                 cflags = DP_C_LDOUBLE;
282                 ch = *format++;
283                 break;
284             default:
285                 break;
286             }
287             state = DP_S_CONV;
288             break;
289         case DP_S_CONV:
290             switch (ch) {
291             case 'd':
292             case 'i':
293                 switch (cflags) {
294                 case DP_C_SHORT:
295                     value = (short int)va_arg(args, int);
296                     break;
297                 case DP_C_LONG:
298                     value = va_arg(args, long int);
299                     break;
300                 case DP_C_LLONG:
301                     value = va_arg(args, LLONG);
302                     break;
303                 default:
304                     value = va_arg(args, int);
305                     break;
306                 }
307                 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
308                 break;
309             case 'X':
310                 flags |= DP_F_UP;
311                 /* FALLTHROUGH */
312             case 'x':
313             case 'o':
314             case 'u':
315                 flags |= DP_F_UNSIGNED;
316                 switch (cflags) {
317                 case DP_C_SHORT:
318                     value = (unsigned short int)va_arg(args, unsigned int);
319                     break;
320                 case DP_C_LONG:
321                     value = (LLONG) va_arg(args,
322                         unsigned long int);
323                     break;
324                 case DP_C_LLONG:
325                     value = va_arg(args, unsigned LLONG);
326                     break;
327                 default:
328                     value = (LLONG) va_arg(args,
329                         unsigned int);
330                     break;
331                 }
332                 fmtint(buffer, &currlen, maxlen, value,
333                        ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
334                        min, max, flags);
335                 break;
336             case 'f':
337                 if (cflags == DP_C_LDOUBLE)
338                     fvalue = va_arg(args, LDOUBLE);
339                 else
340                     fvalue = va_arg(args, double);
341                 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
342                 break;
343             case 'E':
344                 flags |= DP_F_UP;
345             case 'e':
346                 if (cflags == DP_C_LDOUBLE)
347                     fvalue = va_arg(args, LDOUBLE);
348                 else
349                     fvalue = va_arg(args, double);
350                 break;
351             case 'G':
352                 flags |= DP_F_UP;
353             case 'g':
354                 if (cflags == DP_C_LDOUBLE)
355                     fvalue = va_arg(args, LDOUBLE);
356                 else
357                     fvalue = va_arg(args, double);
358                 break;
359             case 'c':
360                 dopr_outch(buffer, &currlen, maxlen,
361                     va_arg(args, int));
362                 break;
363             case 's':
364                 strvalue = va_arg(args, char *);
365                 if (max < 0)
366                     max = maxlen;
367                 fmtstr(buffer, &currlen, maxlen, strvalue,
368                     flags, min, max);
369                 break;
370             case 'p':
371                 value = (long)va_arg(args, void *);
372                 fmtint(buffer, &currlen, maxlen,
373                     value, 16, min, max, flags);
374                 break;
375             case 'n': /* XXX */
376                 if (cflags == DP_C_SHORT) {
377                     short int *num;
378                     num = va_arg(args, short int *);
379                     *num = currlen;
380                 } else if (cflags == DP_C_LONG) { /* XXX */
381                     long int *num;
382                     num = va_arg(args, long int *);
383                     *num = (long int) currlen;
384                 } else if (cflags == DP_C_LLONG) { /* XXX */
385                     LLONG *num;
386                     num = va_arg(args, LLONG *);
387                     *num = (LLONG) currlen;
388                 } else {
389                     int    *num;
390                     num = va_arg(args, int *);
391                     *num = currlen;
392                 }
393                 break;
394             case '%':
395                 dopr_outch(buffer, &currlen, maxlen, ch);
396                 break;
397             case 'w':
398                 /* not supported yet, treat as next char */
399                 ch = *format++;
400                 break;
401             default:
402                 /* unknown, skip */
403                 break;
404             }
405             ch = *format++;
406             state = DP_S_DEFAULT;
407             flags = cflags = min = 0;
408             max = -1;
409             break;
410         case DP_S_DONE:
411             break;
412         default:
413             break;
414         }
415     }
416     if (currlen >= maxlen - 1)
417         currlen = maxlen - 1;
418     buffer[currlen] = '\0';
419     *retlen = currlen;
420     return;
421 }
422
423 static void
424 fmtstr(
425     char *buffer,
426     size_t *currlen,
427     size_t maxlen,
428     char *value,
429     int flags,
430     int min,
431     int max)
432 {
433     int padlen, strln;
434     int cnt = 0;
435
436     if (value == 0)
437         value = "<NULL>";
438     for (strln = 0; value[strln]; ++strln)
439         ;
440     padlen = min - strln;
441     if (padlen < 0)
442         padlen = 0;
443     if (flags & DP_F_MINUS)
444         padlen = -padlen;
445
446     while ((padlen > 0) && (cnt < max)) {
447         dopr_outch(buffer, currlen, maxlen, ' ');
448         --padlen;
449         ++cnt;
450     }
451     while (*value && (cnt < max)) {
452         dopr_outch(buffer, currlen, maxlen, *value++);
453         ++cnt;
454     }
455     while ((padlen < 0) && (cnt < max)) {
456         dopr_outch(buffer, currlen, maxlen, ' ');
457         ++padlen;
458         ++cnt;
459     }
460 }
461
462 static void
463 fmtint(
464     char *buffer,
465     size_t *currlen,
466     size_t maxlen,
467     LLONG value,
468     int base,
469     int min,
470     int max,
471     int flags)
472 {
473     int signvalue = 0;
474     unsigned LLONG uvalue;
475     char convert[20];
476     int place = 0;
477     int spadlen = 0;
478     int zpadlen = 0;
479     int caps = 0;
480
481     if (max < 0)
482         max = 0;
483     uvalue = value;
484     if (!(flags & DP_F_UNSIGNED)) {
485         if (value < 0) {
486             signvalue = '-';
487             uvalue = -value;
488         } else if (flags & DP_F_PLUS)
489             signvalue = '+';
490         else if (flags & DP_F_SPACE)
491             signvalue = ' ';
492     }
493     if (flags & DP_F_UP)
494         caps = 1;
495     do {
496         convert[place++] =
497             (caps ? "0123456789ABCDEF" : "0123456789abcdef")
498             [uvalue % (unsigned) base];
499         uvalue = (uvalue / (unsigned) base);
500     } while (uvalue && (place < 20));
501     if (place == 20)
502         place--;
503     convert[place] = 0;
504
505     zpadlen = max - place;
506     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
507     if (zpadlen < 0)
508         zpadlen = 0;
509     if (spadlen < 0)
510         spadlen = 0;
511     if (flags & DP_F_ZERO) {
512         zpadlen = MAX(zpadlen, spadlen);
513         spadlen = 0;
514     }
515     if (flags & DP_F_MINUS)
516         spadlen = -spadlen;
517
518     /* spaces */
519     while (spadlen > 0) {
520         dopr_outch(buffer, currlen, maxlen, ' ');
521         --spadlen;
522     }
523
524     /* sign */
525     if (signvalue)
526         dopr_outch(buffer, currlen, maxlen, signvalue);
527
528     /* zeros */
529     if (zpadlen > 0) {
530         while (zpadlen > 0) {
531             dopr_outch(buffer, currlen, maxlen, '0');
532             --zpadlen;
533         }
534     }
535     /* digits */
536     while (place > 0)
537         dopr_outch(buffer, currlen, maxlen, convert[--place]);
538
539     /* left justified spaces */
540     while (spadlen < 0) {
541         dopr_outch(buffer, currlen, maxlen, ' ');
542         ++spadlen;
543     }
544     return;
545 }
546
547 static LDOUBLE
548 abs_val(LDOUBLE value)
549 {
550     LDOUBLE result = value;
551     if (value < 0)
552         result = -value;
553     return result;
554 }
555
556 static LDOUBLE
557 pow10(int exp)
558 {
559     LDOUBLE result = 1;
560     while (exp) {
561         result *= 10;
562         exp--;
563     }
564     return result;
565 }
566
567 static long
568 round(LDOUBLE value)
569 {
570     long intpart;
571     intpart = (long) value;
572     value = value - intpart;
573     if (value >= 0.5)
574         intpart++;
575     return intpart;
576 }
577
578 static void
579 fmtfp(
580     char *buffer,
581     size_t *currlen,
582     size_t maxlen,
583     LDOUBLE fvalue,
584     int min,
585     int max,
586     int flags)
587 {
588     int signvalue = 0;
589     LDOUBLE ufvalue;
590     char iconvert[20];
591     char fconvert[20];
592     int iplace = 0;
593     int fplace = 0;
594     int padlen = 0;
595     int zpadlen = 0;
596     int caps = 0;
597     long intpart;
598     long fracpart;
599
600     if (max < 0)
601         max = 6;
602     ufvalue = abs_val(fvalue);
603     if (fvalue < 0)
604         signvalue = '-';
605     else if (flags & DP_F_PLUS)
606         signvalue = '+';
607     else if (flags & DP_F_SPACE)
608         signvalue = ' ';
609
610     intpart = (long)ufvalue;
611
612     /* sorry, we only support 9 digits past the decimal because of our
613        conversion method */
614     if (max > 9)
615         max = 9;
616
617     /* we "cheat" by converting the fractional part to integer by
618        multiplying by a factor of 10 */
619     fracpart = round((pow10(max)) * (ufvalue - intpart));
620
621     if (fracpart >= pow10(max)) {
622         intpart++;
623         fracpart -= (long)pow10(max);
624     }
625
626     /* convert integer part */
627     do {
628         iconvert[iplace++] =
629             (caps ? "0123456789ABCDEF"
630               : "0123456789abcdef")[intpart % 10];
631         intpart = (intpart / 10);
632     } while (intpart && (iplace < 20));
633     if (iplace == 20)
634         iplace--;
635     iconvert[iplace] = 0;
636
637     /* convert fractional part */
638     do {
639         fconvert[fplace++] =
640             (caps ? "0123456789ABCDEF"
641               : "0123456789abcdef")[fracpart % 10];
642         fracpart = (fracpart / 10);
643     } while (fracpart && (fplace < 20));
644     if (fplace == 20)
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) {
660             dopr_outch(buffer, currlen, maxlen, signvalue);
661             --padlen;
662             signvalue = 0;
663         }
664         while (padlen > 0) {
665             dopr_outch(buffer, currlen, maxlen, '0');
666             --padlen;
667         }
668     }
669     while (padlen > 0) {
670         dopr_outch(buffer, currlen, maxlen, ' ');
671         --padlen;
672     }
673     if (signvalue)
674         dopr_outch(buffer, currlen, maxlen, signvalue);
675
676     while (iplace > 0)
677         dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
678
679     /*
680      * Decimal point. This should probably use locale to find the correct
681      * char to print out.
682      */
683     if (max > 0) {
684         dopr_outch(buffer, currlen, maxlen, '.');
685
686         while (fplace > 0)
687             dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
688     }
689     while (zpadlen > 0) {
690         dopr_outch(buffer, currlen, maxlen, '0');
691         --zpadlen;
692     }
693
694     while (padlen < 0) {
695         dopr_outch(buffer, currlen, maxlen, ' ');
696         ++padlen;
697     }
698 }
699
700 static void
701 dopr_outch(
702     char *buffer,
703     size_t *currlen,
704     size_t maxlen,
705     int c)
706 {
707     if (*currlen < maxlen)
708         buffer[(*currlen)++] = (char)c;
709     return;
710 }