summaryrefslogtreecommitdiffstats
path: root/src/kernel/vsprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/vsprintf.c')
-rw-r--r--src/kernel/vsprintf.c235
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
18static 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) ({ \
36int __res; \
37__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
38__res; })
39
40static 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
94int 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}