]> sourceware.org Git - glibc.git/blob - stdio-common/vfprintf.c
Wed Nov 22 12:37:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
[glibc.git] / stdio-common / 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 --specs[cnt].info.width;/* Account for the character itself. */
501 if (!specs[cnt].info.left)
502 PAD (' ');
503 outchar ((unsigned char) args_value[specs[cnt].data_arg].pa_char);
504 if (specs[cnt].info.left)
505 PAD (' ');
506 break;
507
508 case 's':
509 {
510 static const char null[] = "(null)";
511 size_t len;
512
513 str = args_value[specs[cnt].data_arg].pa_string;
514
515 string:
516
517 if (str == NULL)
518 {
519 /* Write "(null)" if there's space. */
520 if (specs[cnt].info.prec == -1
521 || specs[cnt].info.prec >= (int) sizeof (null) - 1)
522 {
523 str = null;
524 len = sizeof (null) - 1;
525 }
526 else
527 {
528 str = "";
529 len = 0;
530 }
531 }
532 else if (specs[cnt].info.prec != -1)
533 {
534 /* Search for the end of the string, but don't search
535 past the length specified by the precision. */
536 const char *end = memchr (str, '\0', specs[cnt].info.prec);
537 if (end)
538 len = end - str;
539 else
540 len = specs[cnt].info.prec;
541 }
542 else
543 len = strlen (str);
544
545 specs[cnt].info.width -= len;
546
547 if (!specs[cnt].info.left)
548 PAD (' ');
549 outstring (str, len);
550 if (specs[cnt].info.left)
551 PAD (' ');
552 }
553 break;
554
555 case 'p':
556 /* Generic pointer. */
557 {
558 const void *ptr;
559 ptr = args_value[specs[cnt].data_arg].pa_pointer;
560 if (ptr != NULL)
561 {
562 /* If the pointer is not NULL, write it as a %#x spec. */
563 base = 16;
564 num = (unsigned long long int) (unsigned long int) ptr;
565 is_neg = 0;
566 specs[cnt].info.alt = 1;
567 specs[cnt].info.spec = 'x';
568 specs[cnt].info.group = 0;
569 goto number;
570 }
571 else
572 {
573 /* Write "(nil)" for a nil pointer. */
574 str = "(nil)";
575 /* Make sure the full string "(nil)" is printed. */
576 if (specs[cnt].info.prec < 5)
577 specs[cnt].info.prec = 5;
578 goto string;
579 }
580 }
581 break;
582
583 case 'n':
584 /* Answer the count of characters written. */
585 if (specs[cnt].info.is_longlong)
586 *(long long int *)
587 args_value[specs[cnt].data_arg].pa_pointer = done;
588 else if (specs[cnt].info.is_long)
589 *(long int *)
590 args_value[specs[cnt].data_arg].pa_pointer = done;
591 else if (!specs[cnt].info.is_short)
592 *(int *)
593 args_value[specs[cnt].data_arg].pa_pointer = done;
594 else
595 *(short int *)
596 args_value[specs[cnt].data_arg].pa_pointer = done;
597 break;
598
599 case 'm':
600 {
601 extern char *_strerror_internal __P ((int, char *buf, size_t));
602 str = _strerror_internal (errno, errorbuf, sizeof errorbuf);
603 goto string;
604 }
605
606 default:
607 /* Unrecognized format specifier. */
608 function = printf_unknown;
609 goto use_function;
610 }
611
612 /* Write the following constant string. */
613 outstring (specs[cnt].end_of_fmt,
614 specs[cnt].next_fmt - specs[cnt].end_of_fmt);
615 }
616
617 return done;
618 }
619
620 #ifdef USE_IN_LIBIO
621 #undef vfprintf
622 strong_alias (_IO_vfprintf, vfprintf)
623 #endif
624
625
626 /* Handle an unknown format specifier. This prints out a canonicalized
627 representation of the format spec itself. */
628
629 static int
630 printf_unknown (s, info, args)
631 FILE *s;
632 const struct printf_info *info;
633 const void **const args;
634 {
635 int done = 0;
636 char work[BUFSIZ];
637 char *const workend = &work[sizeof(work) - 1];
638 register char *w;
639
640 outchar ('%');
641
642 if (info->alt)
643 outchar ('#');
644 if (info->group)
645 outchar ('\'');
646 if (info->showsign)
647 outchar ('+');
648 else if (info->space)
649 outchar (' ');
650 if (info->left)
651 outchar ('-');
652 if (info->pad == '0')
653 outchar ('0');
654
655 if (info->width != 0)
656 {
657 w = _itoa (info->width, workend + 1, 10, 0);
658 while (++w <= workend)
659 outchar (*w);
660 }
661
662 if (info->prec != -1)
663 {
664 outchar ('.');
665 w = _itoa (info->prec, workend + 1, 10, 0);
666 while (++w <= workend)
667 outchar (*w);
668 }
669
670 if (info->spec != '\0')
671 outchar (info->spec);
672
673 return done;
674 }
675 \f
676 /* Group the digits according to the grouping rules of the current locale.
677 The interpretation of GROUPING is as in `struct lconv' from <locale.h>. */
678
679 static char *
680 group_number (char *w, char *workend, const char *grouping,
681 wchar_t thousands_sep)
682 {
683 int len;
684 char *src, *s;
685
686 /* We treat all negative values like CHAR_MAX. */
687
688 if (*grouping == CHAR_MAX || *grouping < 0)
689 /* No grouping should be done. */
690 return w;
691
692 len = *grouping;
693
694 /* Copy existing string so that nothing gets overwritten. */
695 src = (char *) alloca (workend - w);
696 memcpy (src, w + 1, workend - w);
697 s = &src[workend - w - 1];
698 w = workend;
699
700 /* Process all characters in the string. */
701 while (s >= src)
702 {
703 *w-- = *s--;
704
705 if (--len == 0 && s >= src)
706 {
707 /* A new group begins. */
708 *w-- = thousands_sep;
709
710 len = *grouping++;
711 if (*grouping == '\0')
712 /* The previous grouping repeats ad infinitum. */
713 --grouping;
714 else if (*grouping == CHAR_MAX || *grouping < 0)
715 {
716 /* No further grouping to be done.
717 Copy the rest of the number. */
718 do
719 *w-- = *s--;
720 while (s >= src);
721 break;
722 }
723 }
724 }
725 return w;
726 }
727 \f
728 #ifdef USE_IN_LIBIO
729 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer. */
730 struct helper_file
731 {
732 struct _IO_FILE_plus _f;
733 _IO_FILE *_put_stream;
734 };
735
736 static int
737 _IO_helper_overflow (s, c)
738 _IO_FILE *s;
739 int c;
740 {
741 _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
742 int used = s->_IO_write_ptr - s->_IO_write_base;
743 if (used)
744 {
745 _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
746 s->_IO_write_ptr -= written;
747 }
748 return _IO_putc (c, s);
749 }
750
751 static const struct _IO_jump_t _IO_helper_jumps =
752 {
753 JUMP_INIT_DUMMY,
754 JUMP_INIT (finish, _IO_default_finish),
755 JUMP_INIT (overflow, _IO_helper_overflow),
756 JUMP_INIT (underflow, _IO_default_underflow),
757 JUMP_INIT (uflow, _IO_default_uflow),
758 JUMP_INIT (pbackfail, _IO_default_pbackfail),
759 JUMP_INIT (xsputn, _IO_default_xsputn),
760 JUMP_INIT (xsgetn, _IO_default_xsgetn),
761 JUMP_INIT (seekoff, _IO_default_seekoff),
762 JUMP_INIT (seekpos, _IO_default_seekpos),
763 JUMP_INIT (setbuf, _IO_default_setbuf),
764 JUMP_INIT (sync, _IO_default_sync),
765 JUMP_INIT (doallocate, _IO_default_doallocate),
766 JUMP_INIT (read, _IO_default_read),
767 JUMP_INIT (write, _IO_default_write),
768 JUMP_INIT (seek, _IO_default_seek),
769 JUMP_INIT (close, _IO_default_close),
770 JUMP_INIT (stat, _IO_default_stat)
771 };
772
773 static int
774 buffered_vfprintf (s, format, args)
775 register _IO_FILE *s;
776 char const *format;
777 _IO_va_list args;
778 {
779 char buf[_IO_BUFSIZ];
780 struct helper_file helper;
781 register _IO_FILE *hp = (_IO_FILE *) &helper;
782 int result, to_flush;
783
784 /* Initialize helper. */
785 helper._put_stream = s;
786 hp->_IO_write_base = buf;
787 hp->_IO_write_ptr = buf;
788 hp->_IO_write_end = buf + sizeof buf;
789 hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
790 _IO_JUMPS (hp) = (struct _IO_jump_t *) &_IO_helper_jumps;
791
792 /* Now print to helper instead. */
793 result = _IO_vfprintf (hp, format, args);
794
795 /* Now flush anything from the helper to the S. */
796 if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
797 {
798 if (_IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
799 return -1;
800 }
801
802 return result;
803 }
804
805 #else /* !USE_IN_LIBIO */
806
807 static int
808 buffered_vfprintf (s, format, args)
809 register FILE *s;
810 char const *format;
811 va_list args;
812 {
813 char buf[BUFSIZ];
814 int result;
815
816 s->__bufp = s->__buffer = buf;
817 s->__bufsize = sizeof buf;
818 s->__put_limit = s->__buffer + s->__bufsize;
819 s->__get_limit = s->__buffer;
820
821 /* Now use buffer to print. */
822 result = vfprintf (s, format, args);
823
824 if (fflush (s) == EOF)
825 result = -1;
826 s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL;
827 s->__bufsize = 0;
828
829 return result;
830 }
831
832
833 /* Pads string with given number of a specified character.
834 This code is taken from iopadn.c of the GNU I/O library. */
835 #define PADSIZE 16
836 static const char blanks[PADSIZE] =
837 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
838 static const char zeroes[PADSIZE] =
839 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
840
841 ssize_t
842 __printf_pad (s, pad, count)
843 FILE *s;
844 char pad;
845 size_t count;
846 {
847 const char *padptr;
848 register size_t i;
849
850 padptr = pad == ' ' ? blanks : zeroes;
851
852 for (i = count; i >= PADSIZE; i -= PADSIZE)
853 if (PUT (s, padptr, PADSIZE) != PADSIZE)
854 return -1;
855 if (i > 0)
856 if (PUT (s, padptr, i) != i)
857 return -1;
858
859 return count;
860 }
861 #undef PADSIZE
862 #endif /* USE_IN_LIBIO */
This page took 0.075761 seconds and 5 git commands to generate.