2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * @(#)vfprintf.c 8.1 (Berkeley) 6/4/93
33 * $FreeBSD: src/lib/libc/stdio/printf-pos.c,v 1.6 2009/03/02 04:07:58 das Exp $
37 * This is the code responsible for handling positional arguments
38 * (%m$ and %m$.n$) for vfprintf() and vfwprintf().
41 #include "namespace.h"
42 #include <sys/types.h>
52 #include "un-namespace.h"
53 #include "printflocal.h"
56 * Type ids for argument type table.
59 T_UNUSED
, TP_SHORT
, T_INT
, T_U_INT
, TP_INT
,
60 T_LONG
, T_U_LONG
, TP_LONG
, T_LLONG
, T_U_LLONG
, TP_LLONG
,
61 T_PTRDIFFT
, TP_PTRDIFFT
, T_SSIZET
, T_SIZET
, TP_SSIZET
,
62 T_INTMAXT
, T_UINTMAXT
, TP_INTMAXT
, TP_VOID
, TP_CHAR
, TP_SCHAR
,
63 T_DOUBLE
, T_LONG_DOUBLE
, T_WINT
, TP_WCHAR
66 /* An expandable array of types. */
68 enum typeid *table
; /* table of types */
69 enum typeid stattable
[STATIC_ARG_TBL_SIZE
];
70 int tablesize
; /* current size of type table */
71 int tablemax
; /* largest used index in table */
72 int nextarg
; /* 1-based argument index */
75 static int __grow_type_table(struct typetable
*);
76 static void build_arg_table (struct typetable
*, va_list, union arg
**);
79 * Initialize a struct typetable.
82 inittypes(struct typetable
*types
)
86 types
->table
= types
->stattable
;
87 types
->tablesize
= STATIC_ARG_TBL_SIZE
;
90 for (n
= 0; n
< STATIC_ARG_TBL_SIZE
; n
++)
91 types
->table
[n
] = T_UNUSED
;
95 * struct typetable destructor.
98 freetypes(struct typetable
*types
)
101 if (types
->table
!= types
->stattable
)
106 * Ensure that there is space to add a new argument type to the type table.
107 * Expand the table if necessary. Returns 0 on success.
110 _ensurespace(struct typetable
*types
)
113 if (types
->nextarg
>= types
->tablesize
) {
114 if (__grow_type_table(types
))
117 if (types
->nextarg
> types
->tablemax
)
118 types
->tablemax
= types
->nextarg
;
123 * Add an argument type to the table, expanding if necessary.
124 * Returns 0 on success.
127 addtype(struct typetable
*types
, enum typeid type
)
130 if (_ensurespace(types
))
132 types
->table
[types
->nextarg
++] = type
;
137 addsarg(struct typetable
*types
, int flags
)
140 if (_ensurespace(types
))
143 types
->table
[types
->nextarg
++] = T_INTMAXT
;
144 else if (flags
& SIZET
)
145 types
->table
[types
->nextarg
++] = T_SSIZET
;
146 else if (flags
& PTRDIFFT
)
147 types
->table
[types
->nextarg
++] = T_PTRDIFFT
;
148 else if (flags
& LLONGINT
)
149 types
->table
[types
->nextarg
++] = T_LLONG
;
150 else if (flags
& LONGINT
)
151 types
->table
[types
->nextarg
++] = T_LONG
;
153 types
->table
[types
->nextarg
++] = T_INT
;
158 adduarg(struct typetable
*types
, int flags
)
161 if (_ensurespace(types
))
164 types
->table
[types
->nextarg
++] = T_UINTMAXT
;
165 else if (flags
& SIZET
)
166 types
->table
[types
->nextarg
++] = T_SIZET
;
167 else if (flags
& PTRDIFFT
)
168 types
->table
[types
->nextarg
++] = T_SIZET
;
169 else if (flags
& LLONGINT
)
170 types
->table
[types
->nextarg
++] = T_U_LLONG
;
171 else if (flags
& LONGINT
)
172 types
->table
[types
->nextarg
++] = T_U_LONG
;
174 types
->table
[types
->nextarg
++] = T_U_INT
;
179 * Add * arguments to the type array.
182 addaster(struct typetable
*types
, char **fmtp
)
189 while (is_digit(*cp
)) {
190 n2
= 10 * n2
+ to_digit(*cp
);
194 int hold
= types
->nextarg
;
196 if (addtype(types
, T_INT
))
198 types
->nextarg
= hold
;
201 if (addtype(types
, T_INT
))
208 addwaster(struct typetable
*types
, wchar_t **fmtp
)
215 while (is_digit(*cp
)) {
216 n2
= 10 * n2
+ to_digit(*cp
);
220 int hold
= types
->nextarg
;
222 if (addtype(types
, T_INT
))
224 types
->nextarg
= hold
;
227 if (addtype(types
, T_INT
))
234 * Find all arguments when a positional parameter is encountered. Returns a
235 * table, indexed by argument number, of pointers to each arguments. The
236 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
237 * It will be replaces with a malloc-ed one if it overflows.
238 * Returns 0 on success. On failure, returns nonzero and sets errno.
241 __find_arguments(const char *fmt0
, va_list ap
, union arg
**argtable
)
243 char *fmt
; /* format string */
244 int ch
; /* character from fmt */
245 int n
; /* handy integer (short term usage) */
247 int flags
; /* flags as above */
248 struct typetable types
; /* table of types */
250 fmt
= __DECONST(char *, fmt0
);
255 * Scan the format for conversions (`%' character).
258 while ((ch
= *fmt
) != '\0' && ch
!= '%')
262 fmt
++; /* skip over '%' */
267 reswitch
: switch (ch
) {
272 if ((error
= addaster(&types
, &fmt
)))
280 if ((ch
= *fmt
++) == '*') {
281 if ((error
= addaster(&types
, &fmt
)))
285 while (is_digit(ch
)) {
291 case '1': case '2': case '3': case '4':
292 case '5': case '6': case '7': case '8': case '9':
295 n
= 10 * n
+ to_digit(ch
);
297 } while (is_digit(ch
));
303 #ifndef NO_FLOATING_POINT
309 if (flags
& SHORTINT
) {
319 if (flags
& LONGINT
) {
326 flags
|= LLONGINT
; /* not necessarily */
338 error
= addtype(&types
,
339 (flags
& LONGINT
) ? T_WINT
: T_INT
);
348 if ((error
= addsarg(&types
, flags
)))
351 #ifndef NO_FLOATING_POINT
359 error
= addtype(&types
,
360 (flags
& LONGDBL
) ? T_LONG_DOUBLE
: T_DOUBLE
);
364 #endif /* !NO_FLOATING_POINT */
367 error
= addtype(&types
, TP_INTMAXT
);
368 else if (flags
& PTRDIFFT
)
369 error
= addtype(&types
, TP_PTRDIFFT
);
370 else if (flags
& SIZET
)
371 error
= addtype(&types
, TP_SSIZET
);
372 else if (flags
& LLONGINT
)
373 error
= addtype(&types
, TP_LLONG
);
374 else if (flags
& LONGINT
)
375 error
= addtype(&types
, TP_LONG
);
376 else if (flags
& SHORTINT
)
377 error
= addtype(&types
, TP_SHORT
);
378 else if (flags
& CHARINT
)
379 error
= addtype(&types
, TP_SCHAR
);
381 error
= addtype(&types
, TP_INT
);
384 continue; /* no output */
389 if ((error
= adduarg(&types
, flags
)))
393 if ((error
= addtype(&types
, TP_VOID
)))
400 error
= addtype(&types
,
401 (flags
& LONGINT
) ? TP_WCHAR
: TP_CHAR
);
411 if ((error
= adduarg(&types
, flags
)))
414 default: /* "%?" prints ?, unless ? is NUL */
421 build_arg_table(&types
, ap
, argtable
);
424 return (error
|| *argtable
== NULL
);
427 /* wchar version of __find_arguments. */
429 __find_warguments(const wchar_t *fmt0
, va_list ap
, union arg
**argtable
)
431 wchar_t *fmt
; /* format string */
432 wchar_t ch
; /* character from fmt */
433 int n
; /* handy integer (short term usage) */
435 int flags
; /* flags as above */
436 struct typetable types
; /* table of types */
438 fmt
= __DECONST(wchar_t *, fmt0
);
443 * Scan the format for conversions (`%' character).
446 while ((ch
= *fmt
) != '\0' && ch
!= '%')
450 fmt
++; /* skip over '%' */
455 reswitch
: switch (ch
) {
460 if ((error
= addwaster(&types
, &fmt
)))
468 if ((ch
= *fmt
++) == '*') {
469 if ((error
= addwaster(&types
, &fmt
)))
473 while (is_digit(ch
)) {
479 case '1': case '2': case '3': case '4':
480 case '5': case '6': case '7': case '8': case '9':
483 n
= 10 * n
+ to_digit(ch
);
485 } while (is_digit(ch
));
491 #ifndef NO_FLOATING_POINT
497 if (flags
& SHORTINT
) {
507 if (flags
& LONGINT
) {
514 flags
|= LLONGINT
; /* not necessarily */
526 error
= addtype(&types
,
527 (flags
& LONGINT
) ? T_WINT
: T_INT
);
536 if ((error
= addsarg(&types
, flags
)))
539 #ifndef NO_FLOATING_POINT
547 error
= addtype(&types
,
548 (flags
& LONGDBL
) ? T_LONG_DOUBLE
: T_DOUBLE
);
552 #endif /* !NO_FLOATING_POINT */
555 error
= addtype(&types
, TP_INTMAXT
);
556 else if (flags
& PTRDIFFT
)
557 error
= addtype(&types
, TP_PTRDIFFT
);
558 else if (flags
& SIZET
)
559 error
= addtype(&types
, TP_SSIZET
);
560 else if (flags
& LLONGINT
)
561 error
= addtype(&types
, TP_LLONG
);
562 else if (flags
& LONGINT
)
563 error
= addtype(&types
, TP_LONG
);
564 else if (flags
& SHORTINT
)
565 error
= addtype(&types
, TP_SHORT
);
566 else if (flags
& CHARINT
)
567 error
= addtype(&types
, TP_SCHAR
);
569 error
= addtype(&types
, TP_INT
);
572 continue; /* no output */
577 if ((error
= adduarg(&types
, flags
)))
581 if ((error
= addtype(&types
, TP_VOID
)))
588 error
= addtype(&types
,
589 (flags
& LONGINT
) ? TP_WCHAR
: TP_CHAR
);
599 if ((error
= adduarg(&types
, flags
)))
602 default: /* "%?" prints ?, unless ? is NUL */
609 build_arg_table(&types
, ap
, argtable
);
612 return (error
|| *argtable
== NULL
);
616 * Increase the size of the type table. Returns 0 on success.
619 __grow_type_table(struct typetable
*types
)
621 enum typeid *const oldtable
= types
->table
;
622 const int oldsize
= types
->tablesize
;
623 enum typeid *newtable
;
624 int n
, newsize
= oldsize
* 2;
626 if (newsize
< types
->nextarg
+ 1)
627 newsize
= types
->nextarg
+ 1;
628 if (oldsize
== STATIC_ARG_TBL_SIZE
) {
629 if ((newtable
= malloc(newsize
* sizeof(enum typeid))) == NULL
)
631 bcopy(oldtable
, newtable
, oldsize
* sizeof(enum typeid));
633 newtable
= realloc(oldtable
, newsize
* sizeof(enum typeid));
634 if (newtable
== NULL
)
637 for (n
= oldsize
; n
< newsize
; n
++)
638 newtable
[n
] = T_UNUSED
;
640 types
->table
= newtable
;
641 types
->tablesize
= newsize
;
647 * Build the argument table from the completed type table.
648 * On malloc failure, *argtable is set to NULL.
651 build_arg_table(struct typetable
*types
, va_list ap
, union arg
**argtable
)
655 if (types
->tablemax
>= STATIC_ARG_TBL_SIZE
) {
656 *argtable
= (union arg
*)
657 malloc (sizeof (union arg
) * (types
->tablemax
+ 1));
658 if (*argtable
== NULL
)
662 (*argtable
) [0].intarg
= 0;
663 for (n
= 1; n
<= types
->tablemax
; n
++) {
664 switch (types
->table
[n
]) {
665 case T_UNUSED
: /* whoops! */
666 (*argtable
) [n
].intarg
= va_arg(ap
, int);
669 (*argtable
) [n
].pschararg
= va_arg(ap
, signed char *);
672 (*argtable
) [n
].pshortarg
= va_arg(ap
, short *);
675 (*argtable
) [n
].intarg
= va_arg(ap
, int);
678 (*argtable
) [n
].uintarg
= va_arg(ap
, unsigned int);
681 (*argtable
) [n
].pintarg
= va_arg(ap
, int *);
684 (*argtable
) [n
].longarg
= va_arg(ap
, long);
687 (*argtable
) [n
].ulongarg
= va_arg(ap
, unsigned long);
690 (*argtable
) [n
].plongarg
= va_arg(ap
, long *);
693 (*argtable
) [n
].longlongarg
= va_arg(ap
, long long);
696 (*argtable
) [n
].ulonglongarg
= va_arg(ap
, unsigned long long);
699 (*argtable
) [n
].plonglongarg
= va_arg(ap
, long long *);
702 (*argtable
) [n
].ptrdiffarg
= va_arg(ap
, ptrdiff_t);
705 (*argtable
) [n
].pptrdiffarg
= va_arg(ap
, ptrdiff_t *);
708 (*argtable
) [n
].sizearg
= va_arg(ap
, size_t);
711 (*argtable
) [n
].sizearg
= va_arg(ap
, ssize_t
);
714 (*argtable
) [n
].pssizearg
= va_arg(ap
, ssize_t
*);
717 (*argtable
) [n
].intmaxarg
= va_arg(ap
, intmax_t);
720 (*argtable
) [n
].uintmaxarg
= va_arg(ap
, uintmax_t);
723 (*argtable
) [n
].pintmaxarg
= va_arg(ap
, intmax_t *);
726 #ifndef NO_FLOATING_POINT
727 (*argtable
) [n
].doublearg
= va_arg(ap
, double);
731 #ifndef NO_FLOATING_POINT
732 (*argtable
) [n
].longdoublearg
= va_arg(ap
, long double);
736 (*argtable
) [n
].pchararg
= va_arg(ap
, char *);
739 (*argtable
) [n
].pvoidarg
= va_arg(ap
, void *);
742 (*argtable
) [n
].wintarg
= va_arg(ap
, wint_t);
745 (*argtable
) [n
].pwchararg
= va_arg(ap
, wchar_t *);