b11b501512b7470a6563a7c705cb430f67378a36
[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 <assert.h>
68 #include <limits.h>
69 #include "cryptlib.h"
70 #ifndef NO_SYS_TYPES_H
71 #include <sys/types.h>
72 #endif
73 #include <openssl/bio.h>
74
75 #ifdef BN_LLONG
76 # ifndef HAVE_LONG_LONG
77 #  define HAVE_LONG_LONG 1
78 # endif
79 #endif
80
81 static void dopr (char *buffer, size_t maxlen, size_t *retlen,
82         const char *format, va_list args);
83 #ifdef USE_ALLOCATING_PRINT
84 static void doapr (char **buffer, size_t *retlen,
85         const char *format, va_list args);
86 #endif
87
88 int BIO_printf (BIO *bio, ...)
89         {
90         va_list args;
91         char *format;
92         int ret;
93         size_t retlen;
94 #ifdef USE_ALLOCATING_PRINT
95         char *hugebuf;
96 #else
97         MS_STATIC char hugebuf[1024*2]; /* 10k in one chunk is the limit */
98 #endif
99
100         va_start(args, bio);
101         format=va_arg(args, char *);
102
103 #ifndef USE_ALLOCATING_PRINT
104         hugebuf[0]='\0';
105         dopr(hugebuf, sizeof(hugebuf), &retlen, format, args);
106 #else
107         hugebuf = NULL;
108         CRYPTO_push_info("doapr()");
109         doapr(&hugebuf, &retlen, format, args);
110         if (hugebuf)
111                 {
112 #endif
113                 ret=BIO_write(bio, hugebuf, (int)retlen);
114
115 #ifdef USE_ALLOCATING_PRINT
116                 Free(hugebuf);
117                 }
118         CRYPTO_pop_info();
119 #endif
120         va_end(args);
121         return(ret);
122         }
123
124 /*
125  * Copyright Patrick Powell 1995
126  * This code is based on code written by Patrick Powell <papowell@astart.com>
127  * It may be used for any purpose as long as this notice remains intact
128  * on all source code distributions.
129  */
130
131 /*
132  * This code contains numerious changes and enhancements which were
133  * made by lots of contributors over the last years to Patrick Powell's
134  * original code:
135  *
136  * o Patrick Powell <papowell@astart.com>      (1995)
137  * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
138  * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
139  * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
140  * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
141  * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
142  * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
143  */
144
145 #if HAVE_LONG_DOUBLE
146 #define LDOUBLE long double
147 #else
148 #define LDOUBLE double
149 #endif
150
151 #if HAVE_LONG_LONG
152 #define LLONG long long
153 #else
154 #define LLONG long
155 #endif
156
157 static void fmtstr     (void (*)(char **, size_t *, size_t *, int),
158                         char **, size_t *, size_t *, const char *, int, int,
159                         int);
160 static void fmtint     (void (*)(char **, size_t *, size_t *, int),
161                         char **, size_t *, size_t *, LLONG, int, int, int, int);
162 static void fmtfp      (void (*)(char **, size_t *, size_t *, int),
163                         char **, size_t *, size_t *, LDOUBLE, int, int, int);
164 #ifndef USE_ALLOCATING_PRINT
165 static int dopr_isbig (size_t, size_t);
166 static int dopr_copy (size_t);
167 static void dopr_outch (char **, size_t *, size_t *, int);
168 #else
169 static int doapr_isbig (size_t, size_t);
170 static int doapr_copy (size_t);
171 static void doapr_outch (char **, size_t *, size_t *, int);
172 #endif
173 static void _dopr(void (*)(char **, size_t *, size_t *, int),
174                   int (*)(size_t, size_t), int (*)(size_t),
175                   char **buffer, size_t *maxlen, size_t *retlen,
176                   const char *format, va_list args);
177
178 /* format read states */
179 #define DP_S_DEFAULT    0
180 #define DP_S_FLAGS      1
181 #define DP_S_MIN        2
182 #define DP_S_DOT        3
183 #define DP_S_MAX        4
184 #define DP_S_MOD        5
185 #define DP_S_CONV       6
186 #define DP_S_DONE       7
187
188 /* format flags - Bits */
189 #define DP_F_MINUS      (1 << 0)
190 #define DP_F_PLUS       (1 << 1)
191 #define DP_F_SPACE      (1 << 2)
192 #define DP_F_NUM        (1 << 3)
193 #define DP_F_ZERO       (1 << 4)
194 #define DP_F_UP         (1 << 5)
195 #define DP_F_UNSIGNED   (1 << 6)
196
197 /* conversion flags */
198 #define DP_C_SHORT      1
199 #define DP_C_LONG       2
200 #define DP_C_LDOUBLE    3
201 #define DP_C_LLONG      4
202
203 /* some handy macros */
204 #define char_to_int(p) (p - '0')
205 #define MAX(p,q) ((p >= q) ? p : q)
206
207 #ifndef USE_ALLOCATING_PRINT
208 static void
209 dopr(
210     char *buffer,
211     size_t maxlen,
212     size_t *retlen,
213     const char *format,
214     va_list args)
215 {
216     _dopr(dopr_outch, dopr_isbig, dopr_copy,
217           &buffer, &maxlen, retlen, format, args);
218 }
219
220 #else
221 static void
222 doapr(
223     char **buffer,
224     size_t *retlen,
225     const char *format,
226     va_list args)
227 {
228     size_t dummy_maxlen = 0;
229     _dopr(doapr_outch, doapr_isbig, doapr_copy,
230           buffer, &dummy_maxlen, retlen, format, args);
231 }
232 #endif
233
234 static void
235 _dopr(
236     void (*outch_fn)(char **, size_t *, size_t *, int),
237     int (*isbig_fn)(size_t, size_t),
238     int (*copy_fn)(size_t),
239     char **buffer,
240     size_t *maxlen,
241     size_t *retlen,
242     const char *format,
243     va_list args)
244 {
245     char ch;
246     LLONG value;
247     LDOUBLE fvalue;
248     char *strvalue;
249     int min;
250     int max;
251     int state;
252     int flags;
253     int cflags;
254     size_t currlen;
255
256     state = DP_S_DEFAULT;
257     flags = currlen = cflags = min = 0;
258     max = -1;
259     ch = *format++;
260
261     while (state != DP_S_DONE) {
262         if ((ch == '\0') || (*isbig_fn)(currlen, *maxlen))
263             state = DP_S_DONE;
264
265         switch (state) {
266         case DP_S_DEFAULT:
267             if (ch == '%')
268                 state = DP_S_FLAGS;
269             else
270                 (*outch_fn)(buffer, &currlen, maxlen, ch);
271             ch = *format++;
272             break;
273         case DP_S_FLAGS:
274             switch (ch) {
275             case '-':
276                 flags |= DP_F_MINUS;
277                 ch = *format++;
278                 break;
279             case '+':
280                 flags |= DP_F_PLUS;
281                 ch = *format++;
282                 break;
283             case ' ':
284                 flags |= DP_F_SPACE;
285                 ch = *format++;
286                 break;
287             case '#':
288                 flags |= DP_F_NUM;
289                 ch = *format++;
290                 break;
291             case '0':
292                 flags |= DP_F_ZERO;
293                 ch = *format++;
294                 break;
295             default:
296                 state = DP_S_MIN;
297                 break;
298             }
299             break;
300         case DP_S_MIN:
301             if (isdigit((unsigned char)ch)) {
302                 min = 10 * min + char_to_int(ch);
303                 ch = *format++;
304             } else if (ch == '*') {
305                 min = va_arg(args, int);
306                 ch = *format++;
307                 state = DP_S_DOT;
308             } else
309                 state = DP_S_DOT;
310             break;
311         case DP_S_DOT:
312             if (ch == '.') {
313                 state = DP_S_MAX;
314                 ch = *format++;
315             } else
316                 state = DP_S_MOD;
317             break;
318         case DP_S_MAX:
319             if (isdigit((unsigned char)ch)) {
320                 if (max < 0)
321                     max = 0;
322                 max = 10 * max + char_to_int(ch);
323                 ch = *format++;
324             } else if (ch == '*') {
325                 max = va_arg(args, int);
326                 ch = *format++;
327                 state = DP_S_MOD;
328             } else
329                 state = DP_S_MOD;
330             break;
331         case DP_S_MOD:
332             switch (ch) {
333             case 'h':
334                 cflags = DP_C_SHORT;
335                 ch = *format++;
336                 break;
337             case 'l':
338                 if (*format == 'l') {
339                     cflags = DP_C_LLONG;
340                     format++;
341                 } else
342                     cflags = DP_C_LONG;
343                 ch = *format++;
344                 break;
345             case 'q':
346                 cflags = DP_C_LLONG;
347                 ch = *format++;
348                 break;
349             case 'L':
350                 cflags = DP_C_LDOUBLE;
351                 ch = *format++;
352                 break;
353             default:
354                 break;
355             }
356             state = DP_S_CONV;
357             break;
358         case DP_S_CONV:
359             switch (ch) {
360             case 'd':
361             case 'i':
362                 switch (cflags) {
363                 case DP_C_SHORT:
364                     value = (short int)va_arg(args, int);
365                     break;
366                 case DP_C_LONG:
367                     value = va_arg(args, long int);
368                     break;
369                 case DP_C_LLONG:
370                     value = va_arg(args, LLONG);
371                     break;
372                 default:
373                     value = va_arg(args, int);
374                     break;
375                 }
376                 fmtint(outch_fn, buffer, &currlen, maxlen,
377                        value, 10, min, max, flags);
378                 break;
379             case 'X':
380                 flags |= DP_F_UP;
381                 /* FALLTHROUGH */
382             case 'x':
383             case 'o':
384             case 'u':
385                 flags |= DP_F_UNSIGNED;
386                 switch (cflags) {
387                 case DP_C_SHORT:
388                     value = (unsigned short int)va_arg(args, unsigned int);
389                     break;
390                 case DP_C_LONG:
391                     value = (LLONG) va_arg(args,
392                         unsigned long int);
393                     break;
394                 case DP_C_LLONG:
395                     value = va_arg(args, unsigned LLONG);
396                     break;
397                 default:
398                     value = (LLONG) va_arg(args,
399                         unsigned int);
400                     break;
401                 }
402                 fmtint(outch_fn, buffer, &currlen, maxlen, value,
403                        ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
404                        min, max, flags);
405                 break;
406             case 'f':
407                 if (cflags == DP_C_LDOUBLE)
408                     fvalue = va_arg(args, LDOUBLE);
409                 else
410                     fvalue = va_arg(args, double);
411                 fmtfp(outch_fn, buffer, &currlen, maxlen,
412                       fvalue, min, max, flags);
413                 break;
414             case 'E':
415                 flags |= DP_F_UP;
416             case 'e':
417                 if (cflags == DP_C_LDOUBLE)
418                     fvalue = va_arg(args, LDOUBLE);
419                 else
420                     fvalue = va_arg(args, double);
421                 break;
422             case 'G':
423                 flags |= DP_F_UP;
424             case 'g':
425                 if (cflags == DP_C_LDOUBLE)
426                     fvalue = va_arg(args, LDOUBLE);
427                 else
428                     fvalue = va_arg(args, double);
429                 break;
430             case 'c':
431                 (*outch_fn)(buffer, &currlen, maxlen,
432                     va_arg(args, int));
433                 break;
434             case 's':
435                 strvalue = va_arg(args, char *);
436                 if (max < 0)
437                     max = (*copy_fn)(*maxlen);
438                 fmtstr(outch_fn, buffer, &currlen, maxlen, strvalue,
439                        flags, min, max);
440                 break;
441             case 'p':
442                 value = (long)va_arg(args, void *);
443                 fmtint(outch_fn, buffer, &currlen, maxlen,
444                     value, 16, min, max, flags);
445                 break;
446             case 'n': /* XXX */
447                 if (cflags == DP_C_SHORT) {
448                     short int *num;
449                     num = va_arg(args, short int *);
450                     *num = currlen;
451                 } else if (cflags == DP_C_LONG) { /* XXX */
452                     long int *num;
453                     num = va_arg(args, long int *);
454                     *num = (long int) currlen;
455                 } else if (cflags == DP_C_LLONG) { /* XXX */
456                     LLONG *num;
457                     num = va_arg(args, LLONG *);
458                     *num = (LLONG) currlen;
459                 } else {
460                     int    *num;
461                     num = va_arg(args, int *);
462                     *num = currlen;
463                 }
464                 break;
465             case '%':
466                 (*outch_fn)(buffer, &currlen, maxlen, ch);
467                 break;
468             case 'w':
469                 /* not supported yet, treat as next char */
470                 ch = *format++;
471                 break;
472             default:
473                 /* unknown, skip */
474                 break;
475             }
476             ch = *format++;
477             state = DP_S_DEFAULT;
478             flags = cflags = min = 0;
479             max = -1;
480             break;
481         case DP_S_DONE:
482             break;
483         default:
484             break;
485         }
486     }
487     if (currlen >= *maxlen - 1)
488         currlen = *maxlen - 1;
489     (*buffer)[currlen] = '\0';
490     *retlen = currlen;
491     return;
492 }
493
494 static void
495 fmtstr(
496     void (*outch_fn)(char **, size_t *, size_t *, int),
497     char **buffer,
498     size_t *currlen,
499     size_t *maxlen,
500     const char *value,
501     int flags,
502     int min,
503     int max)
504 {
505     int padlen, strln;
506     int cnt = 0;
507
508     if (value == 0)
509         value = "<NULL>";
510     for (strln = 0; value[strln]; ++strln)
511         ;
512     padlen = min - strln;
513     if (padlen < 0)
514         padlen = 0;
515     if (flags & DP_F_MINUS)
516         padlen = -padlen;
517
518     while ((padlen > 0) && (cnt < max)) {
519         (*outch_fn)(buffer, currlen, maxlen, ' ');
520         --padlen;
521         ++cnt;
522     }
523     while (*value && (cnt < max)) {
524         (*outch_fn)(buffer, currlen, maxlen, *value++);
525         ++cnt;
526     }
527     while ((padlen < 0) && (cnt < max)) {
528         (*outch_fn)(buffer, currlen, maxlen, ' ');
529         ++padlen;
530         ++cnt;
531     }
532 }
533
534 static void
535 fmtint(
536     void (*outch_fn)(char **, size_t *, size_t *, int),
537     char **buffer,
538     size_t *currlen,
539     size_t *maxlen,
540     LLONG value,
541     int base,
542     int min,
543     int max,
544     int flags)
545 {
546     int signvalue = 0;
547     unsigned LLONG uvalue;
548     char convert[20];
549     int place = 0;
550     int spadlen = 0;
551     int zpadlen = 0;
552     int caps = 0;
553
554     if (max < 0)
555         max = 0;
556     uvalue = value;
557     if (!(flags & DP_F_UNSIGNED)) {
558         if (value < 0) {
559             signvalue = '-';
560             uvalue = -value;
561         } else if (flags & DP_F_PLUS)
562             signvalue = '+';
563         else if (flags & DP_F_SPACE)
564             signvalue = ' ';
565     }
566     if (flags & DP_F_UP)
567         caps = 1;
568     do {
569         convert[place++] =
570             (caps ? "0123456789ABCDEF" : "0123456789abcdef")
571             [uvalue % (unsigned) base];
572         uvalue = (uvalue / (unsigned) base);
573     } while (uvalue && (place < 20));
574     if (place == 20)
575         place--;
576     convert[place] = 0;
577
578     zpadlen = max - place;
579     spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
580     if (zpadlen < 0)
581         zpadlen = 0;
582     if (spadlen < 0)
583         spadlen = 0;
584     if (flags & DP_F_ZERO) {
585         zpadlen = MAX(zpadlen, spadlen);
586         spadlen = 0;
587     }
588     if (flags & DP_F_MINUS)
589         spadlen = -spadlen;
590
591     /* spaces */
592     while (spadlen > 0) {
593         (*outch_fn)(buffer, currlen, maxlen, ' ');
594         --spadlen;
595     }
596
597     /* sign */
598     if (signvalue)
599         (*outch_fn)(buffer, currlen, maxlen, signvalue);
600
601     /* zeros */
602     if (zpadlen > 0) {
603         while (zpadlen > 0) {
604             (*outch_fn)(buffer, currlen, maxlen, '0');
605             --zpadlen;
606         }
607     }
608     /* digits */
609     while (place > 0)
610         (*outch_fn)(buffer, currlen, maxlen, convert[--place]);
611
612     /* left justified spaces */
613     while (spadlen < 0) {
614         (*outch_fn)(buffer, currlen, maxlen, ' ');
615         ++spadlen;
616     }
617     return;
618 }
619
620 static LDOUBLE
621 abs_val(LDOUBLE value)
622 {
623     LDOUBLE result = value;
624     if (value < 0)
625         result = -value;
626     return result;
627 }
628
629 static LDOUBLE
630 pow10(int exp)
631 {
632     LDOUBLE result = 1;
633     while (exp) {
634         result *= 10;
635         exp--;
636     }
637     return result;
638 }
639
640 static long
641 round(LDOUBLE value)
642 {
643     long intpart;
644     intpart = (long) value;
645     value = value - intpart;
646     if (value >= 0.5)
647         intpart++;
648     return intpart;
649 }
650
651 static void
652 fmtfp(
653     void (*outch_fn)(char **, size_t *, size_t *, int),
654     char **buffer,
655     size_t *currlen,
656     size_t *maxlen,
657     LDOUBLE fvalue,
658     int min,
659     int max,
660     int flags)
661 {
662     int signvalue = 0;
663     LDOUBLE ufvalue;
664     char iconvert[20];
665     char fconvert[20];
666     int iplace = 0;
667     int fplace = 0;
668     int padlen = 0;
669     int zpadlen = 0;
670     int caps = 0;
671     long intpart;
672     long fracpart;
673
674     if (max < 0)
675         max = 6;
676     ufvalue = abs_val(fvalue);
677     if (fvalue < 0)
678         signvalue = '-';
679     else if (flags & DP_F_PLUS)
680         signvalue = '+';
681     else if (flags & DP_F_SPACE)
682         signvalue = ' ';
683
684     intpart = (long)ufvalue;
685
686     /* sorry, we only support 9 digits past the decimal because of our
687        conversion method */
688     if (max > 9)
689         max = 9;
690
691     /* we "cheat" by converting the fractional part to integer by
692        multiplying by a factor of 10 */
693     fracpart = round((pow10(max)) * (ufvalue - intpart));
694
695     if (fracpart >= pow10(max)) {
696         intpart++;
697         fracpart -= (long)pow10(max);
698     }
699
700     /* convert integer part */
701     do {
702         iconvert[iplace++] =
703             (caps ? "0123456789ABCDEF"
704               : "0123456789abcdef")[intpart % 10];
705         intpart = (intpart / 10);
706     } while (intpart && (iplace < 20));
707     if (iplace == 20)
708         iplace--;
709     iconvert[iplace] = 0;
710
711     /* convert fractional part */
712     do {
713         fconvert[fplace++] =
714             (caps ? "0123456789ABCDEF"
715               : "0123456789abcdef")[fracpart % 10];
716         fracpart = (fracpart / 10);
717     } while (fracpart && (fplace < 20));
718     if (fplace == 20)
719         fplace--;
720     fconvert[fplace] = 0;
721
722     /* -1 for decimal point, another -1 if we are printing a sign */
723     padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
724     zpadlen = max - fplace;
725     if (zpadlen < 0)
726         zpadlen = 0;
727     if (padlen < 0)
728         padlen = 0;
729     if (flags & DP_F_MINUS)
730         padlen = -padlen;
731
732     if ((flags & DP_F_ZERO) && (padlen > 0)) {
733         if (signvalue) {
734             (*outch_fn)(buffer, currlen, maxlen, signvalue);
735             --padlen;
736             signvalue = 0;
737         }
738         while (padlen > 0) {
739             (*outch_fn)(buffer, currlen, maxlen, '0');
740             --padlen;
741         }
742     }
743     while (padlen > 0) {
744         (*outch_fn)(buffer, currlen, maxlen, ' ');
745         --padlen;
746     }
747     if (signvalue)
748         (*outch_fn)(buffer, currlen, maxlen, signvalue);
749
750     while (iplace > 0)
751         (*outch_fn)(buffer, currlen, maxlen, iconvert[--iplace]);
752
753     /*
754      * Decimal point. This should probably use locale to find the correct
755      * char to print out.
756      */
757     if (max > 0) {
758         (*outch_fn)(buffer, currlen, maxlen, '.');
759
760         while (fplace > 0)
761             (*outch_fn)(buffer, currlen, maxlen, fconvert[--fplace]);
762     }
763     while (zpadlen > 0) {
764         (*outch_fn)(buffer, currlen, maxlen, '0');
765         --zpadlen;
766     }
767
768     while (padlen < 0) {
769         (*outch_fn)(buffer, currlen, maxlen, ' ');
770         ++padlen;
771     }
772 }
773
774 static int
775 dopr_copy(
776     size_t len)
777 {
778     return len;
779 }
780
781 #ifdef USE_ALLOCATING_PRINT
782 static int
783 doapr_copy(
784     size_t len)
785 {
786     /* Return as high an integer as possible */
787     return INT_MAX;
788 }
789 #endif
790
791 static int
792 dopr_isbig(
793     size_t currlen,
794     size_t maxlen)
795 {
796     return currlen > maxlen;
797 }
798
799 #ifdef USE_ALLOCATING_PRINT
800 static int
801 doapr_isbig(
802     size_t currlen,
803     size_t maxlen)
804 {
805     return 0;
806 }
807 #endif
808
809 static void
810 dopr_outch(
811     char **buffer,
812     size_t *currlen,
813     size_t *maxlen,
814     int c)
815 {
816     if (*currlen < *maxlen)
817         (*buffer)[(*currlen)++] = (char)c;
818     return;
819 }
820
821 #ifdef USE_ALLOCATING_PRINT
822 static void
823 doapr_outch(
824     char **buffer,
825     size_t *currlen,
826     size_t *maxlen,
827     int c)
828 {
829     if (*buffer == NULL) {
830         if (*maxlen == 0)
831             *maxlen = 1024;
832         *buffer = Malloc(*maxlen);
833     }
834     while (*currlen >= *maxlen) {
835         *maxlen += 1024;
836         *buffer = Realloc(*buffer, *maxlen);
837     }
838     /* What to do if *buffer is NULL? */
839     assert(*buffer != NULL);
840
841     (*buffer)[(*currlen)++] = (char)c;
842     return;
843 }
844 #endif