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