]>
git.proxmox.com Git - mirror_frr.git/blob - lib/printf/vfprintf.c
2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Copyright (c) 2011 The FreeBSD Foundation
11 * All rights reserved.
12 * Portions of this software were developed by David Chisnall
13 * under sponsorship from the FreeBSD Foundation.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 #ifdef HAVE_SYS_CDEFS_H
45 #include <sys/cdefs.h>
49 * Actual printf innards.
51 * This code is large and complicated...
54 #include <sys/types.h>
69 #include "printflocal.h"
72 #include "printfcommon.h"
76 * Convert a wide character string argument for the %ls format to a multibyte
77 * string representation. If not -1, prec specifies the maximum number of
78 * bytes to output, and also means that we can't assume that the wide char.
79 * string ends is null-terminated.
82 __wcsconv(wchar_t *wcsarg
, int prec
)
84 static const mbstate_t initial
;
91 /* Allocate space for the maximum number of bytes we could output. */
95 nbytes
= wcsrtombs(NULL
, (const wchar_t **)&p
, 0, &mbs
);
96 if (nbytes
== (size_t)-1)
100 * Optimisation: if the output precision is small enough,
101 * just allocate enough memory for the maximum instead of
102 * scanning the string.
111 clen
= wcrtomb(buf
, *p
++, &mbs
);
112 if (clen
== 0 || clen
== (size_t)-1 ||
113 nbytes
+ clen
> (size_t)prec
)
119 if ((convbuf
= malloc(nbytes
+ 1)) == NULL
)
122 /* Fill the output buffer. */
125 if ((nbytes
= wcsrtombs(convbuf
, (const wchar_t **)&p
,
126 nbytes
, &mbs
)) == (size_t)-1) {
130 convbuf
[nbytes
] = '\0';
133 #endif /* WCHAR_SUPPORT */
136 * The size of the buffer we use as scratch space for integer
137 * conversions, among other things. We need enough space to
138 * write a uintmax_t in octal (plus one byte).
140 #if UINTMAX_MAX <= UINT64_MAX
143 #error "BUF must be large enough to format a uintmax_t"
147 * Non-MT-safe version
150 vbprintfrr(struct fbuf
*cb_in
, const char *fmt0
, va_list ap
)
152 const char *fmt
; /* format string */
153 int ch
; /* character from fmt */
154 int n
, n2
; /* handy integer (short term usage) */
155 const char *cp
; /* handy char pointer (short term usage) */
156 int flags
; /* flags as above */
157 int ret
; /* return value accumulator */
158 int width
; /* width from format (%8d), or 0 */
159 int prec
; /* precision from format; <0 for N/A */
161 char sign
; /* sign prefix (' ', '+', '-', or \0) */
163 u_long ulval
= 0; /* integer arguments %[diouxX] */
164 uintmax_t ujval
= 0; /* %j, %ll, %q, %t, %z integers */
165 void *ptrval
; /* %p */
166 int base
; /* base for [diouxX] conversion */
167 int dprec
; /* a copy of prec if [diouxX], 0 otherwise */
168 int realsz
; /* field size expanded by dprec, sign, etc */
169 int size
; /* size of converted field or string */
170 int prsize
; /* max size of printed field */
171 const char *xdigs
; /* digits for %[xX] conversion */
172 struct io_state io
; /* I/O buffering state */
173 char buf
[BUF
]; /* buffer with space for digits of uintmax_t */
174 char ox
[2]; /* space for 0x; ox[1] is either x, X, or \0 */
175 union arg
*argtable
; /* args, built due to positional arg */
176 union arg statargtable
[STATIC_ARG_TBL_SIZE
];
177 int nextarg
; /* 1-based argument index */
178 va_list orgap
; /* original argument pointer */
179 char *convbuf
; /* wide to multibyte conversion result */
180 char *extstart
= NULL
; /* where printfrr_ext* started printing */
181 struct fbuf cb_copy
, *cb
;
182 struct fmt_outpos
*opos
;
184 static const char xdigs_lower
[16] = "0123456789abcdef";
185 static const char xdigs_upper
[16] = "0123456789ABCDEF";
187 /* BEWARE, these `goto error' on error. */
188 #define PRINT(ptr, len) { \
189 if (io_print(&io, (ptr), (len))) \
192 #define PAD(howmany, with) { \
193 if (io_pad(&io, (howmany), (with))) \
196 #define PRINTANDPAD(p, ep, len, with) { \
197 if (io_printandpad(&io, (p), (ep), (len), (with))) \
200 #define FLUSH() do { } while (0)
203 * Get the argument indexed by nextarg. If the argument table is
204 * built, use it to get the argument. If its not, get the next
205 * argument (and arguments must be gotten sequentially).
207 #define GETARG(type) \
208 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
209 (nextarg++, va_arg(ap, type)))
212 * To extend shorts properly, we need both signed and unsigned
213 * argument extraction methods.
216 (flags&LONGINT ? GETARG(long) : \
217 flags&SHORTINT ? (long)(short)GETARG(int) : \
218 flags&CHARINT ? (long)(signed char)GETARG(int) : \
221 (flags&LONGINT ? GETARG(u_long) : \
222 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
223 flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
224 (u_long)GETARG(u_int))
225 #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT|LONGDBL)
227 (flags&LONGDBL ? GETARG(int64_t) : \
228 flags&INTMAXT ? GETARG(intmax_t) : \
229 flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
230 flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
231 (intmax_t)GETARG(long long))
233 (flags&LONGDBL ? GETARG(uint64_t) : \
234 flags&INTMAXT ? GETARG(uintmax_t) : \
235 flags&SIZET ? (uintmax_t)GETARG(size_t) : \
236 flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
237 (uintmax_t)GETARG(unsigned long long))
240 * Get * arguments, including the form *nn$. Preserve the nextarg
241 * that the argument can be gotten once the type is determined.
243 #define GETASTER(val) \
246 while (is_digit(*cp)) { \
247 n2 = 10 * n2 + to_digit(*cp); \
251 int hold = nextarg; \
252 if (argtable == NULL) { \
253 argtable = statargtable; \
254 if (_frr_find_arguments (fmt0, orgap, &argtable)) { \
260 val = GETARG (int); \
264 val = GETARG (int); \
276 /* prevent printfrr exts from polluting cb->outpos */
278 cb_copy
.outpos
= NULL
;
279 cb_copy
.outpos_n
= cb_copy
.outpos_i
= 0;
288 * Scan the format for conversions (`%' character).
291 for (cp
= fmt
; (ch
= *fmt
) != '\0' && ch
!= '%'; fmt
++)
293 if ((n
= fmt
- cp
) != 0) {
294 if ((unsigned)ret
+ n
> INT_MAX
) {
304 fmt
++; /* skip over '%' */
313 if (cb_in
&& cb_in
->outpos_i
< cb_in
->outpos_n
)
314 opos
= &cb_in
->outpos
[cb_in
->outpos_i
];
319 reswitch
: switch (ch
) {
322 * ``If the space and + flags both appear, the space
323 * flag will be ignored.''
334 * ``A negative field width argument is taken as a
335 * - flag followed by a positive field width.''
337 * They don't exclude field widths read from args.
354 if ((ch
= *fmt
++) == '*') {
359 while (is_digit(ch
)) {
360 prec
= 10 * prec
+ to_digit(ch
);
366 * ``Note that 0 is taken as a flag, not as the
367 * beginning of a field width.''
372 case '1': case '2': case '3': case '4':
373 case '5': case '6': case '7': case '8': case '9':
376 n
= 10 * n
+ to_digit(ch
);
378 } while (is_digit(ch
));
381 if (argtable
== NULL
) {
382 argtable
= statargtable
;
383 if (_frr_find_arguments (fmt0
, orgap
,
397 if (flags
& SHORTINT
) {
407 if (flags
& LONGINT
) {
414 flags
|= LLONGINT
; /* not necessarily */
427 if (flags
& LONGINT
) {
428 static const mbstate_t initial
;
433 mbseqlen
= wcrtomb(cp
= buf
,
434 (wchar_t)GETARG(wint_t), &mbs
);
435 if (mbseqlen
== (size_t)-1) {
438 size
= (int)mbseqlen
;
440 #endif /* WCHAR_SUPPORT */
442 buf
[0] = GETARG(int);
453 if (flags
& INTMAX_SIZE
)
458 if (printfrr_ext_char(fmt
[0])) {
459 struct printfrr_eargs ea
= {
463 .alt_repr
= !!(flags
& ALT
),
464 .leftadj
= !!(flags
& LADJUST
),
470 size
= printfrr_exti(cb
, &ea
,
471 (flags
& INTMAX_SIZE
) ? ujval
479 if (flags
& INTMAX_SIZE
) {
480 if ((intmax_t)ujval
< 0) {
485 if ((long)ulval
< 0) {
492 #ifndef NO_FLOATING_POINT
501 if (flags
& LONGDBL
) {
502 long double arg
= GETARG(long double);
503 char fmt
[6] = "%.*L";
507 snprintf(buf
, sizeof(buf
), fmt
, prec
, arg
);
509 double arg
= GETARG(double);
514 snprintf(buf
, sizeof(buf
), fmt
, prec
, arg
);
517 /* for proper padding */
523 if (!is_digit(*cp
) && *cp
!= '.')
529 cp
= strerror(saved_errno
);
530 size
= (prec
>= 0) ? strnlen(cp
, prec
) : strlen(cp
);
537 if (flags
& INTMAX_SIZE
)
545 * ``The argument shall be a pointer to void. The
546 * value of the pointer is converted to a sequence
547 * of printable characters, in an implementation-
551 ptrval
= GETARG(void *);
552 if (printfrr_ext_char(fmt
[0])) {
553 struct printfrr_eargs ea
= {
557 .alt_repr
= !!(flags
& ALT
),
558 .leftadj
= !!(flags
& LADJUST
),
564 size
= printfrr_extp(cb
, &ea
, ptrval
);
571 ujval
= (uintmax_t)(uintptr_t)ptrval
;
574 flags
= flags
| INTMAXT
;
582 if (flags
& LONGINT
) {
587 if ((wcp
= GETARG(wchar_t *)) == NULL
)
590 convbuf
= __wcsconv(wcp
, prec
);
591 if (convbuf
== NULL
) {
598 if ((cp
= GETARG(char *)) == NULL
)
600 size
= (prec
>= 0) ? strnlen(cp
, prec
) : strlen(cp
);
607 if (flags
& INTMAX_SIZE
)
619 if (flags
& INTMAX_SIZE
)
624 /* leading 0x/X only if non-zero */
626 (flags
& INTMAX_SIZE
? ujval
!= 0 : ulval
!= 0))
630 /* unsigned conversions */
633 * ``... diouXx conversions ... if a precision is
634 * specified, the 0 flag will be ignored.''
637 number
: if ((dprec
= prec
) >= 0)
641 * ``The result of converting a zero value with an
642 * explicit precision of zero is no characters.''
645 * ``The C Standard is clear enough as is. The call
646 * printf("%#.0o", 0) should print 0.''
647 * -- Defect Report #151
650 if (flags
& INTMAX_SIZE
) {
651 if (ujval
!= 0 || prec
!= 0 ||
652 (flags
& ALT
&& base
== 8))
653 cp
= __ujtoa(ujval
, buf
+ BUF
, base
,
656 if (ulval
!= 0 || prec
!= 0 ||
657 (flags
& ALT
&& base
== 8))
658 cp
= __ultoa(ulval
, buf
+ BUF
, base
,
661 size
= buf
+ BUF
- cp
;
662 if (size
> BUF
) /* should never happen */
665 default: /* "%?" prints ?, unless ? is NUL */
668 /* pretend it was %c with argument ch */
678 * All reasonable formats wind up here. At this point, `cp'
679 * points to a string which (if not flags&LADJUST) should be
680 * padded out to `width' places. If flags&ZEROPAD, it should
681 * first be prefixed by any sign or other prefix; otherwise,
682 * it should be blank padded before the prefix is emitted.
683 * After any left-hand padding and prefixing, emit zeroes
684 * required by a decimal [diouxX] precision, then print the
685 * string proper, then emit zeroes required by any leftover
686 * floating precision; finally, if LADJUST, pad with blanks.
688 * Compute actual size, so we know how much to pad.
689 * size excludes decimal prec; realsz includes it.
694 realsz
= dprec
> size
? dprec
: size
;
700 prsize
= width
> realsz
? width
: realsz
;
701 if ((unsigned int)ret
+ prsize
> INT_MAX
) {
707 /* right-adjusting blank padding */
708 if ((flags
& (LADJUST
|ZEROPAD
)) == 0)
709 PAD(width
- realsz
, blanks
);
712 opos
->off_start
= cb
->pos
- cb
->buf
;
718 if (ox
[1]) { /* ox[1] is either x, X, or \0 */
723 /* right-adjusting zero padding */
724 if ((flags
& (LADJUST
|ZEROPAD
)) == ZEROPAD
)
725 PAD(width
- realsz
, zeroes
);
727 /* the string or number proper */
728 /* leading zeroes from decimal precision */
729 PAD(dprec
- size
, zeroes
);
733 opos
->off_end
= cb
->pos
- cb
->buf
;
737 /* left-adjusting padding (always blank) */
739 PAD(width
- realsz
, blanks
);
741 /* finally, adjust ret */
744 FLUSH(); /* copy out the I/O vectors */
748 /* when we arrive here, a printfrr extension has written to cb
749 * (if non-NULL), but we still need to handle padding. The
750 * original cb->pos is in extstart; the return value from the
753 * Keep analogous to code above please.
760 prsize
= width
> realsz
? width
: realsz
;
761 if ((unsigned int)ret
+ prsize
> INT_MAX
) {
767 /* right-adjusting blank padding - need to move the chars
768 * that the extension has already written. Should be very
771 if (cb
&& width
> size
&& (flags
& (LADJUST
|ZEROPAD
)) == 0) {
772 size_t nwritten
= cb
->pos
- extstart
;
773 size_t navail
= cb
->buf
+ cb
->len
- extstart
;
774 size_t npad
= width
- realsz
;
781 nmove
= MIN(nwritten
, navail
);
783 memmove(extstart
+ npad
, extstart
, nmove
);
791 io
.avail
= cb
? cb
->len
- (cb
->pos
- cb
->buf
) : 0;
793 if (opos
&& extstart
<= cb
->pos
) {
794 opos
->off_start
= extstart
- cb
->buf
;
795 opos
->off_end
= cb
->pos
- cb
->buf
;
799 /* left-adjusting padding (always blank) */
801 PAD(width
- realsz
, blanks
);
803 /* finally, adjust ret */
806 FLUSH(); /* copy out the I/O vectors */
814 if ((argtable
!= NULL
) && (argtable
!= statargtable
))
817 cb_in
->pos
= cb
->pos
;