1 /*
2 * linux/lib/vsprintf.c
3 *
4 * Copyright (C) 1991, 1992 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 <linux/types.h>
14 #include <linux/string.h>
15 #include <linux/ctype.h>
16
17 #include <asm/div64.h>
18
19 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
20 {
21 unsigned long result = 0,value;
22
23 if (!base) {
24 base = 10;
25 if (*cp == '') {
26 base = 8;
27 cp++;
28 if ((*cp == 'x') && isxdigit(cp[1])) {
29 cp++;
30 base = 16;
31 }
32 }
33 }
34 while (isxdigit(*cp) &&
35 (value = isdigit(*cp) ? *cp-'' : toupper(*cp)-'A'+10) < base) {
36 result = result*base + value;
37 cp++;
38 }
39 if (endp)
40 *endp = (char *)cp;
41 return result;
42 }
43
44 long simple_strtol(const char *cp,char **endp,unsigned int base)
45 {
46 if(*cp=='-')
47 return -simple_strtoul(cp+1,endp,base);
48 return simple_strtoul(cp,endp,base);
49 }
50
51 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
52 {
53 unsigned long long result = 0,value;
54
55 if (!base) {
56 base = 10;
57 if (*cp == '') {
58 base = 8;
59 cp++;
60 if ((*cp == 'x') && isxdigit(cp[1])) {
61 cp++;
62 base = 16;
63 }
64 }
65 }
66 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'' : (islower(*cp)
67 ? toupper(*cp) : *cp)-'A'+10) < base) {
68 result = result*base + value;
69 cp++;
70 }
71 if (endp)
72 *endp = (char *)cp;
73 return result;
74 }
75
76 long long simple_strtoll(const char *cp,char **endp,unsigned int base)
77 {
78 if(*cp=='-')
79 return -simple_strtoull(cp+1,endp,base);
80 return simple_strtoull(cp,endp,base);
81 }
82
83 static int skip_atoi(const char **s)
84 {
85 int i=0;
86
87 while (isdigit(**s))
88 i = i*10 + *((*s)++) - '';
89 return i;
90 }
91
92 #define ZEROPAD 1 /* pad with zero */
93 #define SIGN 2 /* unsigned/signed long */
94 #define PLUS 4 /* show plus */
95 #define SPACE 8 /* space if plus */
96 #define LEFT 16 /* left justified */
97 #define SPECIAL 32 /* 0x */
98 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
99
100 static char * number(char * str, long long num, int base, int size, int precision, int type)
101 {
102 char c,sign,tmp[66];
103 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
104 int i;
105
106 if (type & LARGE)
107 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
108 if (type & LEFT)
109 type &= ~ZEROPAD;
110 if (base < 2 || base > 36)
111 return 0;
112 c = (type & ZEROPAD) ? '' : ' ';
113 sign = 0;
114 if (type & SIGN) {
115 if (num < 0) {
116 sign = '-';
117 num = -num;
118 size--;
119 } else if (type & PLUS) {
120 sign = '+';
121 size--;
122 } else if (type & SPACE) {
123 sign = ' ';
124 size--;
125 }
126 }
127 if (type & SPECIAL) {
128 if (base == 16)
129 size -= 2;
130 else if (base == 8)
131 size--;
132 }
133 i = 0;
134 if (num == 0)
135 tmp[i++]='';
136 else while (num != 0)
137 tmp[i++] = digits[do_div(num,base)];
138 if (i > precision)
139 precision = i;
140 size -= precision;
141 if (!(type&(ZEROPAD+LEFT)))
142 while(size-->0)
143 *str++ = ' ';
144 if (sign)
145 *str++ = sign;
146 if (type & SPECIAL) {
147 if (base==8)
148 *str++ = '';
149 else if (base==16) {
150 *str++ = '';
151 *str++ = digits[33];
152 }
153 }
154 if (!(type & LEFT))
155 while (size-- > 0)
156 *str++ = c;
157 while (i < precision--)
158 *str++ = '';
159 while (i-- > 0)
160 *str++ = tmp[i];
161 while (size-- > 0)
162 *str++ = ' ';
163 return str;
164 }
165
166 /* Forward decl. needed for IP address printing stuff... */
167 int sprintf(char * buf, const char *fmt, ...);
168
169 int vsprintf(char *buf, const char *fmt, va_list args)
170 {
171 int len;
172 unsigned long long num;
173 int i, base;
174 char * str;
175 const char *s;
176
177 int flags; /* flags to number() */
178
179 int field_width; /* width of output field */
180 int precision; /* min. # of digits for integers; max
181 number of chars for from string */
182 int qualifier; /* 'h', 'l', or 'L' for integer fields */
183 /* 'z' support added 23/7/1999 S.H. */
184 /* 'z' changed to 'Z' --davidm 1/25/99 */
185
186
187 for (str=buf ; *fmt ; ++fmt) {
188 if (*fmt != '%') {
189 *str++ = *fmt;
190 continue;
191 }
192
193 /* process flags */
194 flags = 0;
195 repeat:
196 ++fmt; /* this also skips first '%' */
197 switch (*fmt) {
198 case '-': flags |= LEFT; goto repeat;
199 case '+': flags |= PLUS; goto repeat;
200 case ' ': flags |= SPACE; goto repeat;
201 case '#': flags |= SPECIAL; goto repeat;
202 case '': flags |= ZEROPAD; goto repeat;
203 }
204
205 /* get field width */
206 field_width = -1;
207 if (isdigit(*fmt))
208 field_width = skip_atoi(&fmt);
209 else if (*fmt == '*') {
210 ++fmt;
211 /* it's the next argument */
212 field_width = va_arg(args, int);
213 if (field_width < 0) {
214 field_width = -field_width;
215 flags |= LEFT;
216 }
217 }
218
219 /* get the precision */
220 precision = -1;
221 if (*fmt == '.') {
222 ++fmt;
223 if (isdigit(*fmt))
224 precision = skip_atoi(&fmt);
225 else if (*fmt == '*') {
226 ++fmt;
227 /* it's the next argument */
228 precision = va_arg(args, int);
229 }
230 if (precision < 0)
231 precision = 0;
232 }
233
234 /* get the conversion qualifier */
235 qualifier = -1;
236 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
237 qualifier = *fmt;
238 ++fmt;
239 }
240
241 /* default base */
242 base = 10;
243
244 switch (*fmt) {
245 case 'c':
246 if (!(flags & LEFT))
247 while (--field_width > 0)
248 *str++ = ' ';
249 *str++ = (unsigned char) va_arg(args, int);
250 while (--field_width > 0)
251 *str++ = ' ';
252 continue;
253
254 case 's':
255 s = va_arg(args, char *);
256 if (!s)
257 s = "<NULL>";
258
259 len = strnlen(s, precision);
260
261 if (!(flags & LEFT))
262 while (len < field_width--)
263 *str++ = ' ';
264 for (i = 0; i < len; ++i)
265 *str++ = *s++;
266 while (len < field_width--)
267 *str++ = ' ';
268 continue;
269
270 case 'p':
271 if (field_width == -1) {
272 field_width = 2*sizeof(void *);
273 flags |= ZEROPAD;
274 }
275 str = number(str,
276 (unsigned long) va_arg(args, void *), 16,
277 field_width, precision, flags);
278 continue;
279
280
281 case 'n':
282 if (qualifier == 'l') {
283 long * ip = va_arg(args, long *);
284 *ip = (str - buf);
285 } else if (qualifier == 'Z') {
286 size_t * ip = va_arg(args, size_t *);
287 *ip = (str - buf);
288 } else {
289 int * ip = va_arg(args, int *);
290 *ip = (str - buf);
291 }
292 continue;
293
294 case '%':
295 *str++ = '%';
296 continue;
297
298 /* integer number formats - set up the flags and "break" */
299 case 'o':
300 base = 8;
301 break;
302
303 case 'X':
304 flags |= LARGE;
305 case 'x':
306 base = 16;
307 break;
308
309 case 'd':
310 case 'i':
311 flags |= SIGN;
312 case 'u':
313 break;
314
315 default:
316 *str++ = '%';
317 if (*fmt)
318 *str++ = *fmt;
319 else
320 --fmt;
321 continue;
322 }
323 if (qualifier == 'L')
324 num = va_arg(args, long long);
325 else if (qualifier == 'l') {
326 num = va_arg(args, unsigned long);
327 if (flags & SIGN)
328 num = (signed long) num;
329 } else if (qualifier == 'Z') {
330 num = va_arg(args, size_t);
331 } else if (qualifier == 'h') {
332 num = (unsigned short) va_arg(args, int);
333 if (flags & SIGN)
334 num = (signed short) num;
335 } else {
336 num = va_arg(args, unsigned int);
337 if (flags & SIGN)
338 num = (signed int) num;
339 }
340 str = number(str, num, base, field_width, precision, flags);
341 }
342 *str = '\0';
343 return str-buf;
344 }
345
346 int sprintf(char * buf, const char *fmt, ...)
347 {
348 va_list args;
349 int i;
350
351 va_start(args, fmt);
352 i=vsprintf(buf,fmt,args);
353 va_end(args);
354 return i;
355 }
356
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.