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 * 4. 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 int width
; /* width from format (%8d), or 0 */
249 struct typetable types
; /* table of types */
251 fmt
= __DECONST(char *, fmt0
);
256 * Scan the format for conversions (`%' character).
259 while ((ch
= *fmt
) != '\0' && ch
!= '%')
263 fmt
++; /* skip over '%' */
269 reswitch
: switch (ch
) {
274 if ((error
= addaster(&types
, &fmt
)))
282 if ((ch
= *fmt
++) == '*') {
283 if ((error
= addaster(&types
, &fmt
)))
287 while (is_digit(ch
)) {
293 case '1': case '2': case '3': case '4':
294 case '5': case '6': case '7': case '8': case '9':
297 n
= 10 * n
+ to_digit(ch
);
299 } while (is_digit(ch
));
306 #ifndef NO_FLOATING_POINT
312 if (flags
& SHORTINT
) {
322 if (flags
& LONGINT
) {
329 flags
|= LLONGINT
; /* not necessarily */
341 error
= addtype(&types
,
342 (flags
& LONGINT
) ? T_WINT
: T_INT
);
351 if ((error
= addsarg(&types
, flags
)))
354 #ifndef NO_FLOATING_POINT
362 error
= addtype(&types
,
363 (flags
& LONGDBL
) ? T_LONG_DOUBLE
: T_DOUBLE
);
367 #endif /* !NO_FLOATING_POINT */
370 error
= addtype(&types
, TP_INTMAXT
);
371 else if (flags
& PTRDIFFT
)
372 error
= addtype(&types
, TP_PTRDIFFT
);
373 else if (flags
& SIZET
)
374 error
= addtype(&types
, TP_SSIZET
);
375 else if (flags
& LLONGINT
)
376 error
= addtype(&types
, TP_LLONG
);
377 else if (flags
& LONGINT
)
378 error
= addtype(&types
, TP_LONG
);
379 else if (flags
& SHORTINT
)
380 error
= addtype(&types
, TP_SHORT
);
381 else if (flags
& CHARINT
)
382 error
= addtype(&types
, TP_SCHAR
);
384 error
= addtype(&types
, TP_INT
);
387 continue; /* no output */
392 if ((error
= adduarg(&types
, flags
)))
396 if ((error
= addtype(&types
, TP_VOID
)))
403 error
= addtype(&types
,
404 (flags
& LONGINT
) ? TP_WCHAR
: TP_CHAR
);
414 if ((error
= adduarg(&types
, flags
)))
417 default: /* "%?" prints ?, unless ? is NUL */
424 build_arg_table(&types
, ap
, argtable
);
427 return (error
|| *argtable
== NULL
);
430 /* wchar version of __find_arguments. */
432 __find_warguments(const wchar_t *fmt0
, va_list ap
, union arg
**argtable
)
434 wchar_t *fmt
; /* format string */
435 wchar_t ch
; /* character from fmt */
436 int n
; /* handy integer (short term usage) */
438 int flags
; /* flags as above */
439 int width
; /* width from format (%8d), or 0 */
440 struct typetable types
; /* table of types */
442 fmt
= __DECONST(wchar_t *, fmt0
);
447 * Scan the format for conversions (`%' character).
450 while ((ch
= *fmt
) != '\0' && ch
!= '%')
454 fmt
++; /* skip over '%' */
460 reswitch
: switch (ch
) {
465 if ((error
= addwaster(&types
, &fmt
)))
473 if ((ch
= *fmt
++) == '*') {
474 if ((error
= addwaster(&types
, &fmt
)))
478 while (is_digit(ch
)) {
484 case '1': case '2': case '3': case '4':
485 case '5': case '6': case '7': case '8': case '9':
488 n
= 10 * n
+ to_digit(ch
);
490 } while (is_digit(ch
));
497 #ifndef NO_FLOATING_POINT
503 if (flags
& SHORTINT
) {
513 if (flags
& LONGINT
) {
520 flags
|= LLONGINT
; /* not necessarily */
532 error
= addtype(&types
,
533 (flags
& LONGINT
) ? T_WINT
: T_INT
);
542 if ((error
= addsarg(&types
, flags
)))
545 #ifndef NO_FLOATING_POINT
553 error
= addtype(&types
,
554 (flags
& LONGDBL
) ? T_LONG_DOUBLE
: T_DOUBLE
);
558 #endif /* !NO_FLOATING_POINT */
561 error
= addtype(&types
, TP_INTMAXT
);
562 else if (flags
& PTRDIFFT
)
563 error
= addtype(&types
, TP_PTRDIFFT
);
564 else if (flags
& SIZET
)
565 error
= addtype(&types
, TP_SSIZET
);
566 else if (flags
& LLONGINT
)
567 error
= addtype(&types
, TP_LLONG
);
568 else if (flags
& LONGINT
)
569 error
= addtype(&types
, TP_LONG
);
570 else if (flags
& SHORTINT
)
571 error
= addtype(&types
, TP_SHORT
);
572 else if (flags
& CHARINT
)
573 error
= addtype(&types
, TP_SCHAR
);
575 error
= addtype(&types
, TP_INT
);
578 continue; /* no output */
583 if ((error
= adduarg(&types
, flags
)))
587 if ((error
= addtype(&types
, TP_VOID
)))
594 error
= addtype(&types
,
595 (flags
& LONGINT
) ? TP_WCHAR
: TP_CHAR
);
605 if ((error
= adduarg(&types
, flags
)))
608 default: /* "%?" prints ?, unless ? is NUL */
615 build_arg_table(&types
, ap
, argtable
);
618 return (error
|| *argtable
== NULL
);
622 * Increase the size of the type table. Returns 0 on success.
625 __grow_type_table(struct typetable
*types
)
627 enum typeid *const oldtable
= types
->table
;
628 const int oldsize
= types
->tablesize
;
629 enum typeid *newtable
;
630 int n
, newsize
= oldsize
* 2;
632 if (newsize
< types
->nextarg
+ 1)
633 newsize
= types
->nextarg
+ 1;
634 if (oldsize
== STATIC_ARG_TBL_SIZE
) {
635 if ((newtable
= malloc(newsize
* sizeof(enum typeid))) == NULL
)
637 bcopy(oldtable
, newtable
, oldsize
* sizeof(enum typeid));
639 newtable
= realloc(oldtable
, newsize
* sizeof(enum typeid));
640 if (newtable
== NULL
)
643 for (n
= oldsize
; n
< newsize
; n
++)
644 newtable
[n
] = T_UNUSED
;
646 types
->table
= newtable
;
647 types
->tablesize
= newsize
;
653 * Build the argument table from the completed type table.
654 * On malloc failure, *argtable is set to NULL.
657 build_arg_table(struct typetable
*types
, va_list ap
, union arg
**argtable
)
661 if (types
->tablemax
>= STATIC_ARG_TBL_SIZE
) {
662 *argtable
= (union arg
*)
663 malloc (sizeof (union arg
) * (types
->tablemax
+ 1));
664 if (*argtable
== NULL
)
668 (*argtable
) [0].intarg
= 0;
669 for (n
= 1; n
<= types
->tablemax
; n
++) {
670 switch (types
->table
[n
]) {
671 case T_UNUSED
: /* whoops! */
672 (*argtable
) [n
].intarg
= va_arg(ap
, int);
675 (*argtable
) [n
].pschararg
= va_arg(ap
, signed char *);
678 (*argtable
) [n
].pshortarg
= va_arg(ap
, short *);
681 (*argtable
) [n
].intarg
= va_arg(ap
, int);
684 (*argtable
) [n
].uintarg
= va_arg(ap
, unsigned int);
687 (*argtable
) [n
].pintarg
= va_arg(ap
, int *);
690 (*argtable
) [n
].longarg
= va_arg(ap
, long);
693 (*argtable
) [n
].ulongarg
= va_arg(ap
, unsigned long);
696 (*argtable
) [n
].plongarg
= va_arg(ap
, long *);
699 (*argtable
) [n
].longlongarg
= va_arg(ap
, long long);
702 (*argtable
) [n
].ulonglongarg
= va_arg(ap
, unsigned long long);
705 (*argtable
) [n
].plonglongarg
= va_arg(ap
, long long *);
708 (*argtable
) [n
].ptrdiffarg
= va_arg(ap
, ptrdiff_t);
711 (*argtable
) [n
].pptrdiffarg
= va_arg(ap
, ptrdiff_t *);
714 (*argtable
) [n
].sizearg
= va_arg(ap
, size_t);
717 (*argtable
) [n
].sizearg
= va_arg(ap
, ssize_t
);
720 (*argtable
) [n
].pssizearg
= va_arg(ap
, ssize_t
*);
723 (*argtable
) [n
].intmaxarg
= va_arg(ap
, intmax_t);
726 (*argtable
) [n
].uintmaxarg
= va_arg(ap
, uintmax_t);
729 (*argtable
) [n
].pintmaxarg
= va_arg(ap
, intmax_t *);
732 #ifndef NO_FLOATING_POINT
733 (*argtable
) [n
].doublearg
= va_arg(ap
, double);
737 #ifndef NO_FLOATING_POINT
738 (*argtable
) [n
].longdoublearg
= va_arg(ap
, long double);
742 (*argtable
) [n
].pchararg
= va_arg(ap
, char *);
745 (*argtable
) [n
].pvoidarg
= va_arg(ap
, void *);
748 (*argtable
) [n
].wintarg
= va_arg(ap
, wint_t);
751 (*argtable
) [n
].pwchararg
= va_arg(ap
, wchar_t *);