2192974dc546d73173c966e6d57e0fa72f006edc
3 * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
4 * Copyright (C) Linux kernel developers
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 3 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * vsnprintf - Format a string and place it in a buffer
27 * @buf: The buffer to place the result into
28 * @size: The size of the buffer, including the trailing null space
29 * @fmt: The format string to use
30 * @args: Arguments for the format string
32 * The return value is the number of characters which would
33 * be generated for the given input, excluding the trailing
34 * '\0', as per ISO C99. If you want to have the exact
35 * number of characters written into @buf as return value
36 * (not including the trailing '\0'), use vscnprintf(). If the
37 * return is greater than or equal to @size, the resulting
38 * string is truncated.
40 * Call this function if you are already dealing with a va_list.
41 * You probably want snprintf() instead.
43 int vsnprintf(char *buf
, size_t size
, const char *fmt
, va_list args
)
46 unsigned long long num
;
51 int flags
; /* flags to number() */
53 int field_width
; /* width of output field */
54 int precision
; /* min. # of digits for integers; max
55 number of chars for from string */
56 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
57 /* 'z' support added 23/7/1999 S.H. */
58 /* 'z' changed to 'Z' --davidm 1/25/99 */
59 /* 't' added for ptrdiff_t */
61 /* Reject out-of-range values early. Large positive sizes are
62 used for unknown buffer sizes. */
63 if (unlikely((int) size
< 0))
69 /* Make sure end is always >= buf */
75 for (; *fmt
; ++fmt
) {
86 ++fmt
; /* this also skips first '%' */
88 case '-': flags
|= PRINTF_LEFT
; goto repeat
;
89 case '+': flags
|= PRINTF_PLUS
; goto repeat
;
90 case ' ': flags
|= PRINTF_SPACE
; goto repeat
;
91 case '#': flags
|= PRINTF_SPECIAL
; goto repeat
;
92 case '0': flags
|= PRINTF_ZEROPAD
; goto repeat
;
98 field_width
= skip_atoi(&fmt
);
99 else if (*fmt
== '*') {
101 /* it's the next argument */
102 field_width
= va_arg(args
, int);
103 if (field_width
< 0) {
104 field_width
= -field_width
;
105 flags
|= PRINTF_LEFT
;
109 /* get the precision */
114 precision
= skip_atoi(&fmt
);
115 else if (*fmt
== '*') {
117 /* it's the next argument */
118 precision
= va_arg(args
, int);
124 /* get the conversion qualifier */
126 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' ||
127 *fmt
=='Z' || *fmt
== 'z' || *fmt
== 't') {
130 if (qualifier
== 'l' && *fmt
== 'l') {
141 if (!(flags
& PRINTF_LEFT
)) {
142 while (--field_width
> 0) {
148 c
= (unsigned char) va_arg(args
, int);
152 while (--field_width
> 0) {
160 s
= va_arg(args
, char *);
164 len
= strnlen(s
, precision
);
166 if (!(flags
& PRINTF_LEFT
)) {
167 while (len
< field_width
--) {
173 for (i
= 0; i
< len
; ++i
) {
178 while (len
< field_width
--) {
186 if (field_width
== -1) {
187 field_width
= 2*sizeof(void *);
188 flags
|= PRINTF_ZEROPAD
;
190 str
= number(str
, end
,
191 (unsigned long) va_arg(args
, void *),
192 16, field_width
, precision
, flags
);
202 f
= va_arg(args
, double);
212 while(integer
> (m
*10)) m
*= 10;
213 while((m
>= 1) && (str
< end
)) {
219 integer
= integer
- m
*n
;
222 } else if(str
< end
) {
238 if(str
>= end
) break;
249 * What does C99 say about the overflow case here? */
250 if (qualifier
== 'l') {
251 long * ip
= va_arg(args
, long *);
253 } else if (qualifier
== 'Z' || qualifier
== 'z') {
254 size_t * ip
= va_arg(args
, size_t *);
257 int * ip
= va_arg(args
, int *);
268 /* integer number formats - set up the flags and "break" */
274 flags
|= PRINTF_LARGE
;
281 flags
|= PRINTF_SIGN
;
298 if (qualifier
== 'L')
299 num
= va_arg(args
, long long);
300 else if (qualifier
== 'l') {
301 num
= va_arg(args
, unsigned long);
302 if (flags
& PRINTF_SIGN
)
303 num
= (signed long) num
;
304 } else if (qualifier
== 'Z' || qualifier
== 'z') {
305 num
= va_arg(args
, size_t);
306 } else if (qualifier
== 't') {
307 num
= va_arg(args
, ptrdiff_t);
308 } else if (qualifier
== 'h') {
309 num
= (unsigned short) va_arg(args
, int);
310 if (flags
& PRINTF_SIGN
)
311 num
= (signed short) num
;
313 num
= va_arg(args
, unsigned int);
314 if (flags
& PRINTF_SIGN
)
315 num
= (signed int) num
;
317 str
= number(str
, end
, num
, base
,
318 field_width
, precision
, flags
);
326 /* the trailing null byte doesn't count towards the total */