Don't include sys/types.h if NO_SYS_TYPES_H is defined.
[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 = va_arg(args, short 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 = va_arg(args,
319                         unsigned short int);
320                     break;
321                 case DP_C_LONG:
322                     value = (LLONG) va_arg(args,
323                         unsigned long int);
324                     break;
325                 case DP_C_LLONG:
326                     value = va_arg(args, unsigned LLONG);
327                     break;
328                 default:
329                     value = (LLONG) va_arg(args,
330                         unsigned int);
331                     break;
332                 }
333                 fmtint(buffer, &currlen, maxlen, value,
334                        ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
335                        min, max, flags);
336                 break;
337             case 'f':
338                 if (cflags == DP_C_LDOUBLE)
339                     fvalue = va_arg(args, LDOUBLE);
340                 else
341                     fvalue = va_arg(args, double);
342                 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
343                 break;
344             case 'E':
345                 flags |= DP_F_UP;
346             case 'e':
347                 if (cflags == DP_C_LDOUBLE)
348                     fvalue = va_arg(args, LDOUBLE);
349                 else
350                     fvalue = va_arg(args, double);
351                 break;
352             case 'G':
353                 flags |= DP_F_UP;
354             case 'g':
355                 if (cflags == DP_C_LDOUBLE)
356                     fvalue = va_arg(args, LDOUBLE);
357                 else
358                     fvalue = va_arg(args, double);
359                 break;
360             case 'c':
361                 dopr_outch(buffer, &currlen, maxlen,
362                     va_arg(args, int));
363                 break;
364             case 's':
365                 strvalue = va_arg(args, char *);
366                 if (max < 0)
367                     max = maxlen;
368                 fmtstr(buffer, &currlen, maxlen, strvalue,
369                     flags, min, max);
370                 break;
371             case 'p':
372                 value = (long)va_arg(args, void *);
373                 fmtint(buffer, &currlen, maxlen,
374                     value, 16, min, max, flags);
375                 break;
376             case 'n': /* XXX */
377                 if (cflags == DP_C_SHORT) {
378                     short int *num;
379                     num = va_arg(args, short int *);
380                     *num = currlen;
381                 } else if (cflags == DP_C_LONG) { /* XXX */
382                     long int *num;
383                     num = va_arg(args, long int *);
384                     *num = (long int) currlen;
385                 } else if (cflags == DP_C_LLONG) { /* XXX */
386                     LLONG *num;
387                     num = va_arg(args, LLONG *);
388                     *num = (LLONG) currlen;
389                 } else {
390                     int    *num;
391                     num = va_arg(args, int *);
392                     *num = currlen;
393                 }
394                 break;
395             case '%':
396                 dopr_outch(buffer, &currlen, maxlen, ch);
397                 break;
398             case 'w':
399                 /* not supported yet, treat as next char */
400                 ch = *format++;
401                 break;
402             default:
403                 /* unknown, skip */
404                 break;
405             }
406             ch = *format++;
407             state = DP_S_DEFAULT;
408             flags = cflags = min = 0;
409             max = -1;
410             break;
411         case DP_S_DONE:
412             break;
413         default:
414             break;
415         }
416     }
417     if (currlen >= maxlen - 1)
418         currlen = maxlen - 1;
419     buffer[currlen] = '\0';
420     *retlen = currlen;
421     return;
422 }
423
424 static void
425 fmtstr(
426     char *buffer,
427     size_t *currlen,
428     size_t maxlen,
429     char *value,
430     int flags,
431     int min,
432     int max)
433 {
434     int padlen, strln;
435     int cnt = 0;
436
437     if (value == 0)
438         value = "<NULL>";
439     for (strln = 0; value[strln]; ++strln)
440         ;
441     padlen = min - strln;
442     if (padlen < 0)
443         padlen = 0;
444     if (flags & DP_F_MINUS)
445         padlen = -padlen;
446
447     while ((padlen > 0) && (cnt < max)) {
448         dopr_outch(buffer, currlen, maxlen, ' ');
449         --padlen;
450         ++cnt;
451     }
452     while (*value && (cnt < max)) {
453         dopr_outch(buffer, currlen, maxlen, *value++);
454         ++cnt;
455     }
456     while ((padlen < 0) && (cnt < max)) {
457         dopr_outch(buffer, currlen, maxlen, ' ');
458         ++padlen;
459         ++cnt;
460     }
461 }
462
463 static void
464 fmtint(
465     char *buffer,
466     size_t *currlen,
467     size_t maxlen,
468     LLONG value,
469     int base,
470     int min,
471     int max,
472     int flags)
473 {
474     int signvalue = 0;
475     unsigned LLONG uvalue;
476     char convert[20];
477     int place = 0;
478     int spadlen = 0;
479     int zpadlen = 0;
480     int caps = 0;
481
482     if (max < 0)
483         max = 0;
484     uvalue = value;
485     if (!(flags & DP_F_UNSIGNED)) {
486         if (value < 0) {
487             signvalue = '-';
488             uvalue = -value;
489         } else if (flags & DP_F_PLUS)
490             signvalue = '+';
491         else if (flags & DP_F_SPACE)
492             signvalue = ' ';
493     }
494     if (flags & DP_F_UP)
495         caps = 1;
496     do {
497         convert[place++] =
498             (caps ? "0123456789ABCDEF" : "0123456789abcdef")
499             [uvalue % (unsigned) base];
500         uvalue = (uvalue / (unsigned) base);
501     } while (uvalue && (place < 20));
502     if (place == 20)
503         place--;
504     convert[place] = 0;
505
506     zpadlen = max - place;
507     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
508     if (zpadlen < 0)
509         zpadlen = 0;
510     if (spadlen < 0)
511         spadlen = 0;
512     if (flags & DP_F_ZERO) {
513         zpadlen = MAX(zpadlen, spadlen);
514         spadlen = 0;
515     }
516     if (flags & DP_F_MINUS)
517         spadlen = -spadlen;
518
519     /* spaces */
520     while (spadlen > 0) {
521         dopr_outch(buffer, currlen, maxlen, ' ');
522         --spadlen;
523     }
524
525     /* sign */
526     if (signvalue)
527         dopr_outch(buffer, currlen, maxlen, signvalue);
528
529     /* zeros */
530     if (zpadlen > 0) {
531         while (zpadlen > 0) {
532             dopr_outch(buffer, currlen, maxlen, '0');
533             --zpadlen;
534         }
535     }
536     /* digits */
537     while (place > 0)
538         dopr_outch(buffer, currlen, maxlen, convert[--place]);
539
540     /* left justified spaces */
541     while (spadlen < 0) {
542         dopr_outch(buffer, currlen, maxlen, ' ');
543         ++spadlen;
544     }
545     return;
546 }
547
548 static LDOUBLE
549 abs_val(LDOUBLE value)
550 {
551     LDOUBLE result = value;
552     if (value < 0)
553         result = -value;
554     return result;
555 }
556
557 static LDOUBLE
558 pow10(int exp)
559 {
560     LDOUBLE result = 1;
561     while (exp) {
562         result *= 10;
563         exp--;
564     }
565     return result;
566 }
567
568 static long
569 round(LDOUBLE value)
570 {
571     long intpart;
572     intpart = (long) value;
573     value = value - intpart;
574     if (value >= 0.5)
575         intpart++;
576     return intpart;
577 }
578
579 static void
580 fmtfp(
581     char *buffer,
582     size_t *currlen,
583     size_t maxlen,
584     LDOUBLE fvalue,
585     int min,
586     int max,
587     int flags)
588 {
589     int signvalue = 0;
590     LDOUBLE ufvalue;
591     char iconvert[20];
592     char fconvert[20];
593     int iplace = 0;
594     int fplace = 0;
595     int padlen = 0;
596     int zpadlen = 0;
597     int caps = 0;
598     long intpart;
599     long fracpart;
600
601     if (max < 0)
602         max = 6;
603     ufvalue = abs_val(fvalue);
604     if (fvalue < 0)
605         signvalue = '-';
606     else if (flags & DP_F_PLUS)
607         signvalue = '+';
608     else if (flags & DP_F_SPACE)
609         signvalue = ' ';
610
611     intpart = (long)ufvalue;
612
613     /* sorry, we only support 9 digits past the decimal because of our
614        conversion method */
615     if (max > 9)
616         max = 9;
617
618     /* we "cheat" by converting the fractional part to integer by
619        multiplying by a factor of 10 */
620     fracpart = round((pow10(max)) * (ufvalue - intpart));
621
622     if (fracpart >= pow10(max)) {
623         intpart++;
624         fracpart -= (long)pow10(max);
625     }
626
627     /* convert integer part */
628     do {
629         iconvert[iplace++] =
630             (caps ? "0123456789ABCDEF"
631               : "0123456789abcdef")[intpart % 10];
632         intpart = (intpart / 10);
633     } while (intpart && (iplace < 20));
634     if (iplace == 20)
635         iplace--;
636     iconvert[iplace] = 0;
637
638     /* convert fractional part */
639     do {
640         fconvert[fplace++] =
641             (caps ? "0123456789ABCDEF"
642               : "0123456789abcdef")[fracpart % 10];
643         fracpart = (fracpart / 10);
644     } while (fracpart && (fplace < 20));
645     if (fplace == 20)
646         fplace--;
647     fconvert[fplace] = 0;
648
649     /* -1 for decimal point, another -1 if we are printing a sign */
650     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
651     zpadlen = max - fplace;
652     if (zpadlen < 0)
653         zpadlen = 0;
654     if (padlen < 0)
655         padlen = 0;
656     if (flags & DP_F_MINUS)
657         padlen = -padlen;
658
659     if ((flags & DP_F_ZERO) && (padlen > 0)) {
660         if (signvalue) {
661             dopr_outch(buffer, currlen, maxlen, signvalue);
662             --padlen;
663             signvalue = 0;
664         }
665         while (padlen > 0) {
666             dopr_outch(buffer, currlen, maxlen, '0');
667             --padlen;
668         }
669     }
670     while (padlen > 0) {
671         dopr_outch(buffer, currlen, maxlen, ' ');
672         --padlen;
673     }
674     if (signvalue)
675         dopr_outch(buffer, currlen, maxlen, signvalue);
676
677     while (iplace > 0)
678         dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
679
680     /*
681      * Decimal point. This should probably use locale to find the correct
682      * char to print out.
683      */
684     if (max > 0) {
685         dopr_outch(buffer, currlen, maxlen, '.');
686
687         while (fplace > 0)
688             dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
689     }
690     while (zpadlen > 0) {
691         dopr_outch(buffer, currlen, maxlen, '0');
692         --zpadlen;
693     }
694
695     while (padlen < 0) {
696         dopr_outch(buffer, currlen, maxlen, ' ');
697         ++padlen;
698     }
699 }
700
701 static void
702 dopr_outch(
703     char *buffer,
704     size_t *currlen,
705     size_t maxlen,
706     int c)
707 {
708     if (*currlen < maxlen)
709         buffer[(*currlen)++] = (char)c;
710     return;
711 }