2 * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
7 * A number of things found in this file were borrowed from the Linux Kernel
14 #define unlikely(x) (x)
17 * The following constants should not be available to any users outside this
18 * C file, as they are rather meaningless there.
21 /* borrowed from Linux */
22 #define ZEROPAD 1 /* pad with zero */
23 #define SIGN 2 /* unsigned/signed long */
24 #define PLUS 4 /* show plus */
25 #define SPACE 8 /* space if plus */
26 #define LEFT 16 /* left justified */
27 #define SPECIAL 32 /* 0x */
28 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
30 /* borrowed from Linux */
31 # define do_div(n,base) ({ \
32 u32 __base = (base); \
34 __rem = ((u64)(n)) % __base; \
35 (n) = ((u64)(n)) / __base; \
39 /* borrowed from Linux */
40 static int skip_atoi(const char **s
)
45 i
= i
*10 + *((*s
)++) - '0';
49 /* borrowed from Linux */
50 static char * number(char * buf
, char * end
, unsigned long long num
, int base
, int size
, int precision
, int type
)
54 static const char small_digits
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
55 static const char large_digits
[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
58 digits
= (type
& LARGE
) ? large_digits
: small_digits
;
61 if (base
< 2 || base
> 36)
63 c
= (type
& ZEROPAD
) ? '0' : ' ';
66 if ((signed long long) num
< 0) {
68 num
= - (signed long long) num
;
70 } else if (type
& PLUS
) {
73 } else if (type
& SPACE
) {
88 tmp
[i
++] = digits
[do_div(num
,base
)];
92 if (!(type
&(ZEROPAD
+LEFT
))) {
104 if (type
& SPECIAL
) {
109 } else if (base
==16) {
118 if (!(type
& LEFT
)) {
125 while (i
< precision
--) {
144 * vsnprintf - Format a string and place it in a buffer
145 * @buf: The buffer to place the result into
146 * @size: The size of the buffer, including the trailing null space
147 * @fmt: The format string to use
148 * @args: Arguments for the format string
150 * The return value is the number of characters which would
151 * be generated for the given input, excluding the trailing
152 * '\0', as per ISO C99. If you want to have the exact
153 * number of characters written into @buf as return value
154 * (not including the trailing '\0'), use vscnprintf(). If the
155 * return is greater than or equal to @size, the resulting
156 * string is truncated.
158 * Call this function if you are already dealing with a va_list.
159 * You probably want snprintf() instead.
161 * NOTE: This function was borrowed from Linux's lib/vsprintf.c
163 int vsnprintf(char *buf
, size_t size
, const char *fmt
, va_list args
)
166 unsigned long long num
;
171 int flags
; /* flags to number() */
173 int field_width
; /* width of output field */
174 int precision
; /* min. # of digits for integers; max
175 number of chars for from string */
176 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
177 /* 'z' support added 23/7/1999 S.H. */
178 /* 'z' changed to 'Z' --davidm 1/25/99 */
179 /* 't' added for ptrdiff_t */
181 /* Reject out-of-range values early. Large positive sizes are
182 used for unknown buffer sizes. */
183 if (unlikely((int) size
< 0))
189 /* Make sure end is always >= buf */
195 for (; *fmt
; ++fmt
) {
206 ++fmt
; /* this also skips first '%' */
208 case '-': flags
|= LEFT
; goto repeat
;
209 case '+': flags
|= PLUS
; goto repeat
;
210 case ' ': flags
|= SPACE
; goto repeat
;
211 case '#': flags
|= SPECIAL
; goto repeat
;
212 case '0': flags
|= ZEROPAD
; goto repeat
;
215 /* get field width */
218 field_width
= skip_atoi(&fmt
);
219 else if (*fmt
== '*') {
221 /* it's the next argument */
222 field_width
= va_arg(args
, int);
223 if (field_width
< 0) {
224 field_width
= -field_width
;
229 /* get the precision */
234 precision
= skip_atoi(&fmt
);
235 else if (*fmt
== '*') {
237 /* it's the next argument */
238 precision
= va_arg(args
, int);
244 /* get the conversion qualifier */
246 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' ||
247 *fmt
=='Z' || *fmt
== 'z' || *fmt
== 't') {
250 if (qualifier
== 'l' && *fmt
== 'l') {
261 if (!(flags
& LEFT
)) {
262 while (--field_width
> 0) {
268 c
= (unsigned char) va_arg(args
, int);
272 while (--field_width
> 0) {
280 s
= va_arg(args
, char *);
281 if ((unsigned long)s
< VSPRINTF_PAGE_SIZE
)
284 len
= strnlen(s
, precision
);
286 if (!(flags
& LEFT
)) {
287 while (len
< field_width
--) {
293 for (i
= 0; i
< len
; ++i
) {
298 while (len
< field_width
--) {
306 if (field_width
== -1) {
307 field_width
= 2*sizeof(void *);
310 str
= number(str
, end
,
311 (unsigned long) va_arg(args
, void *),
312 16, field_width
, precision
, flags
);
318 * What does C99 say about the overflow case here? */
319 if (qualifier
== 'l') {
320 long * ip
= va_arg(args
, long *);
322 } else if (qualifier
== 'Z' || qualifier
== 'z') {
323 size_t * ip
= va_arg(args
, size_t *);
326 int * ip
= va_arg(args
, int *);
337 /* integer number formats - set up the flags and "break" */
367 if (qualifier
== 'L')
368 num
= va_arg(args
, long long);
369 else if (qualifier
== 'l') {
370 num
= va_arg(args
, unsigned long);
372 num
= (signed long) num
;
373 } else if (qualifier
== 'Z' || qualifier
== 'z') {
374 num
= va_arg(args
, size_t);
375 } else if (qualifier
== 't') {
376 num
= va_arg(args
, ptrdiff_t);
377 } else if (qualifier
== 'h') {
378 num
= (unsigned short) va_arg(args
, int);
380 num
= (signed short) num
;
382 num
= va_arg(args
, unsigned int);
384 num
= (signed int) num
;
386 str
= number(str
, end
, num
, base
,
387 field_width
, precision
, flags
);
395 /* the trailing null byte doesn't count towards the total */
399 int snprintf(char *buf
, int len
, const char *fmt
, ...)
404 len
= vsnprintf(buf
, len
, fmt
, args
);