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