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