Let's avoid compiler warnings over types.
[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 <sys/types.h>
68 #include "cryptlib.h"
69 #include <openssl/bio.h>
70
71 #ifdef BN_LLONG
72 # ifndef HAVE_LONG_LONG
73 #  define HAVE_LONG_LONG
74 # endif
75 #endif
76
77 static void dopr (char *buffer, size_t maxlen, size_t *retlen,
78         const char *format, va_list args);
79
80 int BIO_printf (BIO *bio, ...)
81         {
82         va_list args;
83         char *format;
84         int ret;
85         size_t retlen;
86         MS_STATIC char hugebuf[1024*2]; /* 10k in one chunk is the limit */
87
88         va_start(args, bio);
89         format=va_arg(args, char *);
90
91         hugebuf[0]='\0';
92         dopr(hugebuf, sizeof(hugebuf), &retlen, format, args);
93         ret=BIO_write(bio, hugebuf, (int)retlen);
94
95         va_end(args);
96         return(ret);
97         }
98
99 /*
100  * Copyright Patrick Powell 1995
101  * This code is based on code written by Patrick Powell <papowell@astart.com>
102  * It may be used for any purpose as long as this notice remains intact
103  * on all source code distributions.
104  */
105
106 /*
107  * This code contains numerious changes and enhancements which were
108  * made by lots of contributors over the last years to Patrick Powell's
109  * original code:
110  *
111  * o Patrick Powell <papowell@astart.com>      (1995)
112  * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
113  * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
114  * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
115  * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
116  * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
117  * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
118  */
119
120 #if HAVE_LONG_DOUBLE
121 #define LDOUBLE long double
122 #else
123 #define LDOUBLE double
124 #endif
125
126 #if HAVE_LONG_LONG
127 #define LLONG long long
128 #else
129 #define LLONG long
130 #endif
131
132 static void fmtstr     (char *, size_t *, size_t, char *, int, int, int);
133 static void fmtint     (char *, size_t *, size_t, LLONG, int, int, int, int);
134 static void fmtfp      (char *, size_t *, size_t, LDOUBLE, int, int, int);
135 static void dopr_outch (char *, size_t *, size_t, int);
136
137 /* format read states */
138 #define DP_S_DEFAULT    0
139 #define DP_S_FLAGS      1
140 #define DP_S_MIN        2
141 #define DP_S_DOT        3
142 #define DP_S_MAX        4
143 #define DP_S_MOD        5
144 #define DP_S_CONV       6
145 #define DP_S_DONE       7
146
147 /* format flags - Bits */
148 #define DP_F_MINUS      (1 << 0)
149 #define DP_F_PLUS       (1 << 1)
150 #define DP_F_SPACE      (1 << 2)
151 #define DP_F_NUM        (1 << 3)
152 #define DP_F_ZERO       (1 << 4)
153 #define DP_F_UP         (1 << 5)
154 #define DP_F_UNSIGNED   (1 << 6)
155
156 /* conversion flags */
157 #define DP_C_SHORT      1
158 #define DP_C_LONG       2
159 #define DP_C_LDOUBLE    3
160 #define DP_C_LLONG      4
161
162 /* some handy macros */
163 #define char_to_int(p) (p - '0')
164 #define MAX(p,q) ((p >= q) ? p : q)
165
166 static void
167 dopr(
168     char *buffer,
169     size_t maxlen,
170     size_t *retlen,
171     const char *format,
172     va_list args)
173 {
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) {
191         if ((ch == '\0') || (currlen >= maxlen))
192             state = DP_S_DONE;
193
194         switch (state) {
195         case DP_S_DEFAULT:
196             if (ch == '%')
197                 state = DP_S_FLAGS;
198             else
199                 dopr_outch(buffer, &currlen, maxlen, ch);
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:
293                     value = va_arg(args, short int);
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                 }
305                 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
306                 break;
307             case 'X':
308                 flags |= DP_F_UP;
309                 /* FALLTHROUGH */
310             case 'x':
311             case 'o':
312             case 'u':
313                 flags |= DP_F_UNSIGNED;
314                 switch (cflags) {
315                 case DP_C_SHORT:
316                     value = va_arg(args,
317                         unsigned short int);
318                     break;
319                 case DP_C_LONG:
320                     value = (LLONG) va_arg(args,
321                         unsigned long int);
322                     break;
323                 case DP_C_LLONG:
324                     value = va_arg(args, unsigned LLONG);
325                     break;
326                 default:
327                     value = (LLONG) va_arg(args,
328                         unsigned int);
329                     break;
330                 }
331                 fmtint(buffer, &currlen, maxlen, value,
332                        ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
333                        min, max, flags);
334                 break;
335             case 'f':
336                 if (cflags == DP_C_LDOUBLE)
337                     fvalue = va_arg(args, LDOUBLE);
338                 else
339                     fvalue = va_arg(args, double);
340                 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
341                 break;
342             case 'E':
343                 flags |= DP_F_UP;
344             case 'e':
345                 if (cflags == DP_C_LDOUBLE)
346                     fvalue = va_arg(args, LDOUBLE);
347                 else
348                     fvalue = va_arg(args, double);
349                 break;
350             case 'G':
351                 flags |= DP_F_UP;
352             case 'g':
353                 if (cflags == DP_C_LDOUBLE)
354                     fvalue = va_arg(args, LDOUBLE);
355                 else
356                     fvalue = va_arg(args, double);
357                 break;
358             case 'c':
359                 dopr_outch(buffer, &currlen, maxlen,
360                     va_arg(args, int));
361                 break;
362             case 's':
363                 strvalue = va_arg(args, char *);
364                 if (max < 0)
365                     max = maxlen;
366                 fmtstr(buffer, &currlen, maxlen, strvalue,
367                     flags, min, max);
368                 break;
369             case 'p':
370                 value = (long)va_arg(args, void *);
371                 fmtint(buffer, &currlen, maxlen,
372                     value, 16, min, max, flags);
373                 break;
374             case 'n': /* XXX */
375                 if (cflags == DP_C_SHORT) {
376                     short int *num;
377                     num = va_arg(args, short int *);
378                     *num = currlen;
379                 } else if (cflags == DP_C_LONG) { /* XXX */
380                     long int *num;
381                     num = va_arg(args, long int *);
382                     *num = (long int) currlen;
383                 } else if (cflags == DP_C_LLONG) { /* XXX */
384                     LLONG *num;
385                     num = va_arg(args, LLONG *);
386                     *num = (LLONG) currlen;
387                 } else {
388                     int    *num;
389                     num = va_arg(args, int *);
390                     *num = currlen;
391                 }
392                 break;
393             case '%':
394                 dopr_outch(buffer, &currlen, maxlen, ch);
395                 break;
396             case 'w':
397                 /* not supported yet, treat as next char */
398                 ch = *format++;
399                 break;
400             default:
401                 /* unknown, skip */
402                 break;
403             }
404             ch = *format++;
405             state = DP_S_DEFAULT;
406             flags = cflags = min = 0;
407             max = -1;
408             break;
409         case DP_S_DONE:
410             break;
411         default:
412             break;
413         }
414     }
415     if (currlen >= maxlen - 1)
416         currlen = maxlen - 1;
417     buffer[currlen] = '\0';
418     *retlen = currlen;
419     return;
420 }
421
422 static void
423 fmtstr(
424     char *buffer,
425     size_t *currlen,
426     size_t maxlen,
427     char *value,
428     int flags,
429     int min,
430     int max)
431 {
432     int padlen, strln;
433     int cnt = 0;
434
435     if (value == 0)
436         value = "<NULL>";
437     for (strln = 0; value[strln]; ++strln)
438         ;
439     padlen = min - strln;
440     if (padlen < 0)
441         padlen = 0;
442     if (flags & DP_F_MINUS)
443         padlen = -padlen;
444
445     while ((padlen > 0) && (cnt < max)) {
446         dopr_outch(buffer, currlen, maxlen, ' ');
447         --padlen;
448         ++cnt;
449     }
450     while (*value && (cnt < max)) {
451         dopr_outch(buffer, currlen, maxlen, *value++);
452         ++cnt;
453     }
454     while ((padlen < 0) && (cnt < max)) {
455         dopr_outch(buffer, currlen, maxlen, ' ');
456         ++padlen;
457         ++cnt;
458     }
459 }
460
461 static void
462 fmtint(
463     char *buffer,
464     size_t *currlen,
465     size_t maxlen,
466     LLONG value,
467     int base,
468     int min,
469     int max,
470     int flags)
471 {
472     int signvalue = 0;
473     unsigned LLONG uvalue;
474     char convert[20];
475     int place = 0;
476     int spadlen = 0;
477     int zpadlen = 0;
478     int caps = 0;
479
480     if (max < 0)
481         max = 0;
482     uvalue = value;
483     if (!(flags & DP_F_UNSIGNED)) {
484         if (value < 0) {
485             signvalue = '-';
486             uvalue = -value;
487         } else if (flags & DP_F_PLUS)
488             signvalue = '+';
489         else if (flags & DP_F_SPACE)
490             signvalue = ' ';
491     }
492     if (flags & DP_F_UP)
493         caps = 1;
494     do {
495         convert[place++] =
496             (caps ? "0123456789ABCDEF" : "0123456789abcdef")
497             [uvalue % (unsigned) base];
498         uvalue = (uvalue / (unsigned) base);
499     } while (uvalue && (place < 20));
500     if (place == 20)
501         place--;
502     convert[place] = 0;
503
504     zpadlen = max - place;
505     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
506     if (zpadlen < 0)
507         zpadlen = 0;
508     if (spadlen < 0)
509         spadlen = 0;
510     if (flags & DP_F_ZERO) {
511         zpadlen = MAX(zpadlen, spadlen);
512         spadlen = 0;
513     }
514     if (flags & DP_F_MINUS)
515         spadlen = -spadlen;
516
517     /* spaces */
518     while (spadlen > 0) {
519         dopr_outch(buffer, currlen, maxlen, ' ');
520         --spadlen;
521     }
522
523     /* sign */
524     if (signvalue)
525         dopr_outch(buffer, currlen, maxlen, signvalue);
526
527     /* zeros */
528     if (zpadlen > 0) {
529         while (zpadlen > 0) {
530             dopr_outch(buffer, currlen, maxlen, '0');
531             --zpadlen;
532         }
533     }
534     /* digits */
535     while (place > 0)
536         dopr_outch(buffer, currlen, maxlen, convert[--place]);
537
538     /* left justified spaces */
539     while (spadlen < 0) {
540         dopr_outch(buffer, currlen, maxlen, ' ');
541         ++spadlen;
542     }
543     return;
544 }
545
546 static LDOUBLE
547 abs_val(LDOUBLE value)
548 {
549     LDOUBLE result = value;
550     if (value < 0)
551         result = -value;
552     return result;
553 }
554
555 static LDOUBLE
556 pow10(int exp)
557 {
558     LDOUBLE result = 1;
559     while (exp) {
560         result *= 10;
561         exp--;
562     }
563     return result;
564 }
565
566 static long
567 round(LDOUBLE value)
568 {
569     long intpart;
570     intpart = (long) value;
571     value = value - intpart;
572     if (value >= 0.5)
573         intpart++;
574     return intpart;
575 }
576
577 static void
578 fmtfp(
579     char *buffer,
580     size_t *currlen,
581     size_t maxlen,
582     LDOUBLE fvalue,
583     int min,
584     int max,
585     int flags)
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;
595     int caps = 0;
596     long intpart;
597     long fracpart;
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
611     /* sorry, we only support 9 digits past the decimal because of our
612        conversion method */
613     if (max > 9)
614         max = 9;
615
616     /* we "cheat" by converting the fractional part to integer by
617        multiplying by a factor of 10 */
618     fracpart = round((pow10(max)) * (ufvalue - intpart));
619
620     if (fracpart >= pow10(max)) {
621         intpart++;
622         fracpart -= (long)pow10(max);
623     }
624
625     /* convert integer part */
626     do {
627         iconvert[iplace++] =
628             (caps ? "0123456789ABCDEF"
629               : "0123456789abcdef")[intpart % 10];
630         intpart = (intpart / 10);
631     } while (intpart && (iplace < 20));
632     if (iplace == 20)
633         iplace--;
634     iconvert[iplace] = 0;
635
636     /* convert fractional part */
637     do {
638         fconvert[fplace++] =
639             (caps ? "0123456789ABCDEF"
640               : "0123456789abcdef")[fracpart % 10];
641         fracpart = (fracpart / 10);
642     } while (fracpart && (fplace < 20));
643     if (fplace == 20)
644         fplace--;
645     fconvert[fplace] = 0;
646
647     /* -1 for decimal point, another -1 if we are printing a sign */
648     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
649     zpadlen = max - fplace;
650     if (zpadlen < 0)
651         zpadlen = 0;
652     if (padlen < 0)
653         padlen = 0;
654     if (flags & DP_F_MINUS)
655         padlen = -padlen;
656
657     if ((flags & DP_F_ZERO) && (padlen > 0)) {
658         if (signvalue) {
659             dopr_outch(buffer, currlen, maxlen, signvalue);
660             --padlen;
661             signvalue = 0;
662         }
663         while (padlen > 0) {
664             dopr_outch(buffer, currlen, maxlen, '0');
665             --padlen;
666         }
667     }
668     while (padlen > 0) {
669         dopr_outch(buffer, currlen, maxlen, ' ');
670         --padlen;
671     }
672     if (signvalue)
673         dopr_outch(buffer, currlen, maxlen, signvalue);
674
675     while (iplace > 0)
676         dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
677
678     /*
679      * Decimal point. This should probably use locale to find the correct
680      * char to print out.
681      */
682     if (max > 0) {
683         dopr_outch(buffer, currlen, maxlen, '.');
684
685         while (fplace > 0)
686             dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
687     }
688     while (zpadlen > 0) {
689         dopr_outch(buffer, currlen, maxlen, '0');
690         --zpadlen;
691     }
692
693     while (padlen < 0) {
694         dopr_outch(buffer, currlen, maxlen, ' ');
695         ++padlen;
696     }
697 }
698
699 static void
700 dopr_outch(
701     char *buffer,
702     size_t *currlen,
703     size_t maxlen,
704     int c)
705 {
706     if (*currlen < maxlen)
707         buffer[(*currlen)++] = (char)c;
708     return;
709 }