2 * linux/kernel/vsprintf.c
4 * (C) 1991 Linus Torvalds
7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
9 * Wirzenius wrote this portably, Torvalds fucked it up :-)
14 /* we use this so that we can do without the ctype library */
15 #define is_digit(c) ((c) >= '0' && (c) <= '9')
17 static int skip_atoi(const char **s
)
22 i
= i
*10 + *((*s
)++) - '0';
26 #define ZEROPAD 1 /* pad with zero */
27 #define SIGN 2 /* unsigned/signed long */
28 #define PLUS 4 /* show plus */
29 #define SPACE 8 /* space if plus */
30 #define LEFT 16 /* left justified */
31 #define SPECIAL 32 /* 0x */
32 #define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */
34 #define do_div(n,base) ({ \
36 __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
39 static int do_div (int num, int base)
47 static char * number(char * str
, int num
, int base
, int size
, int precision
51 const char *digits
="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
54 if (type
&SMALL
) digits
="0123456789abcdefghijklmnopqrstuvwxyz";
55 if (type
&LEFT
) type
&= ~ZEROPAD
;
56 if (base
<2 || base
>36)
58 c
= (type
& ZEROPAD
) ? '0' : ' ' ;
59 if (type
&SIGN
&& num
<0) {
63 sign
=(type
&PLUS
) ? '+' : ((type
&SPACE
) ? ' ' : 0);
66 if (base
==16) size
-= 2;
67 else if (base
==8) size
--;
73 tmp
[i
++]=digits
[do_div(num
,base
)];
74 if (i
>precision
) precision
=i
;
76 if (!(type
&(ZEROPAD
+LEFT
)))
101 int vsprintf(char *buf
, const char *fmt
, va_list args
)
109 int flags
; /* flags to number() */
111 int field_width
; /* width of output field */
112 int precision
; /* min. # of digits for integers; max
113 number of chars for from string */
114 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
116 for (str
=buf
; *fmt
; ++fmt
) {
125 ++fmt
; /* this also skips first '%' */
127 case '-': flags
|= LEFT
; goto repeat
;
128 case '+': flags
|= PLUS
; goto repeat
;
129 case ' ': flags
|= SPACE
; goto repeat
;
130 case '#': flags
|= SPECIAL
; goto repeat
;
131 case '0': flags
|= ZEROPAD
; goto repeat
;
134 /* get field width */
137 field_width
= skip_atoi(&fmt
);
138 else if (*fmt
== '*') {
139 /* it's the next argument */
140 field_width
= va_arg(args
,int);
141 if (field_width
< 0) {
142 field_width
= -field_width
;
147 /* get the precision */
152 precision
= skip_atoi(&fmt
);
153 else if (*fmt
== '*') {
154 /* it's the next argument */
156 precision
= va_arg(args
,int);
162 /* get the conversion qualifier */
164 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L') {
172 while (--field_width
> 0)
174 *str
++ = (unsigned char) va_arg(args
,int);
175 while (--field_width
> 0)
180 s
= va_arg(args
,char *);
184 else if (len
> precision
)
188 while (len
< field_width
--)
190 for (i
= 0; i
< len
; ++i
)
192 while (len
< field_width
--)
197 str
= number(str
, va_arg(args
,unsigned long), 8,
198 field_width
, precision
, flags
);
202 if (field_width
== -1) {
207 (unsigned long) va_arg(args
,void *), 16,
208 field_width
, precision
, flags
);
214 str
= number(str
, va_arg(args
,unsigned long), 16,
215 field_width
, precision
, flags
);
222 str
= number(str
, va_arg(args
,unsigned long), 10,
223 field_width
, precision
, flags
);
227 ip
= va_arg(args
,int *);