|
|
1.1 root 1: /*
2: * linux/kernel/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/kernel.h>
16:
17: static inline
18: isxdigit(c)
19: char c;
20: {
21: return ((c >= '0' && c <= '9')
22: || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
23: }
24:
25: static inline
26: islower(c)
27: char c;
28: {
29: return (c >= 'a' && c <= 'z');
30: }
31:
32: static inline
33: toupper(c)
34: char c;
35: {
36: return (islower(c) ? c - 'a' + 'A' : c);
37: }
38:
39: static inline
40: isdigit(c)
41: char c;
42: {
43: return (c >= '0' && c <= '9');
44: }
45:
46: unsigned long
47: simple_strtoul(const char *cp,char **endp,unsigned int base)
48: {
49: unsigned long result = 0,value;
50:
51: if (!base) {
52: base = 10;
53: if (*cp == '0') {
54: base = 8;
55: cp++;
56: if ((*cp == 'x') && isxdigit(cp[1])) {
57: cp++;
58: base = 16;
59: }
60: }
61: }
62: while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
63: ? toupper(*cp) : *cp)-'A'+10) < base) {
64: result = result*base + value;
65: cp++;
66: }
67: if (endp)
68: *endp = (char *)cp;
69: return result;
70: }
71:
72: /* we use this so that we can do without the ctype library */
73: #define is_digit(c) ((c) >= '0' && (c) <= '9')
74:
75: static int
76: skip_atoi(const char **s)
77: {
78: int i=0;
79:
80: while (is_digit(**s))
81: i = i*10 + *((*s)++) - '0';
82: return i;
83: }
84:
85: #define ZEROPAD 1 /* pad with zero */
86: #define SIGN 2 /* unsigned/signed long */
87: #define PLUS 4 /* show plus */
88: #define SPACE 8 /* space if plus */
89: #define LEFT 16 /* left justified */
90: #define SPECIAL 32 /* 0x */
91: #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
92:
93: #define do_div(n,base) ({ \
94: int __res; \
95: __res = ((unsigned long) n) % (unsigned) base; \
96: n = ((unsigned long) n) / (unsigned) base; \
97: __res; })
98:
99: static char *
100: number(char * str, long num, int base, int size, int precision, int type)
101: {
102: char c,sign,tmp[36];
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) ? '0' : ' ';
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++]='0';
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++ = '0';
149: else if (base==16) {
150: *str++ = '0';
151: *str++ = digits[33];
152: }
153: if (!(type & LEFT))
154: while (size-- > 0)
155: *str++ = c;
156: while (i < precision--)
157: *str++ = '0';
158: while (i-- > 0)
159: *str++ = tmp[i];
160: while (size-- > 0)
161: *str++ = ' ';
162: return str;
163: }
164:
165: int
166: linux_vsprintf(char *buf, const char *fmt, va_list args)
167: {
168: int len;
169: unsigned long num;
170: int i, base;
171: char * str;
172: char *s;
173:
174: int flags; /* flags to number() */
175:
176: int field_width; /* width of output field */
177: int precision; /* min. # of digits for integers; max
178: number of chars for from string */
179: int qualifier; /* 'h', 'l', or 'L' for integer fields */
180:
181: for (str=buf ; *fmt ; ++fmt) {
182: if (*fmt != '%') {
183: *str++ = *fmt;
184: continue;
185: }
186:
187: /* process flags */
188: flags = 0;
189: repeat:
190: ++fmt; /* this also skips first '%' */
191: switch (*fmt) {
192: case '-': flags |= LEFT; goto repeat;
193: case '+': flags |= PLUS; goto repeat;
194: case ' ': flags |= SPACE; goto repeat;
195: case '#': flags |= SPECIAL; goto repeat;
196: case '0': flags |= ZEROPAD; goto repeat;
197: }
198:
199: /* get field width */
200: field_width = -1;
201: if (is_digit(*fmt))
202: field_width = skip_atoi(&fmt);
203: else if (*fmt == '*') {
204: ++fmt;
205: /* it's the next argument */
206: field_width = va_arg(args, int);
207: if (field_width < 0) {
208: field_width = -field_width;
209: flags |= LEFT;
210: }
211: }
212:
213: /* get the precision */
214: precision = -1;
215: if (*fmt == '.') {
216: ++fmt;
217: if (is_digit(*fmt))
218: precision = skip_atoi(&fmt);
219: else if (*fmt == '*') {
220: ++fmt;
221: /* it's the next argument */
222: precision = va_arg(args, int);
223: }
224: if (precision < 0)
225: precision = 0;
226: }
227:
228: /* get the conversion qualifier */
229: qualifier = -1;
230: if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
231: qualifier = *fmt;
232: ++fmt;
233: }
234:
235: /* default base */
236: base = 10;
237:
238: switch (*fmt) {
239: case 'c':
240: if (!(flags & LEFT))
241: while (--field_width > 0)
242: *str++ = ' ';
243: *str++ = (unsigned char) va_arg(args, int);
244: while (--field_width > 0)
245: *str++ = ' ';
246: continue;
247:
248: case 's':
249: s = va_arg(args, char *);
250: if (!s)
251: s = "<NULL>";
252: len = strlen(s);
253: if (precision < 0)
254: precision = len;
255: else if (len > precision)
256: len = precision;
257:
258: if (!(flags & LEFT))
259: while (len < field_width--)
260: *str++ = ' ';
261: for (i = 0; i < len; ++i)
262: *str++ = *s++;
263: while (len < field_width--)
264: *str++ = ' ';
265: continue;
266:
267: case 'p':
268: if (field_width == -1) {
269: field_width = 2*sizeof(void *);
270: flags |= ZEROPAD;
271: }
272: str = number(str,
273: (unsigned long) va_arg(args, void *), 16,
274: field_width, precision, flags);
275: continue;
276:
277:
278: case 'n':
279: if (qualifier == 'l') {
280: long * ip = va_arg(args, long *);
281: *ip = (str - buf);
282: } else {
283: int * ip = va_arg(args, int *);
284: *ip = (str - buf);
285: }
286: continue;
287:
288: /* integer number formats - set up the flags and "break" */
289: case 'o':
290: base = 8;
291: break;
292:
293: case 'X':
294: flags |= LARGE;
295: case 'x':
296: base = 16;
297: break;
298:
299: case 'd':
300: case 'i':
301: flags |= SIGN;
302: case 'u':
303: break;
304:
305: default:
306: if (*fmt != '%')
307: *str++ = '%';
308: if (*fmt)
309: *str++ = *fmt;
310: else
311: --fmt;
312: continue;
313: }
314: if (qualifier == 'l')
315: num = va_arg(args, unsigned long);
316: else if (qualifier == 'h')
317: if (flags & SIGN)
318: num = va_arg(args, short);
319: else
320: num = va_arg(args, unsigned short);
321: else if (flags & SIGN)
322: num = va_arg(args, int);
323: else
324: num = va_arg(args, unsigned int);
325: str = number(str, num, base, field_width, precision, flags);
326: }
327: *str = '\0';
328: return str-buf;
329: }
330:
331: int
332: linux_sprintf(char * buf, const char *fmt, ...)
333: {
334: va_list args;
335: int i;
336:
337: va_start(args, fmt);
338: i = linux_vsprintf(buf, fmt, args);
339: va_end(args);
340: return i;
341: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.