diff options
Diffstat (limited to 'src/kernel/vsprintf.c')
-rw-r--r-- | src/kernel/vsprintf.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/src/kernel/vsprintf.c b/src/kernel/vsprintf.c new file mode 100644 index 0000000..ab70f23 --- /dev/null +++ b/src/kernel/vsprintf.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * linux/kernel/vsprintf.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ | ||
8 | /* | ||
9 | * Wirzenius wrote this portably, Torvalds fucked it up :-) | ||
10 | */ | ||
11 | |||
12 | #include <stdarg.h> | ||
13 | #include <string.h> | ||
14 | |||
15 | /* we use this so that we can do without the ctype library */ | ||
16 | #define is_digit(c) ((c) >= '0' && (c) <= '9') | ||
17 | |||
18 | static int skip_atoi(const char **s) | ||
19 | { | ||
20 | int i=0; | ||
21 | |||
22 | while (is_digit(**s)) | ||
23 | i = i*10 + *((*s)++) - '0'; | ||
24 | return i; | ||
25 | } | ||
26 | |||
27 | #define ZEROPAD 1 /* pad with zero */ | ||
28 | #define SIGN 2 /* unsigned/signed long */ | ||
29 | #define PLUS 4 /* show plus */ | ||
30 | #define SPACE 8 /* space if plus */ | ||
31 | #define LEFT 16 /* left justified */ | ||
32 | #define SPECIAL 32 /* 0x */ | ||
33 | #define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ | ||
34 | |||
35 | #define do_div(n,base) ({ \ | ||
36 | int __res; \ | ||
37 | __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ | ||
38 | __res; }) | ||
39 | |||
40 | static char * number(char * str, int num, int base, int size, int precision | ||
41 | ,int type) | ||
42 | { | ||
43 | char c,sign,tmp[36]; | ||
44 | const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||
45 | int i; | ||
46 | |||
47 | if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; | ||
48 | if (type&LEFT) type &= ~ZEROPAD; | ||
49 | if (base<2 || base>36) | ||
50 | return 0; | ||
51 | c = (type & ZEROPAD) ? '0' : ' ' ; | ||
52 | if (type&SIGN && num<0) { | ||
53 | sign='-'; | ||
54 | num = -num; | ||
55 | } else | ||
56 | sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); | ||
57 | if (sign) size--; | ||
58 | if (type&SPECIAL) { | ||
59 | if (base==16) size -= 2; | ||
60 | else if (base==8) size--; | ||
61 | } | ||
62 | i=0; | ||
63 | if (num==0) | ||
64 | tmp[i++]='0'; | ||
65 | else while (num!=0) | ||
66 | tmp[i++]=digits[do_div(num,base)]; | ||
67 | if (i>precision) precision=i; | ||
68 | size -= precision; | ||
69 | if (!(type&(ZEROPAD+LEFT))) | ||
70 | while(size-->0) | ||
71 | *str++ = ' '; | ||
72 | if (sign) | ||
73 | *str++ = sign; | ||
74 | if (type&SPECIAL) { | ||
75 | if (base==8) | ||
76 | *str++ = '0'; | ||
77 | else if (base==16) { | ||
78 | *str++ = '0'; | ||
79 | *str++ = digits[33]; | ||
80 | } | ||
81 | } | ||
82 | if (!(type&LEFT)) | ||
83 | while(size-->0) | ||
84 | *str++ = c; | ||
85 | while(i<precision--) | ||
86 | *str++ = '0'; | ||
87 | while(i-->0) | ||
88 | *str++ = tmp[i]; | ||
89 | while(size-->0) | ||
90 | *str++ = ' '; | ||
91 | return str; | ||
92 | } | ||
93 | |||
94 | int vsprintf(char *buf, const char *fmt, va_list args) | ||
95 | { | ||
96 | int len; | ||
97 | int i; | ||
98 | char * str; | ||
99 | char *s; | ||
100 | int *ip; | ||
101 | |||
102 | int flags; /* flags to number() */ | ||
103 | |||
104 | int field_width; /* width of output field */ | ||
105 | int precision; /* min. # of digits for integers; max | ||
106 | number of chars for from string */ | ||
107 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ | ||
108 | |||
109 | for (str=buf ; *fmt ; ++fmt) { | ||
110 | if (*fmt != '%') { | ||
111 | *str++ = *fmt; | ||
112 | continue; | ||
113 | } | ||
114 | |||
115 | /* process flags */ | ||
116 | flags = 0; | ||
117 | repeat: | ||
118 | ++fmt; /* this also skips first '%' */ | ||
119 | switch (*fmt) { | ||
120 | case '-': flags |= LEFT; goto repeat; | ||
121 | case '+': flags |= PLUS; goto repeat; | ||
122 | case ' ': flags |= SPACE; goto repeat; | ||
123 | case '#': flags |= SPECIAL; goto repeat; | ||
124 | case '0': flags |= ZEROPAD; goto repeat; | ||
125 | } | ||
126 | |||
127 | /* get field width */ | ||
128 | field_width = -1; | ||
129 | if (is_digit(*fmt)) | ||
130 | field_width = skip_atoi(&fmt); | ||
131 | else if (*fmt == '*') { | ||
132 | /* it's the next argument */ | ||
133 | field_width = va_arg(args, int); | ||
134 | if (field_width < 0) { | ||
135 | field_width = -field_width; | ||
136 | flags |= LEFT; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /* get the precision */ | ||
141 | precision = -1; | ||
142 | if (*fmt == '.') { | ||
143 | ++fmt; | ||
144 | if (is_digit(*fmt)) | ||
145 | precision = skip_atoi(&fmt); | ||
146 | else if (*fmt == '*') { | ||
147 | /* it's the next argument */ | ||
148 | precision = va_arg(args, int); | ||
149 | } | ||
150 | if (precision < 0) | ||
151 | precision = 0; | ||
152 | } | ||
153 | |||
154 | /* get the conversion qualifier */ | ||
155 | qualifier = -1; | ||
156 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { | ||
157 | qualifier = *fmt; | ||
158 | ++fmt; | ||
159 | } | ||
160 | |||
161 | switch (*fmt) { | ||
162 | case 'c': | ||
163 | if (!(flags & LEFT)) | ||
164 | while (--field_width > 0) | ||
165 | *str++ = ' '; | ||
166 | *str++ = (unsigned char) va_arg(args, int); | ||
167 | while (--field_width > 0) | ||
168 | *str++ = ' '; | ||
169 | break; | ||
170 | |||
171 | case 's': | ||
172 | s = va_arg(args, char *); | ||
173 | len = strlen(s); | ||
174 | if (precision < 0) | ||
175 | precision = len; | ||
176 | else if (len > precision) | ||
177 | len = precision; | ||
178 | |||
179 | if (!(flags & LEFT)) | ||
180 | while (len < field_width--) | ||
181 | *str++ = ' '; | ||
182 | for (i = 0; i < len; ++i) | ||
183 | *str++ = *s++; | ||
184 | while (len < field_width--) | ||
185 | *str++ = ' '; | ||
186 | break; | ||
187 | |||
188 | case 'o': | ||
189 | str = number(str, va_arg(args, unsigned long), 8, | ||
190 | field_width, precision, flags); | ||
191 | break; | ||
192 | |||
193 | case 'p': | ||
194 | if (field_width == -1) { | ||
195 | field_width = 8; | ||
196 | flags |= ZEROPAD; | ||
197 | } | ||
198 | str = number(str, | ||
199 | (unsigned long) va_arg(args, void *), 16, | ||
200 | field_width, precision, flags); | ||
201 | break; | ||
202 | |||
203 | case 'x': | ||
204 | flags |= SMALL; | ||
205 | case 'X': | ||
206 | str = number(str, va_arg(args, unsigned long), 16, | ||
207 | field_width, precision, flags); | ||
208 | break; | ||
209 | |||
210 | case 'd': | ||
211 | case 'i': | ||
212 | flags |= SIGN; | ||
213 | case 'u': | ||
214 | str = number(str, va_arg(args, unsigned long), 10, | ||
215 | field_width, precision, flags); | ||
216 | break; | ||
217 | |||
218 | case 'n': | ||
219 | ip = va_arg(args, int *); | ||
220 | *ip = (str - buf); | ||
221 | break; | ||
222 | |||
223 | default: | ||
224 | if (*fmt != '%') | ||
225 | *str++ = '%'; | ||
226 | if (*fmt) | ||
227 | *str++ = *fmt; | ||
228 | else | ||
229 | --fmt; | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | *str = '\0'; | ||
234 | return str-buf; | ||
235 | } | ||