1246229a632dc865f74f5623ec998240ff95e10d
[kopensolaris-gnu/glibc.git] / stdio / vfprintf.c
1 /* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ctype.h>
20 #include <errno.h>
21 #include <float.h>
22 #include <limits.h>
23 #include <math.h>
24 #include <printf.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <printf.h>
29 #include <stddef.h>
30 #include "_itoa.h"
31 #include "../locale/localeinfo.h"
32
33 /* Include the shared code for parsing the format string.  */
34 #include "printf-parse.h"
35
36
37 /* This function from the GNU C library is also used in libio.
38    To compile for use in libio, compile with -DUSE_IN_LIBIO.  */
39
40 #ifdef USE_IN_LIBIO
41 /* This code is for use in libio.  */
42 #include <libioP.h>
43 #define PUT(f, s, n)    _IO_sputn (f, s, n)
44 #define PAD(padchar)                                                          \
45   if (specs[cnt].info.width > 0)                                              \
46     done += _IO_padn (s, padchar, specs[cnt].info.width)
47 #define PUTC(c, f)      _IO_putc (c, f)
48 #define vfprintf        _IO_vfprintf
49 #define size_t          _IO_size_t
50 #define FILE            _IO_FILE
51 #define va_list         _IO_va_list
52 #undef  BUFSIZ
53 #define BUFSIZ          _IO_BUFSIZ
54 #define ARGCHECK(s, format)                                                   \
55   do                                                                          \
56     {                                                                         \
57       /* Check file argument for consistence.  */                             \
58       CHECK_FILE (s, -1);                                                     \
59       if (s->_flags & _IO_NO_WRITES || format == NULL)                        \
60         {                                                                     \
61           MAYBE_SET_EINVAL;                                                   \
62           return -1;                                                          \
63         }                                                                     \
64     } while (0)
65 #define UNBUFFERED_P(s) ((s)->_IO_file_flags & _IO_UNBUFFERED)
66 #else /* ! USE_IN_LIBIO */
67 /* This code is for use in the GNU C library.  */
68 #include <stdio.h>
69 #define PUTC(c, f)      putc (c, f)
70 #define PUT(f, s, n)    fwrite (s, 1, n, f)
71 ssize_t __printf_pad __P ((FILE *, char pad, size_t n));
72 #define PAD(padchar)                                                          \
73   if (specs[cnt].info.width > 0)                                              \
74     { if (__printf_pad (s, padchar, specs[cnt].info.width) == -1)             \
75         return -1; else done += specs[cnt].info.width; }
76 #define ARGCHECK(s, format) \
77   do                                                                          \
78     {                                                                         \
79       /* Check file argument for consistence.  */                             \
80       if (!__validfp(s) || !s->__mode.__write || format == NULL)              \
81         {                                                                     \
82           errno = EINVAL;                                                     \
83           return -1;                                                          \
84         }                                                                     \
85       if (!s->__seen)                                                         \
86         {                                                                     \
87           if (__flshfp (s, EOF) == EOF)                                       \
88             return -1;                                                        \
89         }                                                                     \
90     } while (0)
91 #define UNBUFFERED_P(s) ((s)->__buffer == NULL)
92 #endif /* USE_IN_LIBIO */
93
94
95 #define outchar(x)                                                            \
96   do                                                                          \
97     {                                                                         \
98       register const int outc = (x);                                          \
99       if (putc (outc, s) == EOF)                                              \
100         return -1;                                                            \
101       else                                                                    \
102         ++done;                                                               \
103     } while (0)
104
105 #define outstring(string, len)                                                \
106   do                                                                          \
107     {                                                                         \
108       if (len > 20)                                                           \
109         {                                                                     \
110           if (PUT (s, string, len) != len)                                    \
111             return -1;                                                        \
112           done += len;                                                        \
113         }                                                                     \
114       else                                                                    \
115         {                                                                     \
116           register const char *cp = string;                                   \
117           register int l = len;                                               \
118           while (l-- > 0)                                                     \
119             outchar (*cp++);                                                  \
120         }                                                                     \
121     } while (0)
122
123 /* Helper function to provide temporary buffering for unbuffered streams.  */
124 static int buffered_vfprintf __P ((FILE *stream, const char *fmt, va_list));
125
126 static printf_function printf_unknown;
127
128 extern printf_function **__printf_function_table;
129
130 static char *group_number __P ((char *, char *, const char *, wchar_t));
131
132
133 int
134 vfprintf (s, format, ap)
135     register FILE *s;
136     const char *format;
137     va_list ap;
138 {
139   /* The character used as thousands separator.  */
140   wchar_t thousands_sep;
141
142   /* The string describing the size of groups of digits.  */
143   const char *grouping;
144
145   /* Array with information about the needed arguments.  This has to be
146      dynamically extendable.  */
147   size_t nspecs;
148   size_t nspecs_max;
149   struct printf_spec *specs;
150
151   /* The number of arguments the format string requests.  This will
152      determine the size of the array needed to store the argument
153      attributes.  */
154   size_t nargs;
155   int *args_type;
156   union printf_arg *args_value;
157
158   /* Positional parameters refer to arguments directly.  This could also
159      determine the maximum number of arguments.  Track the maximum number.  */
160   size_t max_ref_arg;
161
162   /* End of leading constant string.  */
163   const char *lead_str_end;
164
165   /* Number of characters written.  */
166   register size_t done = 0;
167
168   /* Running pointer through format string.  */
169   const char *f;
170
171   /* Just a counter.  */
172   int cnt;
173
174   ARGCHECK (s, format);
175
176   if (UNBUFFERED_P (s))
177     /* Use a helper function which will allocate a local temporary buffer
178        for the stream and then call us again.  */
179     return buffered_vfprintf (s, format, ap);
180
181   /* Reset multibyte characters to their initial state.  */
182   (void) mblen ((char *) NULL, 0);
183
184   /* Figure out the thousands separator character.  */
185   if (mbtowc (&thousands_sep, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
186               strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
187     thousands_sep = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
188   grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
189   if (*grouping == '\0' || *grouping == CHAR_MAX || thousands_sep == L'\0')
190     grouping = NULL;
191
192   nspecs_max = 32;              /* A more or less arbitrary start value.  */
193   specs = alloca (nspecs_max * sizeof (struct printf_spec));
194   nspecs = 0;
195   nargs = 0;
196   max_ref_arg = 0;
197
198   /* Find the first format specifier.  */
199   lead_str_end = find_spec (format);
200
201   for (f = lead_str_end; *f != '\0'; f = specs[nspecs++].next_fmt)
202     {
203       if (nspecs >= nspecs_max)
204         {
205           /* Extend the array of format specifiers.  */
206           struct printf_spec *old = specs;
207
208           nspecs_max *= 2;
209           specs = alloca (nspecs_max * sizeof (struct printf_spec));
210           if (specs == &old[nspecs])
211             /* Stack grows up, OLD was the last thing allocated; extend it.  */
212             nspecs_max += nspecs_max / 2;
213           else
214             {
215               /* Copy the old array's elements to the new space.  */
216               memcpy (specs, old, nspecs * sizeof (struct printf_spec));
217               if (old == &specs[nspecs])
218                 /* Stack grows down, OLD was just below the new SPECS.
219                    We can use that space when the new space runs out.  */
220                 nspecs_max += nspecs_max / 2;
221             }
222         }
223
224       /* Parse the format specifier.  */
225       nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg);
226     }
227
228   /* Determine the number of arguments the format string consumes.  */
229   nargs = MAX (nargs, max_ref_arg);
230
231   /* Allocate memory for the argument descriptions.  */
232   args_type = alloca (nargs * sizeof (int));
233   args_value = alloca (nargs * sizeof (union printf_arg));
234
235   /* XXX Could do sanity check here:
236      Initialize args_type elts to zero.
237      If any is still zero after this loop, format is invalid.  */
238
239   /* Fill in the types of all the arguments.  */
240   for (cnt = 0; cnt < nspecs; ++cnt)
241     {
242       /* If the width is determined by an argument this is an int.  */ 
243       if (specs[cnt].width_arg != -1)
244         args_type[specs[cnt].width_arg] = PA_INT;
245
246       /* If the precision is determined by an argument this is an int.  */ 
247       if (specs[cnt].prec_arg != -1)
248         args_type[specs[cnt].prec_arg] = PA_INT;
249
250       switch (specs[cnt].ndata_args)
251         {
252         case 0:                 /* No arguments.  */
253           break;
254         case 1:                 /* One argument; we already have the type.  */
255           args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
256           break;
257         default:
258           /* We have more than one argument for this format spec.  We must
259              call the arginfo function again to determine all the types.  */
260           (void) (*__printf_arginfo_table[specs[cnt].info.spec])
261             (&specs[cnt].info,
262              specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]);
263           break;
264         }
265     }
266
267   /* Now we know all the types and the order.  Fill in the argument values.  */
268   for (cnt = 0; cnt < nargs; ++cnt)
269     switch (args_type[cnt])
270       {
271 #define T(tag, mem, type)                                                     \
272       case tag:                                                               \
273         args_value[cnt].mem = va_arg (ap, type);                              \
274         break
275
276         T (PA_CHAR, pa_char, int); /* Promoted.  */
277         T (PA_INT|PA_FLAG_SHORT, pa_short_int, int); /* Promoted.  */
278         T (PA_INT, pa_int, int);
279         T (PA_INT|PA_FLAG_LONG, pa_long_int, long int);
280         T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
281         T (PA_FLOAT, pa_float, double); /* Promoted.  */
282         T (PA_DOUBLE, pa_double, double);
283         T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double);
284         T (PA_STRING, pa_string, const char *);
285         T (PA_POINTER, pa_pointer, void *);
286 #undef T
287       default:
288         if ((args_type[cnt] & PA_FLAG_PTR) != 0)
289           args_value[cnt].pa_pointer = va_arg (ap, void *);
290         break;
291       }
292
293   /* Write the literal text before the first format.  */
294   outstring (format, lead_str_end - format);
295
296   /* Now walk through all format specifiers and process them.  */
297   for (cnt = 0; cnt < nspecs; ++cnt)
298     {
299       printf_function *function; /* Auxiliary function to do output.  */
300       int is_neg;               /* Decimal integer is negative.  */
301       int base;                 /* Base of a number to be written.  */
302       unsigned long long int num; /* Integral number to be written.  */
303       const char *str;          /* String to be written.  */
304       char errorbuf[1024];      /* Buffer sometimes used by %m.  */
305
306       if (specs[cnt].width_arg != -1)
307         {
308           /* Extract the field width from an argument.  */
309           specs[cnt].info.width = args_value[specs[cnt].width_arg].pa_int;
310
311           if (specs[cnt].info.width < 0)
312             /* If the width value is negative left justification is selected
313                and the value is taken as being positive.  */
314             {
315               specs[cnt].info.width = -specs[cnt].info.width;
316               specs[cnt].info.left = 1;
317             }
318         }
319
320       if (specs[cnt].prec_arg != -1)
321         {
322           /* Extract the precision from an argument.  */
323           specs[cnt].info.prec = args_value[specs[cnt].prec_arg].pa_int;
324
325           if (specs[cnt].info.prec < 0)
326             /* If the precision is negative the precision is omitted.  */
327             specs[cnt].info.prec = -1;
328         }
329
330       /* Check for a user-defined handler for this spec.  */
331       function = (__printf_function_table == NULL ? NULL :
332                   __printf_function_table[specs[cnt].info.spec]);
333
334       if (function != NULL)
335       use_function:             /* Built-in formats with helpers use this.  */
336         {
337           int function_done;
338           unsigned int i;
339           const void *ptr[specs[cnt].ndata_args];
340
341           /* Fill in an array of pointers to the argument values.  */
342           for (i = 0; i < specs[cnt].ndata_args; ++i)
343             ptr[i] = &args_value[specs[cnt].data_arg + i];
344
345           /* Call the function.  */
346           function_done = (*function) (s, &specs[cnt].info, ptr);
347
348           /* If an error occured don't do any further work.  */
349           if (function_done < 0)
350             return -1;
351
352           done += function_done;
353         }
354       else
355         switch (specs[cnt].info.spec)
356           {
357           case '%':
358             /* Write a literal "%".  */
359             outchar ('%');
360             break;
361           case 'i':
362           case 'd':
363             {
364               long long int signed_num;
365
366               /* Decimal integer.  */
367               base = 10;
368               if (specs[cnt].info.is_longlong)
369                 signed_num = args_value[specs[cnt].data_arg].pa_long_long_int;
370               else if (specs[cnt].info.is_long)
371                 signed_num = args_value[specs[cnt].data_arg].pa_long_int;
372               else if (!specs[cnt].info.is_short)
373                 signed_num = args_value[specs[cnt].data_arg].pa_int;
374               else
375                 signed_num = args_value[specs[cnt].data_arg].pa_short_int;
376
377               is_neg = signed_num < 0;
378               num = is_neg ? (- signed_num) : signed_num;
379               goto number;
380             }
381
382           case 'u':
383             /* Decimal unsigned integer.  */
384             base = 10;
385             goto unsigned_number;
386
387           case 'o':
388             /* Octal unsigned integer.  */
389             base = 8;
390             goto unsigned_number;
391
392           case 'X':
393             /* Hexadecimal unsigned integer.  */
394           case 'x':
395             /* Hex with lower-case digits.  */
396             base = 16;
397
398           unsigned_number:
399             /* Unsigned number of base BASE.  */
400
401             if (specs[cnt].info.is_longlong)
402               num = args_value[specs[cnt].data_arg].pa_u_long_long_int;
403             else if (specs[cnt].info.is_long)
404               num = args_value[specs[cnt].data_arg].pa_u_long_int;
405             else if (!specs[cnt].info.is_short)
406               num = args_value[specs[cnt].data_arg].pa_u_int;
407             else
408               num = args_value[specs[cnt].data_arg].pa_u_short_int;
409
410             /* ANSI only specifies the `+' and
411                ` ' flags for signed conversions.  */
412             is_neg = 0;
413             specs[cnt].info.showsign = 0;
414             specs[cnt].info.space = 0;
415
416           number:
417             /* Number of base BASE.  */
418             {
419               char work[BUFSIZ];
420               char *const workend = &work[sizeof(work) - 1];
421               register char *w;
422
423               /* Supply a default precision if none was given.  */
424               if (specs[cnt].info.prec == -1)
425                 specs[cnt].info.prec = 1;
426
427               /* Put the number in WORK.  */
428               w = _itoa (num, workend + 1, base, specs[cnt].info.spec == 'X');
429               w -= 1;
430               if (specs[cnt].info.group && grouping)
431                 w = group_number (w, workend, grouping, thousands_sep);
432               specs[cnt].info.width -= workend - w;
433               specs[cnt].info.prec -= workend - w;
434
435               if (num != 0 && specs[cnt].info.alt && base == 8
436                   && specs[cnt].info.prec <= 0)
437                 {
438                   /* Add octal marker.  */
439                   *w-- = '0';
440                   --specs[cnt].info.width;
441                 }
442
443               if (specs[cnt].info.prec > 0)
444                 {
445                   /* Add zeros to the precision.  */
446                   specs[cnt].info.width -= specs[cnt].info.prec;
447                   while (specs[cnt].info.prec-- > 0)
448                     *w-- = '0';
449                 }
450
451               if (num != 0 && specs[cnt].info.alt && base == 16)
452                 /* Account for 0X hex marker.  */
453                 specs[cnt].info.width -= 2;
454
455               if (is_neg || specs[cnt].info.showsign || specs[cnt].info.space)
456                 --specs[cnt].info.width;
457
458               if (!specs[cnt].info.left && specs[cnt].info.pad == ' ')
459                 PAD (' ');
460
461               if (is_neg)
462                 outchar ('-');
463               else if (specs[cnt].info.showsign)
464                 outchar ('+');
465               else if (specs[cnt].info.space)
466                 outchar (' ');
467
468               if (num != 0 && specs[cnt].info.alt && base == 16)
469                 {
470                   outchar ('0');
471                   outchar (specs[cnt].info.spec);
472                 }
473
474               if (!specs[cnt].info.left && specs[cnt].info.pad == '0')
475                 PAD ('0');
476
477               /* Write the number.  */
478               while (++w <= workend)
479                 outchar (*w);
480
481               if (specs[cnt].info.left)
482                 PAD (' ');
483             }
484             break;
485
486           case 'e':
487           case 'E':
488           case 'f':
489           case 'g':
490           case 'G':
491             {
492               /* Floating-point number.  This is handled by printf_fp.c.  */
493               extern printf_function __printf_fp;
494               function = __printf_fp;
495               goto use_function;
496             }
497
498           case 'c':
499             /* Character.  */
500             if (!specs[cnt].info.left)
501               {
502                 --specs[cnt].info.width;
503                 PAD (' ');
504               }
505             outchar ((unsigned char) args_value[specs[cnt].data_arg].pa_char);
506             if (specs[cnt].info.left)
507               PAD (' ');
508             break;
509
510           case 's':
511             {
512               static const char null[] = "(null)";
513               size_t len;
514
515               str = args_value[specs[cnt].data_arg].pa_string;
516
517             string:
518
519               if (str == NULL)
520                 {
521                   /* Write "(null)" if there's space.  */
522                   if (specs[cnt].info.prec == -1
523                       || specs[cnt].info.prec >= (int) sizeof (null) - 1)
524                     {
525                       str = null;
526                       len = sizeof (null) - 1;
527                     }
528                   else
529                     {
530                       str = "";
531                       len = 0;
532                     }
533                 }
534               else if (specs[cnt].info.prec != -1)
535                 {
536                   const char *end = memchr (str, '\0', specs[cnt].info.prec);
537                   if (end)
538                     len = end - str;
539                   else
540                     len = strlen (str);
541                 }
542               else
543                 {
544                   len = strlen (str);
545
546                   if (specs[cnt].info.prec != -1
547                       && (size_t) specs[cnt].info.prec < len)
548                     /* Limit the length to the precision.  */
549                     len = specs[cnt].info.prec;
550                 }
551
552               specs[cnt].info.width -= len;
553
554               if (!specs[cnt].info.left)
555                 PAD (' ');
556               outstring (str, len);
557               if (specs[cnt].info.left)
558                 PAD (' ');
559             }
560             break;
561
562           case 'p':
563             /* Generic pointer.  */
564             {
565               const void *ptr;
566               ptr = args_value[specs[cnt].data_arg].pa_pointer;
567               if (ptr != NULL)
568                 {
569                   /* If the pointer is not NULL, write it as a %#x spec.  */
570                   base = 16;
571                   num = (unsigned long long int) (unsigned long int) ptr;
572                   is_neg = 0;
573                   specs[cnt].info.alt = 1;
574                   specs[cnt].info.spec = 'x';
575                   specs[cnt].info.group = 0;
576                   goto number;
577                 }
578               else
579                 {
580                   /* Write "(nil)" for a nil pointer.  */
581                   str = "(nil)";
582                   /* Make sure the full string "(nil)" is printed.  */
583                   if (specs[cnt].info.prec < 5)
584                     specs[cnt].info.prec = 5;
585                   goto string;
586                 }
587             }
588             break;
589
590           case 'n':
591             /* Answer the count of characters written.  */
592             if (specs[cnt].info.is_longlong)
593               *(long long int *) 
594                 args_value[specs[cnt].data_arg].pa_pointer = done;
595             else if (specs[cnt].info.is_long)
596               *(long int *) 
597                 args_value[specs[cnt].data_arg].pa_pointer = done;
598             else if (!specs[cnt].info.is_short)
599               *(int *) 
600                 args_value[specs[cnt].data_arg].pa_pointer = done;
601             else
602               *(short int *) 
603                 args_value[specs[cnt].data_arg].pa_pointer = done;
604             break;
605
606           case 'm':
607             {
608               extern char *_strerror_internal __P ((int, char buf[1024]));
609               str = _strerror_internal (errno, errorbuf);
610               goto string;
611             }
612
613           default:
614             /* Unrecognized format specifier.  */
615             function = printf_unknown;
616             goto use_function;
617           }
618
619       /* Write the following constant string.  */
620       outstring (specs[cnt].end_of_fmt,
621                  specs[cnt].next_fmt - specs[cnt].end_of_fmt);
622     }
623
624   return done;
625 }
626
627
628 /* Handle an unknown format specifier.  This prints out a canonicalized
629    representation of the format spec itself.  */
630
631 static int
632 printf_unknown (s, info, args)
633   FILE *s;
634   const struct printf_info *info;
635   const void **const args;
636 {
637   int done = 0;
638   char work[BUFSIZ];
639   char *const workend = &work[sizeof(work) - 1];
640   register char *w;
641
642   outchar ('%');
643
644   if (info->alt)
645     outchar ('#');
646   if (info->group)
647     outchar ('\'');
648   if (info->showsign)
649     outchar ('+');
650   else if (info->space)
651     outchar (' ');
652   if (info->left)
653     outchar ('-');
654   if (info->pad == '0')
655     outchar ('0');
656
657   if (info->width != 0)
658     {
659       w = _itoa (info->width, workend + 1, 10, 0);
660       while (++w <= workend)
661         outchar (*w);
662     }
663
664   if (info->prec != -1)
665     {
666       outchar ('.');
667       w = _itoa (info->prec, workend + 1, 10, 0);
668       while (++w <= workend)
669         outchar (*w);
670     }
671
672   if (info->spec != '\0')
673     outchar (info->spec);
674
675   return done;
676 }
677 \f
678 /* Group the digits according to the grouping rules of the current locale.
679    The interpretation of GROUPING is as in `struct lconv' from <locale.h>.  */
680
681 static char *
682 group_number (char *w, char *workend, const char *grouping,
683               wchar_t thousands_sep)
684 {
685   int len;
686   char *src, *s;
687
688   /* We treat all negative values like CHAR_MAX.  */
689
690   if (*grouping == CHAR_MAX || *grouping < 0)
691     /* No grouping should be done.  */
692     return w;
693
694   len = *grouping;
695
696   /* Copy existing string so that nothing gets overwritten.  */
697   src = (char *) alloca (workend - w);
698   memcpy (src, w + 1, workend - w);
699   s = &src[workend - w - 1];
700   w = workend;
701
702   /* Process all characters in the string.  */
703   while (s >= src)
704     {
705       *w-- = *s--;
706
707       if (--len == 0 && s >= src)
708         {
709           /* A new group begins.  */
710           *w-- = thousands_sep;
711
712           len = *grouping++;
713           if (*grouping == '\0')
714             /* The previous grouping repeats ad infinitum.  */
715             --grouping;
716           else if (*grouping == CHAR_MAX || *grouping < 0)
717             {
718               /* No further grouping to be done.
719                  Copy the rest of the number.  */
720               do
721                 *w-- = *s--;
722               while (s >= src);
723               break;
724             }
725         }
726     }
727   return w;
728 }
729 \f
730 #ifdef USE_IN_LIBIO
731 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
732 struct helper_file
733   {
734     struct _IO_FILE_plus _f;
735     _IO_FILE *_put_stream;
736   };
737
738 static int
739 _IO_helper_overflow (s, c)
740   _IO_FILE *s;
741   int c;
742 {
743   _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
744   int used = s->_IO_write_ptr - s->_IO_write_base;
745   if (used)
746     {
747       _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
748       s->_IO_write_ptr -= written;
749     }
750   return _IO_putc (c, s);
751 }
752
753 static const struct _IO_jump_t _IO_helper_jumps =
754   {
755     _IO_helper_overflow,
756     _IO_default_underflow,
757     _IO_default_xsputn,
758     _IO_default_xsgetn,
759     _IO_default_read,
760     _IO_default_write,
761     _IO_default_doallocate,
762     _IO_default_pbackfail,
763     _IO_default_setbuf,
764     _IO_default_sync,
765     _IO_default_finish,
766     _IO_default_close,
767     _IO_default_stat,
768     _IO_default_seek,
769     _IO_default_seekoff,
770     _IO_default_seekpos,
771     _IO_default_uflow
772   };
773
774 static int
775 buffered_vfprintf (s, format, args)
776   register _IO_FILE *s;
777   char const *format;
778   _IO_va_list args;
779 {
780   char buf[_IO_BUFSIZ];
781   struct helper_file helper;
782   register _IO_FILE *hp = (_IO_FILE *) &helper;
783   int result, to_flush;
784
785   /* Initialize helper.  */
786   helper._put_stream = s;
787   hp->_IO_write_base = buf;
788   hp->_IO_write_ptr = buf;
789   hp->_IO_write_end = buf + sizeof buf;
790   hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
791   hp->_jumps = (struct _IO_jump_t *) &_IO_helper_jumps;
792   
793   /* Now print to helper instead.  */
794   result = _IO_vfprintf (hp, format, args);
795
796   /* Now flush anything from the helper to the S. */
797   if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
798     {
799       if (_IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
800         return -1;
801     }
802
803   return result;
804 }
805
806 #else /* !USE_IN_LIBIO */
807
808 static int
809 buffered_vfprintf (s, format, args)
810   register FILE *s;
811   char const *format;
812   va_list args;
813 {
814   char buf[BUFSIZ];
815   int result;
816
817   s->__bufp = s->__buffer = buf;
818   s->__bufsize = sizeof buf;
819   s->__put_limit = s->__buffer + s->__bufsize;
820   s->__get_limit = s->__buffer;
821
822   /* Now use buffer to print.  */
823   result = vfprintf (s, format, args);
824
825   if (fflush (s) == EOF)
826     result = -1;
827   s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL;
828   s->__bufsize = 0;
829
830   return result;
831 }
832
833
834 /* Pads string with given number of a specified character.
835    This code is taken from iopadn.c of the GNU I/O library.  */
836 #define PADSIZE 16
837 static const char blanks[PADSIZE] =
838 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
839 static const char zeroes[PADSIZE] =
840 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
841
842 ssize_t
843 __printf_pad (s, pad, count)
844      FILE *s;
845      char pad;
846      size_t count;
847 {
848   const char *padptr;
849   register size_t i;
850
851   padptr = pad == ' ' ? blanks : zeroes;
852
853   for (i = count; i >= PADSIZE; i -= PADSIZE)
854     if (PUT (s, padptr, PADSIZE) != PADSIZE)
855       return -1;
856   if (i > 0)
857     if (PUT (s, padptr, i) != i)
858       return -1;
859
860   return count;
861 }
862 #undef PADSIZE
863 #endif /* USE_IN_LIBIO */