2 Copyright (C) 1998 Andrew Tridgell
3 Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
5 This code is derived from code in the GNU C library, version
6 2.0.6. It was modified by Andew Tridgell to provide a standalone
7 vslprintf implementation portable across a wide range of
8 machines. The modifications required some fairly heavy handed
9 chainsawing of the code. If you think you can do a cleaner job then
10 please do, and send me a patch (at tridge@samba.org)
12 Note that some features of the glibc implementation were lost
13 during the modifications. If you are looking for a full-featured
14 glibc vsnprintf() routine then please go to the glibc sources. This
15 code is intended for use by people writing secure applications for
16 systems that may not have glibc installed.
20 The GNU C Library is free software; you can redistribute it and/or
21 modify it under the terms of the GNU Library General Public License as
22 published by the Free Software Foundation; either version 2 of the
23 License, or (at your option) any later version.
25 The GNU C Library is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 Library General Public License for more details.
30 You should have received a copy of the GNU Library General Public
31 License along with the GNU C Library; see the file COPYING.LIB. If not,
32 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
33 Boston, MA 02111-1307, USA. */
42 #define UCHAR_T unsigned char
45 #define ISDIGIT(Ch) isdigit (Ch)
47 /* Codes returned by `parse_printf_format' for basic types.
49 These values cover all the standard format specifications.
50 Users can add new values after PA_LAST for their own types. */
55 PA_CHAR, /* int, cast to char */
56 PA_WCHAR, /* wide char */
57 PA_STRING, /* const char *, a '\0'-terminated string */
58 PA_WSTRING, /* const wchar_t *, wide character string */
59 PA_POINTER, /* void * */
61 PA_DOUBLE, /* double */
65 /* Flag bits that can be set in a type returned by `parse_printf_format'. */
66 #define PA_FLAG_MASK 0xff00
67 #define PA_FLAG_LONG_LONG (1 << 8)
68 #define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG
69 #define PA_FLAG_LONG (1 << 9)
70 #define PA_FLAG_SHORT (1 << 10)
71 #define PA_FLAG_PTR (1 << 11)
75 int prec; /* Precision. */
76 int width; /* Width. */
77 wchar_t spec; /* Format letter. */
78 unsigned int is_long_double:1;/* L flag. */
79 unsigned int is_short:1; /* h flag. */
80 unsigned int is_long:1; /* l flag. */
81 unsigned int alt:1; /* # flag. */
82 unsigned int space:1; /* Space flag. */
83 unsigned int left:1; /* - flag. */
84 unsigned int showsign:1; /* + flag. */
85 unsigned int group:1; /* ' flag. */
86 unsigned int extra:1; /* For special use. */
87 wchar_t pad; /* Padding character. */
91 /* we create a pseudo-file structure to make interfacing with the existing code
94 char *s; /* pointer to the buffer */
95 unsigned long offset; /* current offset within the buffer */
96 unsigned long len; /* the size of the buffer */
102 register const int outc = (Ch); \
103 if (PUTC (outc, s) == EOF) \
110 #define outstring(String, Len) \
113 if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \
119 /* For handling long_double and longlong we use the same flag. */
121 # define is_longlong is_long_double
125 /* Global variables. */
126 static const char null[] = "(null)";
129 /* Helper function to provide temporary buffering for unbuffered streams. */
130 static int buffered_vfprintf __P ((sFILE *stream, const CHAR_T *fmt, va_list));
132 /* Handle unknown format specifier. */
133 static int printf_unknown __P ((FILE *, const struct printf_info *,
134 const void *const *));
136 /* Group digits of number string. */
137 static char *group_number __P ((CHAR_T *, CHAR_T *, const CHAR_T *, wchar_t));
142 /* Information parsed from the format spec. */
143 struct printf_info info;
145 /* Pointers into the format string for the end of this format
146 spec and the next (or to the end of the string if no more). */
147 const char *end_of_fmt, *next_fmt;
149 /* Position of arguments for precision and width, or -1 if `info' has
150 the constant value. */
151 int prec_arg, width_arg;
153 int data_arg; /* Position of data argument. */
154 int data_arg_type; /* Type of first argument. */
155 /* Number of arguments consumed by this format specifier. */
160 /* The various kinds off arguments that can be passed to printf. */
163 unsigned char pa_char;
165 short int pa_short_int;
167 long int pa_long_int;
168 long long int pa_long_long_int;
169 unsigned short int pa_u_short_int;
170 unsigned int pa_u_int;
171 unsigned long int pa_u_long_int;
172 unsigned long long int pa_u_long_long_int;
175 long double pa_long_double;
176 const char *pa_string;
177 const wchar_t *pa_wstring;
182 /* Read a simple integer from a string and update the string pointer.
183 It is assumed that the first character is a digit. */
184 static inline unsigned int
185 read_int (const UCHAR_T * *pstr)
187 unsigned int retval = **pstr - L_('0');
189 while (ISDIGIT (*++(*pstr)))
192 retval += **pstr - L_('0');
200 /* Find the next spec in FORMAT, or the end of the string. Returns
201 a pointer into FORMAT, to a '%' or a '\0'. */
202 static inline const char *
203 find_spec (const char *format)
205 while (*format != '\0' && *format != '%')
213 #define UCHAR_MAX 255
216 /* Type of a printf specifier-handler function.
217 STREAM is the FILE on which to write output.
218 INFO gives information about the format specification.
219 ARGS is a vector of pointers to the argument data;
220 the number of pointers will be the number returned
221 by the associated arginfo function for the same INFO.
223 The function should return the number of characters written,
226 typedef int printf_function __P ((FILE *__stream,
227 __const struct printf_info *__info,
228 __const void *__const *__args));
230 /* Type of a printf specifier-arginfo function.
231 INFO gives information about the format specification.
232 N, ARGTYPES, and return value are as for printf_parse_format. */
234 typedef int printf_arginfo_function __P ((__const struct printf_info *__info,
238 static printf_function *__printf_function_table[UCHAR_MAX + 1];
239 static printf_arginfo_function *__printf_arginfo_table[UCHAR_MAX + 1];
242 /* FORMAT must point to a '%' at the beginning of a spec. Fills in *SPEC
243 with the parsed details. POSN is the number of arguments already
244 consumed. At most MAXTYPES - POSN types are filled in TYPES. Return
245 the number of args consumed by this spec; *MAX_REF_ARG is updated so it
246 remains the highest argument index used. */
248 parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
257 /* Clear information structure. */
260 spec->info.space = 0;
262 spec->info.showsign = 0;
263 spec->info.group = 0;
264 spec->info.pad = ' ';
266 /* Test for positional argument. */
267 if (ISDIGIT (*format))
269 const UCHAR_T *begin = format;
271 n = read_int (&format);
273 if (n > 0 && *format == L_('$'))
274 /* Is positional parameter. */
276 ++format; /* Skip the '$'. */
277 spec->data_arg = n - 1;
278 *max_ref_arg = MAX (*max_ref_arg, n);
281 /* Oops; that was actually the width and/or 0 padding flag.
282 Step back and read it again. */
286 /* Check for spec modifiers. */
287 while (*format == L_(' ') || *format == L_('+') || *format == L_('-') ||
288 *format == L_('#') || *format == L_('0') || *format == L_('\''))
292 /* Output a space in place of a sign, when there is no sign. */
293 spec->info.space = 1;
296 /* Always output + or - for numbers. */
297 spec->info.showsign = 1;
300 /* Left-justify things. */
304 /* Use the "alternate form":
305 Hex has 0x or 0X, FP always has a decimal point. */
310 spec->info.pad = '0';
313 /* Show grouping in numbers if the locale information
315 spec->info.group = 1;
319 spec->info.pad = ' ';
321 /* Get the field width. */
322 spec->width_arg = -1;
323 spec->info.width = 0;
324 if (*format == L_('*'))
326 /* The field width is given in an argument.
327 A negative field width indicates left justification. */
328 const UCHAR_T *begin = ++format;
330 if (ISDIGIT (*format))
332 /* The width argument might be found in a positional parameter. */
333 n = read_int (&format);
335 if (n > 0 && *format == L_('$'))
337 spec->width_arg = n - 1;
338 *max_ref_arg = MAX (*max_ref_arg, n);
339 ++format; /* Skip '$'. */
343 if (spec->width_arg < 0)
345 /* Not in a positional parameter. Consume one argument. */
346 spec->width_arg = posn++;
348 format = begin; /* Step back and reread. */
351 else if (ISDIGIT (*format))
352 /* Constant width specification. */
353 spec->info.width = read_int (&format);
355 /* Get the precision. */
357 /* -1 means none given; 0 means explicit 0. */
358 spec->info.prec = -1;
359 if (*format == L_('.'))
362 if (*format == L_('*'))
364 /* The precision is given in an argument. */
365 const UCHAR_T *begin = ++format;
367 if (ISDIGIT (*format))
369 n = read_int (&format);
371 if (n > 0 && *format == L_('$'))
373 spec->prec_arg = n - 1;
374 *max_ref_arg = MAX (*max_ref_arg, n);
379 if (spec->prec_arg < 0)
381 /* Not in a positional parameter. */
382 spec->prec_arg = posn++;
387 else if (ISDIGIT (*format))
388 spec->info.prec = read_int (&format);
390 /* "%.?" is treated like "%.0?". */
394 /* Check for type modifiers. */
395 #define is_longlong is_long_double
396 spec->info.is_long_double = 0;
397 spec->info.is_short = 0;
398 spec->info.is_long = 0;
400 if (*format == L_('h') || *format == L_('l') || *format == L_('L') ||
401 *format == L_('Z') || *format == L_('q'))
405 /* int's are short int's. */
406 spec->info.is_short = 1;
409 /* int's are long int's. */
410 spec->info.is_long = 1;
411 if (*format != L_('l'))
416 /* double's are long double's, and int's are long long int's. */
418 /* 4.4 uses this for long long. */
419 spec->info.is_long_double = 1;
422 /* int's are size_t's. */
423 assert (sizeof(size_t) <= sizeof(unsigned long long int));
424 spec->info.is_longlong = sizeof(size_t) > sizeof(unsigned long int);
425 spec->info.is_long = sizeof(size_t) > sizeof(unsigned int);
429 /* Get the format specification. */
430 spec->info.spec = (wchar_t) *format++;
431 if (__printf_function_table != NULL
432 && spec->info.spec <= UCHAR_MAX
433 && __printf_arginfo_table[spec->info.spec] != NULL)
434 /* We don't try to get the types for all arguments if the format
435 uses more than one. The normal case is covered though. */
436 spec->ndata_args = (*__printf_arginfo_table[spec->info.spec])
437 (&spec->info, 1, &spec->data_arg_type);
440 /* Find the data argument types of a built-in spec. */
441 spec->ndata_args = 1;
443 switch (spec->info.spec)
451 if (spec->info.is_longlong)
452 spec->data_arg_type = PA_INT|PA_FLAG_LONG_LONG;
453 else if (spec->info.is_long)
454 spec->data_arg_type = PA_INT|PA_FLAG_LONG;
455 else if (spec->info.is_short)
456 spec->data_arg_type = PA_INT|PA_FLAG_SHORT;
458 spec->data_arg_type = PA_INT;
465 if (spec->info.is_long_double)
466 spec->data_arg_type = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;
468 spec->data_arg_type = PA_DOUBLE;
471 spec->data_arg_type = PA_CHAR;
474 spec->data_arg_type = PA_WCHAR;
477 spec->data_arg_type = PA_STRING;
480 spec->data_arg_type = PA_WSTRING;
483 spec->data_arg_type = PA_POINTER;
486 spec->data_arg_type = PA_INT|PA_FLAG_PTR;
491 /* An unknown spec will consume no args. */
492 spec->ndata_args = 0;
497 if (spec->data_arg == -1 && spec->ndata_args > 0)
499 /* There are args consumed, but no positional spec. Use the
500 next sequential arg position. */
501 spec->data_arg = posn;
502 nargs += spec->ndata_args;
505 if (spec->info.spec == L'\0')
506 /* Format ended before this spec was complete. */
507 spec->end_of_fmt = spec->next_fmt = format - 1;
510 /* Find the next format spec. */
511 spec->end_of_fmt = format;
512 spec->next_fmt = find_spec (format);
519 /* The function itself. */
521 _vslprintf (sFILE *s, const CHAR_T *format, va_list ap)
523 /* The character used as thousands separator. */
524 wchar_t thousands_sep;
526 /* The string describing the size of groups of digits. */
527 const char *grouping;
529 /* Place to accumulate the result. */
532 /* Current character in format string. */
535 /* End of leading constant string. */
536 const UCHAR_T *lead_str_end;
538 /* Points to next format specifier. */
539 const UCHAR_T *end_of_spec;
541 /* Buffer intermediate results. */
542 char work_buffer[1000];
543 #define workend (&work_buffer[sizeof (work_buffer) - 1])
545 /* We have to save the original argument pointer. */
548 /* Count number of specifiers we already processed. */
551 /* This table maps a character into a number representing a
552 class. In each step there is a destination label for each
554 static const int jump_table[] =
556 /* ' ' */ 1, 0, 0, /* '#' */ 4,
557 0, /* '%' */ 14, 0, /* '\''*/ 6,
558 0, 0, /* '*' */ 7, /* '+' */ 2,
559 0, /* '-' */ 3, /* '.' */ 9, 0,
560 /* '0' */ 5, /* '1' */ 8, /* '2' */ 8, /* '3' */ 8,
561 /* '4' */ 8, /* '5' */ 8, /* '6' */ 8, /* '7' */ 8,
562 /* '8' */ 8, /* '9' */ 8, 0, 0,
564 0, 0, 0, /* 'C' */ 25,
565 0, /* 'E' */ 19, 0, /* 'G' */ 19,
567 /* 'L' */ 12, 0, 0, 0,
568 0, 0, 0, /* 'S' */ 21,
570 /* 'X' */ 18, 0, /* 'Z' */ 13, 0,
572 0, 0, 0, /* 'c' */ 20,
573 /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
574 /* 'h' */ 10, /* 'i' */ 15, 0, 0,
575 /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
576 /* 'p' */ 22, /* 'q' */ 12, 0, /* 's' */ 21,
577 0, /* 'u' */ 16, 0, 0,
581 #define NOT_IN_JUMP_RANGE(Ch) ((Ch) < ' ' || (Ch) > 'x')
582 #define CHAR_CLASS(Ch) (jump_table[(int) (Ch) - ' '])
583 #define JUMP(ChExpr, table) \
588 ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
589 : table[CHAR_CLASS (spec)]; \
594 #define STEP0_3_TABLE \
595 /* Step 0: at the beginning. */ \
596 static const void *step0_jumps[26] = \
598 REF (form_unknown), \
599 REF (flag_space), /* for ' ' */ \
600 REF (flag_plus), /* for '+' */ \
601 REF (flag_minus), /* for '-' */ \
602 REF (flag_hash), /* for '<hash>' */ \
603 REF (flag_zero), /* for '0' */ \
604 REF (flag_quote), /* for '\'' */ \
605 REF (width_asterics), /* for '*' */ \
606 REF (width), /* for '1'...'9' */ \
607 REF (precision), /* for '.' */ \
608 REF (mod_half), /* for 'h' */ \
609 REF (mod_long), /* for 'l' */ \
610 REF (mod_longlong), /* for 'L', 'q' */ \
611 REF (mod_size_t), /* for 'Z' */ \
612 REF (form_percent), /* for '%' */ \
613 REF (form_integer), /* for 'd', 'i' */ \
614 REF (form_unsigned), /* for 'u' */ \
615 REF (form_octal), /* for 'o' */ \
616 REF (form_hexa), /* for 'X', 'x' */ \
617 REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \
618 REF (form_character), /* for 'c' */ \
619 REF (form_string), /* for 's', 'S' */ \
620 REF (form_pointer), /* for 'p' */ \
621 REF (form_number), /* for 'n' */ \
622 REF (form_strerror), /* for 'm' */ \
623 REF (form_wcharacter) /* for 'C' */ \
625 /* Step 1: after processing width. */ \
626 static const void *step1_jumps[26] = \
628 REF (form_unknown), \
629 REF (form_unknown), /* for ' ' */ \
630 REF (form_unknown), /* for '+' */ \
631 REF (form_unknown), /* for '-' */ \
632 REF (form_unknown), /* for '<hash>' */ \
633 REF (form_unknown), /* for '0' */ \
634 REF (form_unknown), /* for '\'' */ \
635 REF (form_unknown), /* for '*' */ \
636 REF (form_unknown), /* for '1'...'9' */ \
637 REF (precision), /* for '.' */ \
638 REF (mod_half), /* for 'h' */ \
639 REF (mod_long), /* for 'l' */ \
640 REF (mod_longlong), /* for 'L', 'q' */ \
641 REF (mod_size_t), /* for 'Z' */ \
642 REF (form_percent), /* for '%' */ \
643 REF (form_integer), /* for 'd', 'i' */ \
644 REF (form_unsigned), /* for 'u' */ \
645 REF (form_octal), /* for 'o' */ \
646 REF (form_hexa), /* for 'X', 'x' */ \
647 REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \
648 REF (form_character), /* for 'c' */ \
649 REF (form_string), /* for 's', 'S' */ \
650 REF (form_pointer), /* for 'p' */ \
651 REF (form_number), /* for 'n' */ \
652 REF (form_strerror), /* for 'm' */ \
653 REF (form_wcharacter) /* for 'C' */ \
655 /* Step 2: after processing precision. */ \
656 static const void *step2_jumps[26] = \
658 REF (form_unknown), \
659 REF (form_unknown), /* for ' ' */ \
660 REF (form_unknown), /* for '+' */ \
661 REF (form_unknown), /* for '-' */ \
662 REF (form_unknown), /* for '<hash>' */ \
663 REF (form_unknown), /* for '0' */ \
664 REF (form_unknown), /* for '\'' */ \
665 REF (form_unknown), /* for '*' */ \
666 REF (form_unknown), /* for '1'...'9' */ \
667 REF (form_unknown), /* for '.' */ \
668 REF (mod_half), /* for 'h' */ \
669 REF (mod_long), /* for 'l' */ \
670 REF (mod_longlong), /* for 'L', 'q' */ \
671 REF (mod_size_t), /* for 'Z' */ \
672 REF (form_percent), /* for '%' */ \
673 REF (form_integer), /* for 'd', 'i' */ \
674 REF (form_unsigned), /* for 'u' */ \
675 REF (form_octal), /* for 'o' */ \
676 REF (form_hexa), /* for 'X', 'x' */ \
677 REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \
678 REF (form_character), /* for 'c' */ \
679 REF (form_string), /* for 's', 'S' */ \
680 REF (form_pointer), /* for 'p' */ \
681 REF (form_number), /* for 'n' */ \
682 REF (form_strerror), /* for 'm' */ \
683 REF (form_wcharacter) /* for 'C' */ \
685 /* Step 3: after processing first 'l' modifier. */ \
686 static const void *step3_jumps[26] = \
688 REF (form_unknown), \
689 REF (form_unknown), /* for ' ' */ \
690 REF (form_unknown), /* for '+' */ \
691 REF (form_unknown), /* for '-' */ \
692 REF (form_unknown), /* for '<hash>' */ \
693 REF (form_unknown), /* for '0' */ \
694 REF (form_unknown), /* for '\'' */ \
695 REF (form_unknown), /* for '*' */ \
696 REF (form_unknown), /* for '1'...'9' */ \
697 REF (form_unknown), /* for '.' */ \
698 REF (form_unknown), /* for 'h' */ \
699 REF (mod_longlong), /* for 'l' */ \
700 REF (form_unknown), /* for 'L', 'q' */ \
701 REF (form_unknown), /* for 'Z' */ \
702 REF (form_percent), /* for '%' */ \
703 REF (form_integer), /* for 'd', 'i' */ \
704 REF (form_unsigned), /* for 'u' */ \
705 REF (form_octal), /* for 'o' */ \
706 REF (form_hexa), /* for 'X', 'x' */ \
707 REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \
708 REF (form_character), /* for 'c' */ \
709 REF (form_string), /* for 's', 'S' */ \
710 REF (form_pointer), /* for 'p' */ \
711 REF (form_number), /* for 'n' */ \
712 REF (form_strerror), /* for 'm' */ \
713 REF (form_wcharacter) /* for 'C' */ \
716 #define STEP4_TABLE \
717 /* Step 4: processing format specifier. */ \
718 static const void *step4_jumps[26] = \
720 REF (form_unknown), \
721 REF (form_unknown), /* for ' ' */ \
722 REF (form_unknown), /* for '+' */ \
723 REF (form_unknown), /* for '-' */ \
724 REF (form_unknown), /* for '<hash>' */ \
725 REF (form_unknown), /* for '0' */ \
726 REF (form_unknown), /* for '\'' */ \
727 REF (form_unknown), /* for '*' */ \
728 REF (form_unknown), /* for '1'...'9' */ \
729 REF (form_unknown), /* for '.' */ \
730 REF (form_unknown), /* for 'h' */ \
731 REF (form_unknown), /* for 'l' */ \
732 REF (form_unknown), /* for 'L', 'q' */ \
733 REF (form_unknown), /* for 'Z' */ \
734 REF (form_percent), /* for '%' */ \
735 REF (form_integer), /* for 'd', 'i' */ \
736 REF (form_unsigned), /* for 'u' */ \
737 REF (form_octal), /* for 'o' */ \
738 REF (form_hexa), /* for 'X', 'x' */ \
739 REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \
740 REF (form_character), /* for 'c' */ \
741 REF (form_string), /* for 's', 'S' */ \
742 REF (form_pointer), /* for 'p' */ \
743 REF (form_number), /* for 'n' */ \
744 REF (form_strerror), /* for 'm' */ \
745 REF (form_wcharacter) /* for 'C' */ \
749 #define process_arg(fspec) \
750 /* Start real work. We know about all flags and modifiers and \
751 now process the wanted format specifier. */ \
752 LABEL (form_percent): \
753 /* Write a literal "%". */ \
757 LABEL (form_integer): \
758 /* Signed decimal integer. */ \
763 long long int signed_number; \
766 signed_number = va_arg (ap, long long int); \
768 signed_number = args_value[fspec->data_arg].pa_long_long_int; \
770 is_negative = signed_number < 0; \
771 number.longlong = is_negative ? (- signed_number) : signed_number; \
773 goto LABEL (longlong_number); \
777 long int signed_number; \
781 signed_number = va_arg (ap, long int); \
782 else /* `short int' will be promoted to `int'. */ \
783 signed_number = va_arg (ap, int); \
786 signed_number = args_value[fspec->data_arg].pa_long_int; \
788 signed_number = args_value[fspec->data_arg].pa_int; \
790 is_negative = signed_number < 0; \
791 number.word = is_negative ? (- signed_number) : signed_number; \
793 goto LABEL (number); \
797 LABEL (form_unsigned): \
798 /* Unsigned decimal integer. */ \
800 goto LABEL (unsigned_number); \
803 LABEL (form_octal): \
804 /* Unsigned octal integer. */ \
806 goto LABEL (unsigned_number); \
810 /* Unsigned hexadecimal integer. */ \
813 LABEL (unsigned_number): /* Unsigned number of base BASE. */ \
815 /* ANSI specifies the `+' and ` ' flags only for signed \
824 number.longlong = va_arg (ap, unsigned long long int); \
826 number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \
828 LABEL (longlong_number): \
830 /* Supply a default precision if none was given. */ \
833 /* We have to take care for the '0' flag. If a precision \
834 is given it must be ignored. */ \
837 /* If the precision is 0 and the number is 0 nothing has to \
838 be written for the number. */ \
839 if (prec == 0 && number.longlong == 0) \
843 /* Put the number in WORK. */ \
844 string = _itoa (number.longlong, workend + 1, base, \
847 if (group && grouping) \
848 string = group_number (string, workend, grouping, \
851 /* Simply further test for num != 0. */ \
852 number.word = number.longlong != 0; \
858 number.word = va_arg (ap, unsigned long int); \
859 else if (!is_short) \
860 number.word = va_arg (ap, unsigned int); \
862 number.word = (unsigned short int) va_arg (ap, unsigned int); \
865 number.word = args_value[fspec->data_arg].pa_u_long_int; \
866 else if (!is_short) \
867 number.word = args_value[fspec->data_arg].pa_u_int; \
869 number.word = (unsigned short int) \
870 args_value[fspec->data_arg].pa_u_short_int; \
874 /* Supply a default precision if none was given. */ \
877 /* We have to take care for the '0' flag. If a precision \
878 is given it must be ignored. */ \
881 /* If the precision is 0 and the number is 0 nothing has to \
882 be written for the number. */ \
883 if (prec == 0 && number.word == 0) \
887 /* Put the number in WORK. */ \
888 string = _itoa_word (number.word, workend + 1, base, \
891 if (group && grouping) \
892 string = group_number (string, workend, grouping, \
897 prec -= workend - string; \
900 /* Add zeros to the precision. */ \
903 else if (number.word != 0 && alt && base == 8) \
904 /* Add octal marker. */ \
909 width -= workend - string; \
911 if (number.word != 0 && alt && base == 16) \
912 /* Account for 0X hex marker. */ \
915 if (is_negative || showsign || space) \
920 while (width-- > 0) \
923 if (number.word != 0 && alt && base == 16) \
938 if (number.word != 0 && alt && base == 16) \
951 while (width-- > 0) \
955 outstring (string + 1, workend - string); \
961 if (number.word != 0 && alt && base == 16) \
974 width -= workend - string; \
975 outstring (string + 1, workend - string); \
981 LABEL (form_float): \
983 /* Floating-point number. This is handled by printf_fp.c. */ \
984 extern int __printf_fp __P ((FILE *, const struct printf_info *, \
985 const void **const)); \
991 struct printf_info info = { prec: prec, \
994 is_long_double: is_long_double, \
995 is_short: is_short, \
1000 showsign: showsign, \
1005 if (is_long_double) \
1006 the_arg.pa_long_double = va_arg (ap, long double); \
1008 the_arg.pa_double = va_arg (ap, double); \
1009 ptr = (const void *) &the_arg; \
1011 function_done = __printf_fp (s, &info, &ptr); \
1015 ptr = (const void *) &args_value[fspec->data_arg]; \
1017 function_done = __printf_fp (s, &fspec->info, &ptr); \
1020 if (function_done < 0) \
1021 /* Error in print handler. */ \
1024 done += function_done; \
1028 LABEL (form_character): \
1031 goto LABEL (form_wcharacter); \
1032 --width; /* Account for the character itself. */ \
1035 if (fspec == NULL) \
1036 outchar ((unsigned char) va_arg (ap, int)); /* Promoted. */ \
1038 outchar ((unsigned char) args_value[fspec->data_arg].pa_char); \
1043 LABEL (form_string): \
1047 /* The string argument could in fact be `char *' or `wchar_t *'. \
1048 But this should not make a difference here. */ \
1049 if (fspec == NULL) \
1050 string = (char *) va_arg (ap, const char *); \
1052 string = (char *) args_value[fspec->data_arg].pa_string; \
1054 /* Entry point for printing other strings. */ \
1055 LABEL (print_string): \
1057 if (string == NULL) \
1059 /* Write "(null)" if there's space. */ \
1060 if (prec == -1 || prec >= (int) sizeof (null) - 1) \
1062 string = (char *) null; \
1063 len = sizeof (null) - 1; \
1067 string = (char *) ""; \
1071 else if (!is_long && spec != L_('S')) \
1074 /* Search for the end of the string, but don't search past \
1075 the length specified by the precision. */ \
1076 len = strnlen (string, prec); \
1078 len = strlen (string); \
1081 if ((width -= len) < 0) \
1083 outstring (string, len); \
1089 outstring (string, len); \
1095 LABEL (form_pointer): \
1096 /* Generic pointer. */ \
1099 if (fspec == NULL) \
1100 ptr = va_arg (ap, void *); \
1102 ptr = args_value[fspec->data_arg].pa_pointer; \
1105 /* If the pointer is not NULL, write it as a %#x spec. */ \
1107 number.word = (unsigned long int) ptr; \
1112 goto LABEL (number); \
1116 /* Write "(nil)" for a nil pointer. */ \
1117 string = (char *) "(nil)"; \
1118 /* Make sure the full string "(nil)" is printed. */ \
1121 is_long = 0; /* This is no wide-char string. */ \
1122 goto LABEL (print_string); \
1127 LABEL (form_number): \
1128 /* Answer the count of characters written. */ \
1129 if (fspec == NULL) \
1131 *(long long int *) va_arg (ap, void *) = done; \
1133 *(long int *) va_arg (ap, void *) = done; \
1134 else if (!is_short) \
1135 *(int *) va_arg (ap, void *) = done; \
1137 *(short int *) va_arg (ap, void *) = done; \
1140 *(long long int *) args_value[fspec->data_arg].pa_pointer = done; \
1142 *(long int *) args_value[fspec->data_arg].pa_pointer = done; \
1143 else if (!is_short) \
1144 *(int *) args_value[fspec->data_arg].pa_pointer = done; \
1146 *(short int *) args_value[fspec->data_arg].pa_pointer = done; \
1150 /* Sanity check of arguments. */
1151 ARGCHECK (s, format);
1153 if (UNBUFFERED_P (s))
1154 /* Use a helper function which will allocate a local temporary buffer
1155 for the stream and then call us again. */
1156 return buffered_vfprintf (s, format, ap);
1158 /* Initialize local variables. */
1160 grouping = (const char *) -1;
1162 /* This macro will be available soon in gcc's <stdarg.h>. Me need it
1163 since on some systems `va_list' is not an integral type. */
1164 __va_copy (ap_save, ap);
1170 /* Find the first format specifier. */
1171 f = lead_str_end = find_spec (format);
1173 /* Write the literal text before the first format. */
1174 outstring ((const UCHAR_T *) format,
1175 lead_str_end - (const UCHAR_T *) format);
1177 /* If we only have to print a simple string, return now. */
1181 /* Process whole format string. */
1184 #define REF(Name) &&do_##Name
1185 #define LABEL(Name) do_##Name
1189 union printf_arg *args_value; /* This is not used here but ... */
1190 int is_negative; /* Flag for negative number. */
1193 unsigned long long int longlong;
1194 unsigned long int word;
1197 union printf_arg the_arg;
1198 char *string; /* Pointer to argument string. */
1199 int alt = 0; /* Alternate format. */
1200 int space = 0; /* Use space prefix if no sign is needed. */
1201 int left = 0; /* Left-justify output. */
1202 int showsign = 0; /* Always begin with plus or minus sign. */
1203 int group = 0; /* Print numbers according grouping rules. */
1204 int is_long_double = 0; /* Argument is long double/ long long int. */
1205 int is_short = 0; /* Argument is long int. */
1206 int is_long = 0; /* Argument is short int. */
1207 int width = 0; /* Width of output; 0 means none specified. */
1208 int prec = -1; /* Precision of output; -1 means none specified. */
1209 char pad = ' '; /* Padding character. */
1212 /* Get current character in format string. */
1213 JUMP (*++f, step0_jumps);
1218 JUMP (*++f, step0_jumps);
1223 JUMP (*++f, step0_jumps);
1229 JUMP (*++f, step0_jumps);
1234 JUMP (*++f, step0_jumps);
1240 JUMP (*++f, step0_jumps);
1242 /* The '\'' flag. */
1246 /* XXX Completely wrong. Use wctob. */
1247 if (grouping == (const char *) -1)
1252 JUMP (*++f, step0_jumps);
1254 /* Get width from argument. */
1255 LABEL (width_asterics):
1257 const UCHAR_T *tmp; /* Temporary value. */
1260 if (ISDIGIT (*tmp) && read_int (&tmp) && *tmp == L_('$'))
1261 /* The width comes from a positional parameter. */
1264 width = va_arg (ap, int);
1266 /* Negative width means left justified. */
1274 JUMP (*f, step1_jumps);
1276 /* Given width in format string. */
1278 width = read_int (&f);
1280 /* Oh, oh. The argument comes from a positional parameter. */
1282 JUMP (*f, step1_jumps);
1288 const UCHAR_T *tmp; /* Temporary value. */
1291 if (ISDIGIT (*tmp) && read_int (&tmp) > 0 && *tmp == L_('$'))
1292 /* The precision comes from a positional parameter. */
1295 prec = va_arg (ap, int);
1297 /* If the precision is negative the precision is omitted. */
1301 else if (ISDIGIT (*f))
1302 prec = read_int (&f);
1305 JUMP (*f, step2_jumps);
1307 /* Process 'h' modifier. No other modifier is allowed to
1311 JUMP (*++f, step4_jumps);
1313 /* Process 'l' modifier. There might another 'l' follow. */
1316 JUMP (*++f, step3_jumps);
1318 /* Process 'L', 'q', or 'll' modifier. No other modifier is
1319 allowed to follow. */
1320 LABEL (mod_longlong):
1322 JUMP (*++f, step4_jumps);
1325 is_longlong = sizeof (size_t) > sizeof (unsigned long int);
1326 is_long = sizeof (size_t) > sizeof (unsigned int);
1327 JUMP (*++f, step4_jumps);
1330 /* Process current format. */
1333 process_arg (((struct printf_spec *) NULL));
1335 LABEL (form_unknown):
1336 if (spec == L_('\0'))
1338 /* The format string ended before the specifier is complete. */
1343 /* If we are in the fast loop force entering the complicated
1348 /* The format is correctly handled. */
1351 /* Look for next format specifier. */
1352 f = find_spec ((end_of_spec = ++f));
1354 /* Write the following constant string. */
1355 outstring (end_of_spec, f - end_of_spec);
1357 while (*f != L_('\0'));
1359 /* Unlock stream and return. */
1362 /* Here starts the more complex loop to handle positional parameters. */
1365 /* Array with information about the needed arguments. This has to
1366 be dynamically extensible. */
1368 size_t nspecs_max = 32; /* A more or less arbitrary start value. */
1369 struct printf_spec *specs
1370 = alloca (nspecs_max * sizeof (struct printf_spec));
1372 /* The number of arguments the format string requests. This will
1373 determine the size of the array needed to store the argument
1377 union printf_arg *args_value;
1379 /* Positional parameters refer to arguments directly. This could
1380 also determine the maximum number of arguments. Track the
1382 size_t max_ref_arg = 0;
1384 /* Just a counter. */
1388 if (grouping == (const char *) -1)
1394 for (f = lead_str_end; *f != '\0'; f = specs[nspecs++].next_fmt)
1396 if (nspecs >= nspecs_max)
1398 /* Extend the array of format specifiers. */
1399 struct printf_spec *old = specs;
1402 specs = alloca (nspecs_max * sizeof (struct printf_spec));
1404 if (specs == &old[nspecs])
1405 /* Stack grows up, OLD was the last thing allocated;
1407 nspecs_max += nspecs_max / 2;
1410 /* Copy the old array's elements to the new space. */
1411 memcpy (specs, old, nspecs * sizeof (struct printf_spec));
1412 if (old == &specs[nspecs])
1413 /* Stack grows down, OLD was just below the new
1414 SPECS. We can use that space when the new space
1416 nspecs_max += nspecs_max / 2;
1420 /* Parse the format specifier. */
1421 nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg);
1424 /* Determine the number of arguments the format string consumes. */
1425 nargs = MAX (nargs, max_ref_arg);
1427 /* Allocate memory for the argument descriptions. */
1428 args_type = alloca (nargs * sizeof (int));
1429 memset (args_type, 0, nargs * sizeof (int));
1430 args_value = alloca (nargs * sizeof (union printf_arg));
1432 /* XXX Could do sanity check here: If any element in ARGS_TYPE is
1433 still zero after this loop, format is invalid. For now we
1434 simply use 0 as the value. */
1436 /* Fill in the types of all the arguments. */
1437 for (cnt = 0; cnt < nspecs; ++cnt)
1439 /* If the width is determined by an argument this is an int. */
1440 if (specs[cnt].width_arg != -1)
1441 args_type[specs[cnt].width_arg] = PA_INT;
1443 /* If the precision is determined by an argument this is an int. */
1444 if (specs[cnt].prec_arg != -1)
1445 args_type[specs[cnt].prec_arg] = PA_INT;
1447 switch (specs[cnt].ndata_args)
1449 case 0: /* No arguments. */
1451 case 1: /* One argument; we already have the type. */
1452 args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
1455 /* We have more than one argument for this format spec.
1456 We must call the arginfo function again to determine
1458 (void) (*__printf_arginfo_table[specs[cnt].info.spec])
1460 specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]);
1465 /* Now we know all the types and the order. Fill in the argument
1467 for (cnt = 0; cnt < nargs; ++cnt)
1468 switch (args_type[cnt])
1470 #define T(tag, mem, type) \
1472 args_value[cnt].mem = va_arg (ap_save, type); \
1475 T (PA_CHAR, pa_char, int); /* Promoted. */
1476 T (PA_WCHAR, pa_wchar, wint_t);
1477 T (PA_INT|PA_FLAG_SHORT, pa_short_int, int); /* Promoted. */
1478 T (PA_INT, pa_int, int);
1479 T (PA_INT|PA_FLAG_LONG, pa_long_int, long int);
1480 T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
1481 T (PA_FLOAT, pa_float, double); /* Promoted. */
1482 T (PA_DOUBLE, pa_double, double);
1483 T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double);
1484 T (PA_STRING, pa_string, const char *);
1485 T (PA_WSTRING, pa_wstring, const wchar_t *);
1486 T (PA_POINTER, pa_pointer, void *);
1489 if ((args_type[cnt] & PA_FLAG_PTR) != 0)
1490 args_value[cnt].pa_pointer = va_arg (ap_save, void *);
1492 args_value[cnt].pa_long_double = 0.0;
1496 /* Now walk through all format specifiers and process them. */
1497 for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
1500 #define REF(Name) &&do2_##Name
1502 #define LABEL(Name) do2_##Name
1508 unsigned long long int longlong;
1509 unsigned long int word;
1512 union printf_arg the_arg;
1513 char *string; /* Pointer to argument string. */
1515 /* Fill variables from values in struct. */
1516 int alt = specs[nspecs_done].info.alt;
1517 int space = specs[nspecs_done].info.space;
1518 int left = specs[nspecs_done].info.left;
1519 int showsign = specs[nspecs_done].info.showsign;
1520 int group = specs[nspecs_done].info.group;
1521 int is_long_double = specs[nspecs_done].info.is_long_double;
1522 int is_short = specs[nspecs_done].info.is_short;
1523 int is_long = specs[nspecs_done].info.is_long;
1524 int width = specs[nspecs_done].info.width;
1525 int prec = specs[nspecs_done].info.prec;
1526 char pad = specs[nspecs_done].info.pad;
1527 CHAR_T spec = specs[nspecs_done].info.spec;
1529 /* Fill in last information. */
1530 if (specs[nspecs_done].width_arg != -1)
1532 /* Extract the field width from an argument. */
1533 specs[nspecs_done].info.width =
1534 args_value[specs[nspecs_done].width_arg].pa_int;
1536 if (specs[nspecs_done].info.width < 0)
1537 /* If the width value is negative left justification is
1538 selected and the value is taken as being positive. */
1540 specs[nspecs_done].info.width *= -1;
1541 left = specs[nspecs_done].info.left = 1;
1543 width = specs[nspecs_done].info.width;
1546 if (specs[nspecs_done].prec_arg != -1)
1548 /* Extract the precision from an argument. */
1549 specs[nspecs_done].info.prec =
1550 args_value[specs[nspecs_done].prec_arg].pa_int;
1552 if (specs[nspecs_done].info.prec < 0)
1553 /* If the precision is negative the precision is
1555 specs[nspecs_done].info.prec = -1;
1557 prec = specs[nspecs_done].info.prec;
1560 /* Process format specifiers. */
1563 JUMP (spec, step4_jumps);
1565 process_arg ((&specs[nspecs_done]));
1567 LABEL (form_unknown):
1570 printf_function *function;
1575 (__printf_function_table == NULL ? NULL :
1576 __printf_function_table[specs[nspecs_done].info.spec]);
1578 if (function == NULL)
1579 function = &printf_unknown;
1581 ptr = alloca (specs[nspecs_done].ndata_args
1582 * sizeof (const void *));
1584 /* Fill in an array of pointers to the argument values. */
1585 for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
1586 ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
1588 /* Call the function. */
1589 function_done = (*function) (s, &specs[nspecs_done].info, ptr);
1591 /* If an error occurred we don't have information about #
1593 if (function_done < 0)
1599 done += function_done;
1604 /* Write the following constant string. */
1605 outstring (specs[nspecs_done].end_of_fmt,
1606 specs[nspecs_done].next_fmt
1607 - specs[nspecs_done].end_of_fmt);
1612 /* Unlock the stream. */
1613 __libc_cleanup_region_end (1);
1619 /* Handle an unknown format specifier. This prints out a canonicalized
1620 representation of the format spec itself. */
1622 printf_unknown (sFILE *s, const struct printf_info *info,
1623 const void *const *args)
1627 char work_buffer[BUFSIZ];
1638 else if (info->space)
1642 if (info->pad == '0')
1645 if (info->width != 0)
1647 w = _itoa_word (info->width, workend + 1, 10, 0);
1648 while (w <= workend)
1652 if (info->prec != -1)
1655 w = _itoa_word (info->prec, workend + 1, 10, 0);
1656 while (w <= workend)
1660 if (info->spec != '\0')
1661 outchar (info->spec);
1667 /* Group the digits according to the grouping rules of the current locale.
1668 The interpretation of GROUPING is as in `struct lconv' from <locale.h>. */
1670 group_number (CHAR_T *w, CHAR_T *rear_ptr, const CHAR_T *grouping,
1671 wchar_t thousands_sep)
1676 /* We treat all negative values like CHAR_MAX. */
1678 if (*grouping == CHAR_MAX || *grouping <= 0)
1679 /* No grouping should be done. */
1684 /* Copy existing string so that nothing gets overwritten. */
1685 src = (char *) alloca (rear_ptr - w);
1686 memcpy (src, w + 1, rear_ptr - w);
1687 s = &src[rear_ptr - w - 1];
1690 /* Process all characters in the string. */
1695 if (--len == 0 && s >= src)
1697 /* A new group begins. */
1698 *w-- = thousands_sep;
1701 if (*grouping == '\0')
1702 /* The previous grouping repeats ad infinitum. */
1704 else if (*grouping == CHAR_MAX || *grouping < 0)
1706 /* No further grouping to be done.
1707 Copy the rest of the number. */
1719 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer. */
1722 struct _IO_FILE_plus _f;
1723 _IO_FILE *_put_stream;
1724 #ifdef _IO_MTSAFE_IO
1730 _IO_helper_overflow (_IO_FILE *s, int c)
1732 _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
1733 int used = s->_IO_write_ptr - s->_IO_write_base;
1736 _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
1737 s->_IO_write_ptr -= written;
1742 static const struct _IO_jump_t _IO_helper_jumps =
1745 JUMP_INIT (finish, _IO_default_finish),
1746 JUMP_INIT (overflow, _IO_helper_overflow),
1747 JUMP_INIT (underflow, _IO_default_underflow),
1748 JUMP_INIT (uflow, _IO_default_uflow),
1749 JUMP_INIT (pbackfail, _IO_default_pbackfail),
1750 JUMP_INIT (xsputn, _IO_default_xsputn),
1751 JUMP_INIT (xsgetn, _IO_default_xsgetn),
1752 JUMP_INIT (seekoff, _IO_default_seekoff),
1753 JUMP_INIT (seekpos, _IO_default_seekpos),
1754 JUMP_INIT (setbuf, _IO_default_setbuf),
1755 JUMP_INIT (sync, _IO_default_sync),
1756 JUMP_INIT (doallocate, _IO_default_doallocate),
1757 JUMP_INIT (read, _IO_default_read),
1758 JUMP_INIT (write, _IO_default_write),
1759 JUMP_INIT (seek, _IO_default_seek),
1760 JUMP_INIT (close, _IO_default_close),
1761 JUMP_INIT (stat, _IO_default_stat)
1765 buffered_vfprintf (sFILE *s, const CHAR_T *format,
1768 char buf[_IO_BUFSIZ];
1769 struct helper_file helper;
1770 register _IO_FILE *hp = (_IO_FILE *) &helper;
1771 int result, to_flush;
1773 /* Initialize helper. */
1774 helper._put_stream = s;
1775 hp->_IO_write_base = buf;
1776 hp->_IO_write_ptr = buf;
1777 hp->_IO_write_end = buf + sizeof buf;
1778 hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
1779 #ifdef _IO_MTSAFE_IO
1780 hp->_lock = &helper.lock;
1781 __libc_lock_init (*hp->_lock);
1783 _IO_JUMPS (hp) = (struct _IO_jump_t *) &_IO_helper_jumps;
1785 /* Now print to helper instead. */
1786 result = _IO_vfprintf (hp, format, args);
1788 /* Now flush anything from the helper to the S. */
1789 if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
1791 if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
1798 #else /* !USE_IN_LIBIO */
1801 buffered_vfprintf (register FILE *s, const CHAR_T *format, va_list args)
1806 s->__bufp = s->__buffer = buf;
1807 s->__bufsize = sizeof buf;
1808 s->__put_limit = s->__buffer + s->__bufsize;
1809 s->__get_limit = s->__buffer;
1811 /* Now use buffer to print. */
1812 result = vfprintf (s, format, args);
1814 if (fflush (s) == EOF)
1816 s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL;
1822 /* Pads string with given number of a specified character.
1823 This code is taken from iopadn.c of the GNU I/O library. */
1825 static const CHAR_T blanks[PADSIZE] =
1826 { L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '),
1827 L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ') };
1828 static const CHAR_T zeroes[PADSIZE] =
1829 { L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'),
1830 L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0') };
1833 #ifndef COMPILE_WPRINTF
1834 __printf_pad (FILE *s, char pad, size_t count)
1836 __wprintf_pad (FILE *s, wchar_t pad, size_t count)
1839 const CHAR_T *padptr;
1842 padptr = pad == L_(' ') ? blanks : zeroes;
1844 for (i = count; i >= PADSIZE; i -= PADSIZE)
1845 if (PUT (s, padptr, PADSIZE) != PADSIZE)
1848 if (PUT (s, padptr, i) != i)
1854 #endif /* USE_IN_LIBIO */