|
|
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)
1.1.1.2 root 134: {
135: if (base == 8)
136: {
137: *str++ = '0';
138: }
139: else if (base == 16)
140: {
141: *str++ = '0';
142: *str++ = digits[33];
143: }
144: }
1.1 root 145: if (!(type & LEFT))
146: while (size-- > 0)
147: *str++ = c;
148: while (i < precision--)
149: *str++ = '0';
150: while (i-- > 0)
151: *str++ = tmp[i];
152: while (size-- > 0)
153: *str++ = ' ';
154: return str;
155: }
156:
157: int
158: linux_vsprintf (char *buf, const char *fmt, va_list args)
159: {
160: int len;
161: unsigned long num;
162: int i, base;
163: char *str;
164: const char *s;
165:
166: int flags; /* flags to number() */
167:
168: int field_width; /* width of output field */
169: int precision; /* min. # of digits for integers; max
170: * number of chars for from string
171: */
172: int qualifier; /* 'h', 'l', or 'L' for integer fields */
173:
174: for (str = buf; *fmt; ++fmt)
175: {
176: if (*fmt != '%')
177: {
178: *str++ = *fmt;
179: continue;
180: }
181:
182: /* process flags */
183: flags = 0;
184: repeat:
185: ++fmt; /* this also skips first '%' */
186: switch (*fmt)
187: {
188: case '-':
189: flags |= LEFT;
190: goto repeat;
191: case '+':
192: flags |= PLUS;
193: goto repeat;
194: case ' ':
195: flags |= SPACE;
196: goto repeat;
197: case '#':
198: flags |= SPECIAL;
199: goto repeat;
200: case '0':
201: flags |= ZEROPAD;
202: goto repeat;
203: }
204:
205: /* get field width */
206: field_width = -1;
207: if (is_digit (*fmt))
208: field_width = skip_atoi (&fmt);
209: else if (*fmt == '*')
210: {
211: ++fmt;
212: /* it's the next argument */
213: field_width = va_arg (args, int);
214: if (field_width < 0)
215: {
216: field_width = -field_width;
217: flags |= LEFT;
218: }
219: }
220:
221: /* get the precision */
222: precision = -1;
223: if (*fmt == '.')
224: {
225: ++fmt;
226: if (is_digit (*fmt))
227: precision = skip_atoi (&fmt);
228: else if (*fmt == '*')
229: {
230: ++fmt;
231: /* it's the next argument */
232: precision = va_arg (args, int);
233: }
234: if (precision < 0)
235: precision = 0;
236: }
237:
238: /* get the conversion qualifier */
239: qualifier = -1;
240: if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
241: {
242: qualifier = *fmt;
243: ++fmt;
244: }
245:
246: /* default base */
247: base = 10;
248:
249: switch (*fmt)
250: {
251: case 'c':
252: if (!(flags & LEFT))
253: while (--field_width > 0)
254: *str++ = ' ';
255: *str++ = (unsigned char) va_arg (args, int);
256: while (--field_width > 0)
257: *str++ = ' ';
258: continue;
259:
260: case 's':
261: s = va_arg (args, char *);
262: if (!s)
263: s = "<NULL>";
264:
265: len = strnlen (s, precision);
266:
267: if (!(flags & LEFT))
268: while (len < field_width--)
269: *str++ = ' ';
270: for (i = 0; i < len; ++i)
271: *str++ = *s++;
272: while (len < field_width--)
273: *str++ = ' ';
274: continue;
275:
276: case 'p':
277: if (field_width == -1)
278: {
279: field_width = 2 * sizeof (void *);
280: flags |= ZEROPAD;
281: }
282: str = number (str,
283: (unsigned long) va_arg (args, void *), 16,
284: field_width, precision, flags);
285: continue;
286:
287:
288: case 'n':
289: if (qualifier == 'l')
290: {
291: long *ip = va_arg (args, long *);
292: *ip = (str - buf);
293: }
294: else
295: {
296: int *ip = va_arg (args, int *);
297: *ip = (str - buf);
298: }
299: continue;
300:
301: /* integer number formats - set up the flags and "break" */
302: case 'o':
303: base = 8;
304: break;
305:
306: case 'X':
307: flags |= LARGE;
308: case 'x':
309: base = 16;
310: break;
311:
312: case 'd':
313: case 'i':
314: flags |= SIGN;
315: case 'u':
316: break;
317:
318: default:
319: if (*fmt != '%')
320: *str++ = '%';
321: if (*fmt)
322: *str++ = *fmt;
323: else
324: --fmt;
325: continue;
326: }
327: if (qualifier == 'l')
328: num = va_arg (args, unsigned long);
329: else if (qualifier == 'h')
330: if (flags & SIGN)
1.1.1.3 ! root 331: num = (short) va_arg (args, int);
1.1 root 332: else
1.1.1.3 ! root 333: num = (unsigned short) va_arg (args, unsigned int);
1.1 root 334: else if (flags & SIGN)
335: num = va_arg (args, int);
336: else
337: num = va_arg (args, unsigned int);
338: str = number (str, num, base, field_width, precision, flags);
339: }
340: *str = '\0';
341: return str - buf;
342: }
343:
344: int
345: linux_sprintf (char *buf, const char *fmt,...)
346: {
347: va_list args;
348: int i;
349:
350: va_start (args, fmt);
351: i = linux_vsprintf (buf, fmt, args);
352: va_end (args);
353: return i;
354: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.