Blame view

lib/vsprintf.c 47 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /*
   *  linux/lib/vsprintf.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
  
  /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
  /*
   * Wirzenius wrote this portably, Torvalds fucked it up :-)
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
11
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
18
19
20
21
22
23
   * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
   * - changed to provide snprintf and vsnprintf functions
   * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
   * - scnprintf and vscnprintf
   */
  
  #include <stdarg.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/ctype.h>
  #include <linux/kernel.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
24
25
  #include <linux/kallsyms.h>
  #include <linux/uaccess.h>
332d2e783   Linus Torvalds   Implement %pR to ...
26
  #include <linux/ioport.h>
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
27
  #include <net/addrconf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

4e57b6817   Tim Schmielau   [PATCH] fix missi...
29
  #include <asm/page.h>		/* for PAGE_SIZE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include <asm/div64.h>
deac93df2   James Bottomley   lib: Correct prin...
31
  #include <asm/sections.h>	/* for dereference_function_descriptor() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

aa46a63ef   Harvey Harrison   lib: pull base-gu...
33
34
35
  static unsigned int simple_guess_base(const char *cp)
  {
  	if (cp[0] == '0') {
75fb8f269   Andy Shevchenko   lib: make _tolowe...
36
  		if (_tolower(cp[1]) == 'x' && isxdigit(cp[2]))
aa46a63ef   Harvey Harrison   lib: pull base-gu...
37
38
39
40
41
42
43
  			return 16;
  		else
  			return 8;
  	} else {
  		return 10;
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
45
   * simple_strtoull - convert a string to an unsigned long long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
50
  unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
52
  	unsigned long long result = 0;
aa46a63ef   Harvey Harrison   lib: pull base-gu...
53
54
55
  
  	if (!base)
  		base = simple_guess_base(cp);
75fb8f269   Andy Shevchenko   lib: make _tolowe...
56
  	if (base == 16 && cp[0] == '0' && _tolower(cp[1]) == 'x')
aa46a63ef   Harvey Harrison   lib: pull base-gu...
57
58
59
60
  		cp += 2;
  
  	while (isxdigit(*cp)) {
  		unsigned int value;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
61
  		value = isdigit(*cp) ? *cp - '0' : _tolower(*cp) - 'a' + 10;
aa46a63ef   Harvey Harrison   lib: pull base-gu...
62
63
64
  		if (value >= base)
  			break;
  		result = result * base + value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
  		cp++;
  	}
  	if (endp)
  		*endp = (char *)cp;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
69

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  	return result;
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
72
  EXPORT_SYMBOL(simple_strtoull);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
75
   * simple_strtoul - convert a string to an unsigned long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
80
  unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
82
  	return simple_strtoull(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
84
  EXPORT_SYMBOL(simple_strtoul);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
87
   * simple_strtol - convert a string to a signed long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
92
  long simple_strtol(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
94
95
  	if (*cp == '-')
  		return -simple_strtoul(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
96

922ac25c9   André Goddard Rosa   vsprintf: reuse a...
97
  	return simple_strtoul(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
99
  EXPORT_SYMBOL(simple_strtol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
  
  /**
   * simple_strtoll - convert a string to a signed long long
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
22d27051b   Harvey Harrison   lib: trivial whit...
107
  long long simple_strtoll(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
109
  	if (*cp == '-')
22d27051b   Harvey Harrison   lib: trivial whit...
110
  		return -simple_strtoull(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
111

22d27051b   Harvey Harrison   lib: trivial whit...
112
  	return simple_strtoull(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  }
98d5ce0d0   Hans Verkuil   lib/vsprintf.c: a...
114
  EXPORT_SYMBOL(simple_strtoll);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115

cf3b429b0   Joe Perches   vsprintf.c: use n...
116
117
  static noinline_for_stack
  int skip_atoi(const char **s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
119
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
  
  	while (isdigit(**s))
  		i = i*10 + *((*s)++) - '0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
123

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
  	return i;
  }
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
126
127
128
129
130
131
132
133
134
135
  /* Decimal conversion is by far the most typical, and is used
   * for /proc and /sys data. This directly impacts e.g. top performance
   * with many processes running. We optimize it for speed
   * using code from
   * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
   * (with permission from the author, Douglas W. Jones). */
  
  /* Formats correctly any integer in [0,99999].
   * Outputs from one to five digits depending on input.
   * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
cf3b429b0   Joe Perches   vsprintf.c: use n...
136
137
  static noinline_for_stack
  char *put_dec_trunc(char *buf, unsigned q)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  {
  	unsigned d3, d2, d1, d0;
  	d1 = (q>>4) & 0xf;
  	d2 = (q>>8) & 0xf;
  	d3 = (q>>12);
  
  	d0 = 6*(d3 + d2 + d1) + (q & 0xf);
  	q = (d0 * 0xcd) >> 11;
  	d0 = d0 - 10*q;
  	*buf++ = d0 + '0'; /* least significant digit */
  	d1 = q + 9*d3 + 5*d2 + d1;
  	if (d1 != 0) {
  		q = (d1 * 0xcd) >> 11;
  		d1 = d1 - 10*q;
  		*buf++ = d1 + '0'; /* next digit */
  
  		d2 = q + 2*d2;
  		if ((d2 != 0) || (d3 != 0)) {
  			q = (d2 * 0xd) >> 7;
  			d2 = d2 - 10*q;
  			*buf++ = d2 + '0'; /* next digit */
  
  			d3 = q + 4*d3;
  			if (d3 != 0) {
  				q = (d3 * 0xcd) >> 11;
  				d3 = d3 - 10*q;
  				*buf++ = d3 + '0';  /* next digit */
  				if (q != 0)
7b9186f5e   André Goddard Rosa   vsprintf: give it...
166
  					*buf++ = q + '0'; /* most sign. digit */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
167
168
169
  			}
  		}
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
170

4277eedd7   Denis Vlasenko   vsprintf.c: optim...
171
172
173
  	return buf;
  }
  /* Same with if's removed. Always emits five digits */
cf3b429b0   Joe Perches   vsprintf.c: use n...
174
175
  static noinline_for_stack
  char *put_dec_full(char *buf, unsigned q)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
176
177
178
179
180
181
182
  {
  	/* BTW, if q is in [0,9999], 8-bit ints will be enough, */
  	/* but anyway, gcc produces better code with full-sized ints */
  	unsigned d3, d2, d1, d0;
  	d1 = (q>>4) & 0xf;
  	d2 = (q>>8) & 0xf;
  	d3 = (q>>12);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
183
184
185
186
187
188
189
190
191
  	/*
  	 * Possible ways to approx. divide by 10
  	 * gcc -O2 replaces multiply with shifts and adds
  	 * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
  	 * (x * 0x67) >> 10:  1100111
  	 * (x * 0x34) >> 9:    110100 - same
  	 * (x * 0x1a) >> 8:     11010 - same
  	 * (x * 0x0d) >> 7:      1101 - same, shortest code (on i386)
  	 */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  	d0 = 6*(d3 + d2 + d1) + (q & 0xf);
  	q = (d0 * 0xcd) >> 11;
  	d0 = d0 - 10*q;
  	*buf++ = d0 + '0';
  	d1 = q + 9*d3 + 5*d2 + d1;
  		q = (d1 * 0xcd) >> 11;
  		d1 = d1 - 10*q;
  		*buf++ = d1 + '0';
  
  		d2 = q + 2*d2;
  			q = (d2 * 0xd) >> 7;
  			d2 = d2 - 10*q;
  			*buf++ = d2 + '0';
  
  			d3 = q + 4*d3;
  				q = (d3 * 0xcd) >> 11; /* - shorter code */
  				/* q = (d3 * 0x67) >> 10; - would also work */
  				d3 = d3 - 10*q;
  				*buf++ = d3 + '0';
  					*buf++ = q + '0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
212

4277eedd7   Denis Vlasenko   vsprintf.c: optim...
213
214
215
  	return buf;
  }
  /* No inlining helps gcc to use registers better */
cf3b429b0   Joe Perches   vsprintf.c: use n...
216
217
  static noinline_for_stack
  char *put_dec(char *buf, unsigned long long num)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
218
219
220
221
222
223
224
225
226
  {
  	while (1) {
  		unsigned rem;
  		if (num < 100000)
  			return put_dec_trunc(buf, num);
  		rem = do_div(num, 100000);
  		buf = put_dec_full(buf, rem);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
231
  #define ZEROPAD	1		/* pad with zero */
  #define SIGN	2		/* unsigned/signed long */
  #define PLUS	4		/* show plus */
  #define SPACE	8		/* space if plus */
  #define LEFT	16		/* left justified */
b89dc5d6b   Bjorn Helgaas   vsprintf: clarify...
232
233
  #define SMALL	32		/* use lowercase in hex (must be 32 == 0x20) */
  #define SPECIAL	64		/* prefix hex with "0x", octal with "0" */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
235
236
  enum format_type {
  	FORMAT_TYPE_NONE, /* Just a string part */
ed681a91a   Vegard Nossum   vsprintf: unify t...
237
  	FORMAT_TYPE_WIDTH,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
238
239
240
241
242
243
244
245
246
  	FORMAT_TYPE_PRECISION,
  	FORMAT_TYPE_CHAR,
  	FORMAT_TYPE_STR,
  	FORMAT_TYPE_PTR,
  	FORMAT_TYPE_PERCENT_CHAR,
  	FORMAT_TYPE_INVALID,
  	FORMAT_TYPE_LONG_LONG,
  	FORMAT_TYPE_ULONG,
  	FORMAT_TYPE_LONG,
a4e94ef0d   Zhaolei   printk: add suppo...
247
248
  	FORMAT_TYPE_UBYTE,
  	FORMAT_TYPE_BYTE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
249
250
251
252
253
254
255
256
257
258
  	FORMAT_TYPE_USHORT,
  	FORMAT_TYPE_SHORT,
  	FORMAT_TYPE_UINT,
  	FORMAT_TYPE_INT,
  	FORMAT_TYPE_NRCHARS,
  	FORMAT_TYPE_SIZE_T,
  	FORMAT_TYPE_PTRDIFF
  };
  
  struct printf_spec {
4e310fda9   Joe Perches   vsprintf: Change ...
259
  	u8	type;		/* format_type enum */
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
260
  	u8	flags;		/* flags to number() */
4e310fda9   Joe Perches   vsprintf: Change ...
261
262
263
264
  	u8	base;		/* number base, 8, 10 or 16 only */
  	u8	qualifier;	/* number qualifier, one of 'hHlLtzZ' */
  	s16	field_width;	/* width of output field */
  	s16	precision;	/* # of digits/chars */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
265
  };
cf3b429b0   Joe Perches   vsprintf.c: use n...
266
267
268
  static noinline_for_stack
  char *number(char *buf, char *end, unsigned long long num,
  	     struct printf_spec spec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  {
9b706aee7   Denys Vlasenko   x86: trivial prin...
270
271
272
273
274
275
  	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
  	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
  
  	char tmp[66];
  	char sign;
  	char locase;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
276
  	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  	int i;
9b706aee7   Denys Vlasenko   x86: trivial prin...
278
279
  	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
  	 * produces same digits or (maybe lowercased) letters */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
280
281
282
  	locase = (spec.flags & SMALL);
  	if (spec.flags & LEFT)
  		spec.flags &= ~ZEROPAD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  	sign = 0;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
284
  	if (spec.flags & SIGN) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
285
  		if ((signed long long)num < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  			sign = '-';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
287
  			num = -(signed long long)num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
288
289
  			spec.field_width--;
  		} else if (spec.flags & PLUS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  			sign = '+';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
291
292
  			spec.field_width--;
  		} else if (spec.flags & SPACE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  			sign = ' ';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
294
  			spec.field_width--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
297
  	if (need_pfx) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
298
299
300
  		spec.field_width--;
  		if (spec.base == 16)
  			spec.field_width--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
302
303
  
  	/* generate full string in tmp[], in reverse order */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
  	i = 0;
  	if (num == 0)
b39a73409   Denis Vlasenko   vsprintf.c: optim...
306
  		tmp[i++] = '0';
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
307
308
  	/* Generic code, for any base:
  	else do {
9b706aee7   Denys Vlasenko   x86: trivial prin...
309
  		tmp[i++] = (digits[do_div(num,base)] | locase);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
310
311
  	} while (num != 0);
  	*/
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
312
313
  	else if (spec.base != 10) { /* 8 or 16 */
  		int mask = spec.base - 1;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
314
  		int shift = 3;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
315
316
317
  
  		if (spec.base == 16)
  			shift = 4;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
318
  		do {
9b706aee7   Denys Vlasenko   x86: trivial prin...
319
  			tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
b39a73409   Denis Vlasenko   vsprintf.c: optim...
320
321
  			num >>= shift;
  		} while (num);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
322
323
324
  	} else { /* base 10 */
  		i = put_dec(tmp, num) - tmp;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
325
326
  
  	/* printing 100 using %2d gives "100", not "00" */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
327
328
  	if (i > spec.precision)
  		spec.precision = i;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
329
  	/* leading space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
330
331
  	spec.field_width -= spec.precision;
  	if (!(spec.flags & (ZEROPAD+LEFT))) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
332
  		while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
333
  			if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
  				*buf = ' ';
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
338
  	/* sign */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  	if (sign) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
340
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
  			*buf = sign;
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
344
345
346
347
348
  	/* "0x" / "0" prefix */
  	if (need_pfx) {
  		if (buf < end)
  			*buf = '0';
  		++buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
349
  		if (spec.base == 16) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
350
  			if (buf < end)
9b706aee7   Denys Vlasenko   x86: trivial prin...
351
  				*buf = ('X' | locase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
355
  	/* zero or space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
356
357
358
  	if (!(spec.flags & LEFT)) {
  		char c = (spec.flags & ZEROPAD) ? '0' : ' ';
  		while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
359
  			if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
363
  				*buf = c;
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
364
  	/* hmm even more zero padding? */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
365
  	while (i <= --spec.precision) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
366
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
  			*buf = '0';
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
370
371
  	/* actual digits of result */
  	while (--i >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
372
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
  			*buf = tmp[i];
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
376
  	/* trailing space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
377
  	while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
378
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
  			*buf = ' ';
  		++buf;
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
382

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  	return buf;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
385
386
  static noinline_for_stack
  char *string(char *buf, char *end, const char *s, struct printf_spec spec)
0f9bfa569   Linus Torvalds   vsprintf: split o...
387
388
389
390
  {
  	int len, i;
  
  	if ((unsigned long)s < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
391
  		s = "(null)";
0f9bfa569   Linus Torvalds   vsprintf: split o...
392

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
393
  	len = strnlen(s, spec.precision);
0f9bfa569   Linus Torvalds   vsprintf: split o...
394

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
395
396
  	if (!(spec.flags & LEFT)) {
  		while (len < spec.field_width--) {
0f9bfa569   Linus Torvalds   vsprintf: split o...
397
398
399
400
401
402
403
404
405
406
  			if (buf < end)
  				*buf = ' ';
  			++buf;
  		}
  	}
  	for (i = 0; i < len; ++i) {
  		if (buf < end)
  			*buf = *s;
  		++buf; ++s;
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
407
  	while (len < spec.field_width--) {
0f9bfa569   Linus Torvalds   vsprintf: split o...
408
409
410
411
  		if (buf < end)
  			*buf = ' ';
  		++buf;
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
412

0f9bfa569   Linus Torvalds   vsprintf: split o...
413
414
  	return buf;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
415
416
417
  static noinline_for_stack
  char *symbol_string(char *buf, char *end, void *ptr,
  		    struct printf_spec spec, char ext)
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
418
419
420
421
  {
  	unsigned long value = (unsigned long) ptr;
  #ifdef CONFIG_KALLSYMS
  	char sym[KSYM_SYMBOL_LEN];
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
422
423
424
  	if (ext == 'B')
  		sprint_backtrace(sym, value);
  	else if (ext != 'f' && ext != 's')
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
425
426
427
  		sprint_symbol(sym, value);
  	else
  		kallsyms_lookup(value, NULL, NULL, NULL, sym);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
428

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
429
  	return string(buf, end, sym, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
430
  #else
7b9186f5e   André Goddard Rosa   vsprintf: give it...
431
  	spec.field_width = 2 * sizeof(void *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
432
433
  	spec.flags |= SPECIAL | SMALL | ZEROPAD;
  	spec.base = 16;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
434

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
435
  	return number(buf, end, value, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
436
437
  #endif
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
438
439
440
  static noinline_for_stack
  char *resource_string(char *buf, char *end, struct resource *res,
  		      struct printf_spec spec, const char *fmt)
332d2e783   Linus Torvalds   Implement %pR to ...
441
442
  {
  #ifndef IO_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
443
  #define IO_RSRC_PRINTK_SIZE	6
332d2e783   Linus Torvalds   Implement %pR to ...
444
445
446
  #endif
  
  #ifndef MEM_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
447
  #define MEM_RSRC_PRINTK_SIZE	10
332d2e783   Linus Torvalds   Implement %pR to ...
448
  #endif
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
449
  	static const struct printf_spec io_spec = {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
450
  		.base = 16,
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
451
  		.field_width = IO_RSRC_PRINTK_SIZE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
452
453
454
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
455
456
457
458
459
460
  	static const struct printf_spec mem_spec = {
  		.base = 16,
  		.field_width = MEM_RSRC_PRINTK_SIZE,
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
0f4050c7d   Bjorn Helgaas   resource: add bus...
461
462
463
464
465
466
  	static const struct printf_spec bus_spec = {
  		.base = 16,
  		.field_width = 2,
  		.precision = -1,
  		.flags = SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
467
  	static const struct printf_spec dec_spec = {
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
468
469
470
471
  		.base = 10,
  		.precision = -1,
  		.flags = 0,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
472
  	static const struct printf_spec str_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
473
474
475
476
  		.field_width = -1,
  		.precision = 10,
  		.flags = LEFT,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
477
  	static const struct printf_spec flag_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
478
479
480
481
  		.base = 16,
  		.precision = -1,
  		.flags = SPECIAL | SMALL,
  	};
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
482
483
484
485
486
  
  	/* 32-bit res (sizeof==4): 10 chars in dec, 10 in hex ("0x" + 8)
  	 * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */
  #define RSRC_BUF_SIZE		((2 * sizeof(resource_size_t)) + 4)
  #define FLAG_BUF_SIZE		(2 * sizeof(res->flags))
9d7cca042   Bjorn Helgaas   resource: add win...
487
  #define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref window disabled]")
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
488
489
490
  #define RAW_BUF_SIZE		sizeof("[mem - flags 0x]")
  	char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE,
  		     2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)];
332d2e783   Linus Torvalds   Implement %pR to ...
491
  	char *p = sym, *pend = sym + sizeof(sym);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
492
  	int decode = (fmt[0] == 'R') ? 1 : 0;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
493
  	const struct printf_spec *specp;
332d2e783   Linus Torvalds   Implement %pR to ...
494
495
  
  	*p++ = '[';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
496
  	if (res->flags & IORESOURCE_IO) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
497
  		p = string(p, pend, "io  ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
498
499
  		specp = &io_spec;
  	} else if (res->flags & IORESOURCE_MEM) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
500
  		p = string(p, pend, "mem ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
501
502
  		specp = &mem_spec;
  	} else if (res->flags & IORESOURCE_IRQ) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
503
  		p = string(p, pend, "irq ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
504
505
  		specp = &dec_spec;
  	} else if (res->flags & IORESOURCE_DMA) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
506
  		p = string(p, pend, "dma ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
507
  		specp = &dec_spec;
0f4050c7d   Bjorn Helgaas   resource: add bus...
508
509
510
  	} else if (res->flags & IORESOURCE_BUS) {
  		p = string(p, pend, "bus ", str_spec);
  		specp = &bus_spec;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
511
  	} else {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
512
  		p = string(p, pend, "??? ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
513
  		specp = &mem_spec;
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
514
  		decode = 0;
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
515
  	}
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
516
  	p = number(p, pend, res->start, *specp);
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
517
518
  	if (res->start != res->end) {
  		*p++ = '-';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
519
  		p = number(p, pend, res->end, *specp);
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
520
  	}
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
521
  	if (decode) {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
522
523
524
525
  		if (res->flags & IORESOURCE_MEM_64)
  			p = string(p, pend, " 64bit", str_spec);
  		if (res->flags & IORESOURCE_PREFETCH)
  			p = string(p, pend, " pref", str_spec);
9d7cca042   Bjorn Helgaas   resource: add win...
526
527
  		if (res->flags & IORESOURCE_WINDOW)
  			p = string(p, pend, " window", str_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
528
529
  		if (res->flags & IORESOURCE_DISABLED)
  			p = string(p, pend, " disabled", str_spec);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
530
531
532
  	} else {
  		p = string(p, pend, " flags ", str_spec);
  		p = number(p, pend, res->flags, flag_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
533
  	}
332d2e783   Linus Torvalds   Implement %pR to ...
534
  	*p++ = ']';
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
535
  	*p = '\0';
332d2e783   Linus Torvalds   Implement %pR to ...
536

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
537
  	return string(buf, end, sym, spec);
332d2e783   Linus Torvalds   Implement %pR to ...
538
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
539
540
541
  static noinline_for_stack
  char *mac_address_string(char *buf, char *end, u8 *addr,
  			 struct printf_spec spec, const char *fmt)
dd45c9cf6   Harvey Harrison   printk: add %pM f...
542
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
543
  	char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
dd45c9cf6   Harvey Harrison   printk: add %pM f...
544
545
  	char *p = mac_addr;
  	int i;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
546
547
548
  	char separator;
  
  	if (fmt[1] == 'F') {		/* FDDI canonical format */
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
549
550
  		separator = '-';
  	} else {
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
551
552
  		separator = ':';
  	}
dd45c9cf6   Harvey Harrison   printk: add %pM f...
553
554
  
  	for (i = 0; i < 6; i++) {
c8e000604   Joe Perches   lib: Kill bit-rev...
555
  		p = pack_hex_byte(p, addr[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
556
  		if (fmt[0] == 'M' && i != 5)
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
557
  			*p++ = separator;
dd45c9cf6   Harvey Harrison   printk: add %pM f...
558
559
  	}
  	*p = '\0';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
560
  	return string(buf, end, mac_addr, spec);
dd45c9cf6   Harvey Harrison   printk: add %pM f...
561
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
562
563
  static noinline_for_stack
  char *ip4_string(char *p, const u8 *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
564
565
  {
  	int i;
0159f24ee   Joe Perches   lib/vsprintf.c: A...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
  	bool leading_zeros = (fmt[0] == 'i');
  	int index;
  	int step;
  
  	switch (fmt[2]) {
  	case 'h':
  #ifdef __BIG_ENDIAN
  		index = 0;
  		step = 1;
  #else
  		index = 3;
  		step = -1;
  #endif
  		break;
  	case 'l':
  		index = 3;
  		step = -1;
  		break;
  	case 'n':
  	case 'b':
  	default:
  		index = 0;
  		step = 1;
  		break;
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
591
592
  	for (i = 0; i < 4; i++) {
  		char temp[3];	/* hold each IP quad in reverse order */
0159f24ee   Joe Perches   lib/vsprintf.c: A...
593
  		int digits = put_dec_trunc(temp, addr[index]) - temp;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
594
595
596
597
598
599
600
601
602
603
604
  		if (leading_zeros) {
  			if (digits < 3)
  				*p++ = '0';
  			if (digits < 2)
  				*p++ = '0';
  		}
  		/* reverse the digits in the quad */
  		while (digits--)
  			*p++ = temp[digits];
  		if (i < 3)
  			*p++ = '.';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
605
  		index += step;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
606
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
607
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
608

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
609
610
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
611
612
  static noinline_for_stack
  char *ip6_compressed_string(char *p, const char *addr)
689afa7da   Harvey Harrison   printk: add %p6 f...
613
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
614
  	int i, j, range;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
615
616
617
618
  	unsigned char zerolength[8];
  	int longest = 1;
  	int colonpos = -1;
  	u16 word;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
619
  	u8 hi, lo;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
620
  	bool needcolon = false;
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
621
622
623
624
625
626
  	bool useIPv4;
  	struct in6_addr in6;
  
  	memcpy(&in6, addr, sizeof(struct in6_addr));
  
  	useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
627
628
629
630
631
632
633
634
635
636
637
  
  	memset(zerolength, 0, sizeof(zerolength));
  
  	if (useIPv4)
  		range = 6;
  	else
  		range = 8;
  
  	/* find position of longest 0 run */
  	for (i = 0; i < range; i++) {
  		for (j = i; j < range; j++) {
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
638
  			if (in6.s6_addr16[j] != 0)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
639
640
641
642
643
644
645
646
647
648
  				break;
  			zerolength[i]++;
  		}
  	}
  	for (i = 0; i < range; i++) {
  		if (zerolength[i] > longest) {
  			longest = zerolength[i];
  			colonpos = i;
  		}
  	}
29cf519ee   Joe Perches   vsprintf: Update ...
649
650
  	if (longest == 1)		/* don't compress a single 0 */
  		colonpos = -1;
689afa7da   Harvey Harrison   printk: add %p6 f...
651

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
  	/* emit address */
  	for (i = 0; i < range; i++) {
  		if (i == colonpos) {
  			if (needcolon || i == 0)
  				*p++ = ':';
  			*p++ = ':';
  			needcolon = false;
  			i += longest - 1;
  			continue;
  		}
  		if (needcolon) {
  			*p++ = ':';
  			needcolon = false;
  		}
  		/* hex u16 without leading 0s */
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
667
  		word = ntohs(in6.s6_addr16[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
668
669
670
671
672
673
674
  		hi = word >> 8;
  		lo = word & 0xff;
  		if (hi) {
  			if (hi > 0x0f)
  				p = pack_hex_byte(p, hi);
  			else
  				*p++ = hex_asc_lo(hi);
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
675
  			p = pack_hex_byte(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
676
  		}
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
677
  		else if (lo > 0x0f)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
678
679
680
681
682
683
684
685
686
  			p = pack_hex_byte(p, lo);
  		else
  			*p++ = hex_asc_lo(lo);
  		needcolon = true;
  	}
  
  	if (useIPv4) {
  		if (needcolon)
  			*p++ = ':';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
687
  		p = ip4_string(p, &in6.s6_addr[12], "I4");
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
688
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
689
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
690

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
691
692
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
693
694
  static noinline_for_stack
  char *ip6_string(char *p, const char *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
695
696
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
697

689afa7da   Harvey Harrison   printk: add %p6 f...
698
  	for (i = 0; i < 8; i++) {
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
699
700
  		p = pack_hex_byte(p, *addr++);
  		p = pack_hex_byte(p, *addr++);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
701
  		if (fmt[0] == 'I' && i != 7)
689afa7da   Harvey Harrison   printk: add %p6 f...
702
703
704
  			*p++ = ':';
  	}
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
705

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
706
707
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
708
709
710
  static noinline_for_stack
  char *ip6_addr_string(char *buf, char *end, const u8 *addr,
  		      struct printf_spec spec, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
711
712
713
714
  {
  	char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
  
  	if (fmt[0] == 'I' && fmt[2] == 'c')
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
715
  		ip6_compressed_string(ip6_addr, addr);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
716
  	else
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
717
  		ip6_string(ip6_addr, addr, fmt);
689afa7da   Harvey Harrison   printk: add %p6 f...
718

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
719
  	return string(buf, end, ip6_addr, spec);
689afa7da   Harvey Harrison   printk: add %p6 f...
720
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
721
722
723
  static noinline_for_stack
  char *ip4_addr_string(char *buf, char *end, const u8 *addr,
  		      struct printf_spec spec, const char *fmt)
4aa996066   Harvey Harrison   printk: add %I4, ...
724
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
725
  	char ip4_addr[sizeof("255.255.255.255")];
4aa996066   Harvey Harrison   printk: add %I4, ...
726

0159f24ee   Joe Perches   lib/vsprintf.c: A...
727
  	ip4_string(ip4_addr, addr, fmt);
4aa996066   Harvey Harrison   printk: add %I4, ...
728

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
729
  	return string(buf, end, ip4_addr, spec);
4aa996066   Harvey Harrison   printk: add %I4, ...
730
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
731
732
733
  static noinline_for_stack
  char *uuid_string(char *buf, char *end, const u8 *addr,
  		  struct printf_spec spec, const char *fmt)
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
  {
  	char uuid[sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")];
  	char *p = uuid;
  	int i;
  	static const u8 be[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
  	static const u8 le[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15};
  	const u8 *index = be;
  	bool uc = false;
  
  	switch (*(++fmt)) {
  	case 'L':
  		uc = true;		/* fall-through */
  	case 'l':
  		index = le;
  		break;
  	case 'B':
  		uc = true;
  		break;
  	}
  
  	for (i = 0; i < 16; i++) {
  		p = pack_hex_byte(p, addr[index[i]]);
  		switch (i) {
  		case 3:
  		case 5:
  		case 7:
  		case 9:
  			*p++ = '-';
  			break;
  		}
  	}
  
  	*p = 0;
  
  	if (uc) {
  		p = uuid;
  		do {
  			*p = toupper(*p);
  		} while (*(++p));
  	}
  
  	return string(buf, end, uuid, spec);
  }
411f05f12   Ingo Molnar   vsprintf: Turn kp...
777
  int kptr_restrict __read_mostly;
455cd5ab3   Dan Rosenberg   kptr_restrict for...
778

4d8a743cd   Linus Torvalds   vsprintf: add inf...
779
780
781
782
783
  /*
   * Show a '%p' thing.  A kernel extension is that the '%p' is followed
   * by an extra set of alphanumeric characters that are extended format
   * specifiers.
   *
332d2e783   Linus Torvalds   Implement %pR to ...
784
785
   * Right now we handle:
   *
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
786
787
   * - 'F' For symbolic function descriptor pointers with offset
   * - 'f' For simple symbolic function names without offset
0efb4d207   Steven Rostedt   vsnprintf: remove...
788
789
   * - 'S' For symbolic direct pointers with offset
   * - 's' For symbolic direct pointers without offset
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
790
   * - 'B' For backtraced symbolic direct pointers with offset
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
791
792
   * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
   * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
dd45c9cf6   Harvey Harrison   printk: add %pM f...
793
794
   * - 'M' For a 6-byte MAC address, it prints the address in the
   *       usual colon-separated hex notation
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
795
   * - 'm' For a 6-byte MAC address, it prints the hex address without colons
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
796
   * - 'MF' For a 6-byte MAC FDDI address, it prints the address
c8e000604   Joe Perches   lib: Kill bit-rev...
797
   *       with a dash-separated hex notation
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
798
799
800
801
802
803
   * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
   *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
   *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
   * - 'i' [46] for 'raw' IPv4/IPv6 addresses
   *       IPv6 omits the colons (01020304...0f)
   *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
0159f24ee   Joe Perches   lib/vsprintf.c: A...
804
   * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
805
   * - 'I6c' for IPv6 addresses printed as specified by
29cf519ee   Joe Perches   vsprintf: Update ...
806
   *       http://tools.ietf.org/html/rfc5952
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
807
808
809
810
811
812
813
814
815
816
817
   * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
   *       "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
   *       Options for %pU are:
   *         b big endian lower case hex (default)
   *         B big endian UPPER case hex
   *         l little endian lower case hex
   *         L little endian UPPER case hex
   *           big endian output byte order is:
   *             [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15]
   *           little endian output byte order is:
   *             [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15]
7db6f5fb6   Joe Perches   vsprintf: Recursi...
818
819
820
821
822
   * - 'V' For a struct va_format which contains a format string * and va_list *,
   *       call vsnprintf(->format, *->va_list).
   *       Implements a "recursive vsnprintf".
   *       Do not use this feature without some mechanism to verify the
   *       correctness of the format string and va_list arguments.
455cd5ab3   Dan Rosenberg   kptr_restrict for...
823
   * - 'K' For a kernel pointer that should be hidden from unprivileged users
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
824
   *
332d2e783   Linus Torvalds   Implement %pR to ...
825
826
827
   * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
   * function pointers are really function descriptors, which contain a
   * pointer to the real address.
4d8a743cd   Linus Torvalds   vsprintf: add inf...
828
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
829
830
831
  static noinline_for_stack
  char *pointer(const char *fmt, char *buf, char *end, void *ptr,
  	      struct printf_spec spec)
78a8bf69b   Linus Torvalds   vsprintf: split o...
832
  {
9f36e2c44   Kees Cook   printk: use %pK f...
833
  	if (!ptr && *fmt != 'K') {
5e0579812   Joe Perches   vsprintf.c: use d...
834
835
836
837
838
839
  		/*
  		 * Print (null) with the same width as a pointer so it makes
  		 * tabular output look nice.
  		 */
  		if (spec.field_width == -1)
  			spec.field_width = 2 * sizeof(void *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
840
  		return string(buf, end, "(null)", spec);
5e0579812   Joe Perches   vsprintf.c: use d...
841
  	}
d97106ab5   Linus Torvalds   Make %p print '(n...
842

0fe1ef24f   Linus Torvalds   vsprintf: add sup...
843
844
  	switch (*fmt) {
  	case 'F':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
845
  	case 'f':
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
846
847
848
  		ptr = dereference_function_descriptor(ptr);
  		/* Fallthrough */
  	case 'S':
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
849
  	case 's':
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
850
  	case 'B':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
851
  		return symbol_string(buf, end, ptr, spec, *fmt);
332d2e783   Linus Torvalds   Implement %pR to ...
852
  	case 'R':
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
853
  	case 'r':
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
854
  		return resource_string(buf, end, ptr, spec, fmt);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
855
856
  	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
  	case 'm':			/* Contiguous: 000102030405 */
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
857
  					/* [mM]F (FDDI, bit reversed) */
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  		return mac_address_string(buf, end, ptr, spec, fmt);
  	case 'I':			/* Formatted IP supported
  					 * 4:	1.2.3.4
  					 * 6:	0001:0203:...:0708
  					 * 6c:	1::708 or 1::1.2.3.4
  					 */
  	case 'i':			/* Contiguous:
  					 * 4:	001.002.003.004
  					 * 6:   000102...0f
  					 */
  		switch (fmt[1]) {
  		case '6':
  			return ip6_addr_string(buf, end, ptr, spec, fmt);
  		case '4':
  			return ip4_addr_string(buf, end, ptr, spec, fmt);
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
874
  		break;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
875
876
  	case 'U':
  		return uuid_string(buf, end, ptr, spec, fmt);
7db6f5fb6   Joe Perches   vsprintf: Recursi...
877
  	case 'V':
d9be9b90d   Jan Beulich   lib/vsprintf.c: f...
878
  		return buf + vsnprintf(buf, end > buf ? end - buf : 0,
7db6f5fb6   Joe Perches   vsprintf: Recursi...
879
880
  				       ((struct va_format *)ptr)->fmt,
  				       *(((struct va_format *)ptr)->va));
455cd5ab3   Dan Rosenberg   kptr_restrict for...
881
882
883
884
885
886
887
888
889
  	case 'K':
  		/*
  		 * %pK cannot be used in IRQ context because its test
  		 * for CAP_SYSLOG would be meaningless.
  		 */
  		if (in_irq() || in_serving_softirq() || in_nmi()) {
  			if (spec.field_width == -1)
  				spec.field_width = 2 * sizeof(void *);
  			return string(buf, end, "pK-error", spec);
455cd5ab3   Dan Rosenberg   kptr_restrict for...
890
  		}
26297607e   Joe Perches   vsprintf: neaten ...
891
892
893
894
895
  		if (!((kptr_restrict == 0) ||
  		      (kptr_restrict == 1 &&
  		       has_capability_noaudit(current, CAP_SYSLOG))))
  			ptr = NULL;
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
896
897
898
  	}
  	spec.flags |= SMALL;
  	if (spec.field_width == -1) {
5e0579812   Joe Perches   vsprintf.c: use d...
899
  		spec.field_width = 2 * sizeof(void *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
  		spec.flags |= ZEROPAD;
  	}
  	spec.base = 16;
  
  	return number(buf, end, (unsigned long) ptr, spec);
  }
  
  /*
   * Helper function to decode printf style format.
   * Each call decode a token from the format and return the
   * number of characters read (or likely the delta where it wants
   * to go on the next call).
   * The decoded token is returned through the parameters
   *
   * 'h', 'l', or 'L' for integer fields
   * 'z' support added 23/7/1999 S.H.
   * 'z' changed to 'Z' --davidm 1/25/99
   * 't' added for ptrdiff_t
   *
   * @fmt: the format string
   * @type of the token returned
   * @flags: various flags such as +, -, # tokens..
   * @field_width: overwritten width
   * @base: base of the number (octal, hex, ...)
   * @precision: precision of a number
   * @qualifier: qualifier of a number (long, size_t, ...)
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
927
928
  static noinline_for_stack
  int format_decode(const char *fmt, struct printf_spec *spec)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
929
930
  {
  	const char *start = fmt;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
931
932
  
  	/* we finished early by reading the field width */
ed681a91a   Vegard Nossum   vsprintf: unify t...
933
  	if (spec->type == FORMAT_TYPE_WIDTH) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
  		if (spec->field_width < 0) {
  			spec->field_width = -spec->field_width;
  			spec->flags |= LEFT;
  		}
  		spec->type = FORMAT_TYPE_NONE;
  		goto precision;
  	}
  
  	/* we finished early by reading the precision */
  	if (spec->type == FORMAT_TYPE_PRECISION) {
  		if (spec->precision < 0)
  			spec->precision = 0;
  
  		spec->type = FORMAT_TYPE_NONE;
  		goto qualifier;
  	}
  
  	/* By default */
  	spec->type = FORMAT_TYPE_NONE;
  
  	for (; *fmt ; ++fmt) {
  		if (*fmt == '%')
  			break;
  	}
  
  	/* Return the current non-format string */
  	if (fmt != start || !*fmt)
  		return fmt - start;
  
  	/* Process flags */
  	spec->flags = 0;
  
  	while (1) { /* this also skips first '%' */
  		bool found = true;
  
  		++fmt;
  
  		switch (*fmt) {
  		case '-': spec->flags |= LEFT;    break;
  		case '+': spec->flags |= PLUS;    break;
  		case ' ': spec->flags |= SPACE;   break;
  		case '#': spec->flags |= SPECIAL; break;
  		case '0': spec->flags |= ZEROPAD; break;
  		default:  found = false;
  		}
  
  		if (!found)
  			break;
  	}
  
  	/* get field width */
  	spec->field_width = -1;
  
  	if (isdigit(*fmt))
  		spec->field_width = skip_atoi(&fmt);
  	else if (*fmt == '*') {
  		/* it's the next argument */
ed681a91a   Vegard Nossum   vsprintf: unify t...
991
  		spec->type = FORMAT_TYPE_WIDTH;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
  		return ++fmt - start;
  	}
  
  precision:
  	/* get the precision */
  	spec->precision = -1;
  	if (*fmt == '.') {
  		++fmt;
  		if (isdigit(*fmt)) {
  			spec->precision = skip_atoi(&fmt);
  			if (spec->precision < 0)
  				spec->precision = 0;
  		} else if (*fmt == '*') {
  			/* it's the next argument */
adf26f84a   Vegard Nossum   fix regression fr...
1006
  			spec->type = FORMAT_TYPE_PRECISION;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1007
1008
1009
1010
1011
1012
1013
  			return ++fmt - start;
  		}
  	}
  
  qualifier:
  	/* get the conversion qualifier */
  	spec->qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1014
1015
  	if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
  	    _tolower(*fmt) == 'z' || *fmt == 't') {
a4e94ef0d   Zhaolei   printk: add suppo...
1016
1017
1018
1019
1020
1021
1022
1023
1024
  		spec->qualifier = *fmt++;
  		if (unlikely(spec->qualifier == *fmt)) {
  			if (spec->qualifier == 'l') {
  				spec->qualifier = 'L';
  				++fmt;
  			} else if (spec->qualifier == 'h') {
  				spec->qualifier = 'H';
  				++fmt;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
  		}
  	}
  
  	/* default base */
  	spec->base = 10;
  	switch (*fmt) {
  	case 'c':
  		spec->type = FORMAT_TYPE_CHAR;
  		return ++fmt - start;
  
  	case 's':
  		spec->type = FORMAT_TYPE_STR;
  		return ++fmt - start;
  
  	case 'p':
  		spec->type = FORMAT_TYPE_PTR;
  		return fmt - start;
  		/* skip alnum */
  
  	case 'n':
  		spec->type = FORMAT_TYPE_NRCHARS;
  		return ++fmt - start;
  
  	case '%':
  		spec->type = FORMAT_TYPE_PERCENT_CHAR;
  		return ++fmt - start;
  
  	/* integer number formats - set up the flags and "break" */
  	case 'o':
  		spec->base = 8;
  		break;
  
  	case 'x':
  		spec->flags |= SMALL;
  
  	case 'X':
  		spec->base = 16;
  		break;
  
  	case 'd':
  	case 'i':
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1066
  		spec->flags |= SIGN;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1067
  	case 'u':
4aa996066   Harvey Harrison   printk: add %I4, ...
1068
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1069
1070
1071
1072
  
  	default:
  		spec->type = FORMAT_TYPE_INVALID;
  		return fmt - start;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1073
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1074
1075
1076
1077
  
  	if (spec->qualifier == 'L')
  		spec->type = FORMAT_TYPE_LONG_LONG;
  	else if (spec->qualifier == 'l') {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1078
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1079
1080
1081
  			spec->type = FORMAT_TYPE_LONG;
  		else
  			spec->type = FORMAT_TYPE_ULONG;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1082
  	} else if (_tolower(spec->qualifier) == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1083
1084
1085
  		spec->type = FORMAT_TYPE_SIZE_T;
  	} else if (spec->qualifier == 't') {
  		spec->type = FORMAT_TYPE_PTRDIFF;
a4e94ef0d   Zhaolei   printk: add suppo...
1086
1087
1088
1089
1090
  	} else if (spec->qualifier == 'H') {
  		if (spec->flags & SIGN)
  			spec->type = FORMAT_TYPE_BYTE;
  		else
  			spec->type = FORMAT_TYPE_UBYTE;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1091
  	} else if (spec->qualifier == 'h') {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1092
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1093
1094
1095
1096
  			spec->type = FORMAT_TYPE_SHORT;
  		else
  			spec->type = FORMAT_TYPE_USHORT;
  	} else {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1097
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1098
1099
1100
  			spec->type = FORMAT_TYPE_INT;
  		else
  			spec->type = FORMAT_TYPE_UINT;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1101
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1102
1103
  
  	return ++fmt - start;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1104
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
1108
1109
1110
1111
  /**
   * vsnprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
20036fdca   Andi Kleen   Add kerneldoc doc...
1112
   * This function follows C99 vsnprintf, but has some extensions:
91adcd2c4   Steven Rostedt   vsprintf: add %ps...
1113
1114
   * %pS output the name of a text symbol with offset
   * %ps output the name of a text symbol without offset
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1115
1116
   * %pF output the name of a function pointer with its offset
   * %pf output the name of a function pointer without its offset
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
1117
   * %pB output the name of a backtrace symbol with its offset
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1118
1119
1120
1121
1122
1123
1124
1125
   * %pR output the address range in a struct resource with decoded flags
   * %pr output the address range in a struct resource with raw flags
   * %pM output a 6-byte MAC address with colons
   * %pm output a 6-byte MAC address without colons
   * %pI4 print an IPv4 address without leading zeros
   * %pi4 print an IPv4 address with leading zeros
   * %pI6 print an IPv6 address with colons
   * %pi6 print an IPv6 address without colons
f996f2081   Jan Engelhardt   lib/vsprintf: rep...
1126
   * %pI6c print an IPv6 address as specified by RFC 5952
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1127
1128
   * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
   *   case.
0efb4d207   Steven Rostedt   vsnprintf: remove...
1129
   * %n is ignored
20036fdca   Andi Kleen   Add kerneldoc doc...
1130
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
1132
1133
1134
   * The return value is the number of characters which would
   * be generated for the given input, excluding the trailing
   * '\0', as per ISO C99. If you want to have the exact
   * number of characters written into @buf as return value
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
1135
   * (not including the trailing '\0'), use vscnprintf(). If the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
1138
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1139
   * If you're not already dealing with a va_list consider using snprintf().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
   */
  int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
  	unsigned long long num;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1144
  	char *str, *end;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1145
  	struct printf_spec spec = {0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1147
1148
  	/* Reject out-of-range values early.  Large positive sizes are
  	   used for unknown buffer sizes. */
2f30b1f9e   Marcin Slusarz   vsprintf: use WAR...
1149
  	if (WARN_ON_ONCE((int) size < 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
1152
  
  	str = buf;
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1153
  	end = buf + size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1155
1156
1157
1158
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1160
1161
  	while (*fmt) {
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1162
  		int read = format_decode(fmt, &spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1164
  		fmt += read;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1166
1167
1168
1169
1170
1171
1172
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE: {
  			int copy = read;
  			if (str < end) {
  				if (copy > end - str)
  					copy = end - str;
  				memcpy(str, old_fmt, copy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1174
1175
  			str += read;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
1177
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1178
1179
  			spec.field_width = va_arg(args, int);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1181
1182
1183
  		case FORMAT_TYPE_PRECISION:
  			spec.precision = va_arg(args, int);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184

d4be151b2   André Goddard Rosa   vsprintf: move lo...
1185
1186
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1187
1188
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1189
  					if (str < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
1191
  						*str = ' ';
  					++str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1193
1194
1195
1196
1197
1198
1199
  				}
  			}
  			c = (unsigned char) va_arg(args, int);
  			if (str < end)
  				*str = c;
  			++str;
  			while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1200
  				if (str < end)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1201
  					*str = ' ';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1202
  				++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1203
1204
  			}
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1205
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1206

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1207
1208
1209
  		case FORMAT_TYPE_STR:
  			str = string(str, end, va_arg(args, char *), spec);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1211
1212
1213
1214
1215
1216
  		case FORMAT_TYPE_PTR:
  			str = pointer(fmt+1, str, end, va_arg(args, void *),
  				      spec);
  			while (isalnum(*fmt))
  				fmt++;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1218
1219
1220
1221
1222
  		case FORMAT_TYPE_PERCENT_CHAR:
  			if (str < end)
  				*str = '%';
  			++str;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1224
1225
1226
1227
  		case FORMAT_TYPE_INVALID:
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1228
1229
1230
  			break;
  
  		case FORMAT_TYPE_NRCHARS: {
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1231
  			u8 qualifier = spec.qualifier;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1232
1233
1234
1235
  
  			if (qualifier == 'l') {
  				long *ip = va_arg(args, long *);
  				*ip = (str - buf);
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1236
  			} else if (_tolower(qualifier) == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1237
1238
1239
1240
1241
1242
1243
  				size_t *ip = va_arg(args, size_t *);
  				*ip = (str - buf);
  			} else {
  				int *ip = va_arg(args, int *);
  				*ip = (str - buf);
  			}
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
  
  		default:
  			switch (spec.type) {
  			case FORMAT_TYPE_LONG_LONG:
  				num = va_arg(args, long long);
  				break;
  			case FORMAT_TYPE_ULONG:
  				num = va_arg(args, unsigned long);
  				break;
  			case FORMAT_TYPE_LONG:
  				num = va_arg(args, long);
  				break;
  			case FORMAT_TYPE_SIZE_T:
  				num = va_arg(args, size_t);
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = va_arg(args, ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1263
1264
1265
1266
1267
1268
  			case FORMAT_TYPE_UBYTE:
  				num = (unsigned char) va_arg(args, int);
  				break;
  			case FORMAT_TYPE_BYTE:
  				num = (signed char) va_arg(args, int);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1269
1270
1271
1272
1273
1274
  			case FORMAT_TYPE_USHORT:
  				num = (unsigned short) va_arg(args, int);
  				break;
  			case FORMAT_TYPE_SHORT:
  				num = (short) va_arg(args, int);
  				break;
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1275
1276
  			case FORMAT_TYPE_INT:
  				num = (int) va_arg(args, int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1277
1278
1279
1280
1281
1282
  				break;
  			default:
  				num = va_arg(args, unsigned int);
  			}
  
  			str = number(str, end, num, spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1285

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1286
1287
1288
1289
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
0a6047eef   Linus Torvalds   Fix vsnprintf off...
1290
  			end[-1] = '\0';
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1291
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1292

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1293
  	/* the trailing null byte doesn't count towards the total */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  	return str-buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1295

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
  EXPORT_SYMBOL(vsnprintf);
  
  /**
   * vscnprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
   * The return value is the number of characters which have been written into
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1307
   * the @buf not including the trailing '\0'. If @size is == 0 the function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
   * returns 0.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1310
   * If you're not already dealing with a va_list consider using scnprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
1311
1312
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
1314
1315
1316
   */
  int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1317
  	i = vsnprintf(buf, size, fmt, args);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1318
1319
1320
1321
1322
  	if (likely(i < size))
  		return i;
  	if (size != 0)
  		return size - 1;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
  EXPORT_SYMBOL(vscnprintf);
  
  /**
   * snprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @...: Arguments for the format string
   *
   * The return value is the number of characters which would be
   * generated for the given input, excluding the trailing null,
   * as per ISO C99.  If the return is greater than or equal to
   * @size, the resulting string is truncated.
20036fdca   Andi Kleen   Add kerneldoc doc...
1337
1338
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1340
  int snprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
1342
1343
1344
1345
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1346
  	i = vsnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1348

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
1350
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
  EXPORT_SYMBOL(snprintf);
  
  /**
   * scnprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @...: Arguments for the format string
   *
   * The return value is the number of characters written into @buf not including
b903c0b88   Changli Gao   lib: fix scnprint...
1361
   * the trailing '\0'. If @size is == 0 the function returns 0.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1363
  int scnprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
1365
1366
1367
1368
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1369
  	i = vscnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1371

b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1372
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
  }
  EXPORT_SYMBOL(scnprintf);
  
  /**
   * vsprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
   * The function returns the number of characters written
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
1383
   * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
1385
   * buffer overflows.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1386
   * If you're not already dealing with a va_list consider using sprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
1387
1388
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1389
1390
1391
1392
1393
   */
  int vsprintf(char *buf, const char *fmt, va_list args)
  {
  	return vsnprintf(buf, INT_MAX, fmt, args);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
1395
1396
1397
1398
1399
1400
1401
1402
  EXPORT_SYMBOL(vsprintf);
  
  /**
   * sprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @fmt: The format string to use
   * @...: Arguments for the format string
   *
   * The function returns the number of characters written
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
1403
   * into @buf. Use snprintf() or scnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
   * buffer overflows.
20036fdca   Andi Kleen   Add kerneldoc doc...
1405
1406
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1408
  int sprintf(char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
1411
1412
1413
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1414
  	i = vsnprintf(buf, INT_MAX, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1416

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1417
1418
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
  EXPORT_SYMBOL(sprintf);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
  #ifdef CONFIG_BINARY_PRINTF
  /*
   * bprintf service:
   * vbin_printf() - VA arguments to binary data
   * bstr_printf() - Binary data to text string
   */
  
  /**
   * vbin_printf - Parse a format string and place args' binary value in a buffer
   * @bin_buf: The buffer to place args' binary value
   * @size: The size of the buffer(by words(32bits), not characters)
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
   * The format follows C99 vsnprintf, except %n is ignored, and its argument
   * is skiped.
   *
   * The return value is the number of words(32bits) which would be generated for
   * the given input.
   *
   * NOTE:
   * If the return value is greater than @size, the resulting bin_buf is NOT
   * valid for bstr_printf().
   */
  int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
  {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1446
  	struct printf_spec spec = {0};
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1447
  	char *str, *end;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
  
  	str = (char *)bin_buf;
  	end = (char *)(bin_buf + size);
  
  #define save_arg(type)							\
  do {									\
  	if (sizeof(type) == 8) {					\
  		unsigned long long value;				\
  		str = PTR_ALIGN(str, sizeof(u32));			\
  		value = va_arg(args, unsigned long long);		\
  		if (str + sizeof(type) <= end) {			\
  			*(u32 *)str = *(u32 *)&value;			\
  			*(u32 *)(str + 4) = *((u32 *)&value + 1);	\
  		}							\
  	} else {							\
  		unsigned long value;					\
  		str = PTR_ALIGN(str, sizeof(type));			\
  		value = va_arg(args, int);				\
  		if (str + sizeof(type) <= end)				\
  			*(typeof(type) *)str = (type)value;		\
  	}								\
  	str += sizeof(type);						\
  } while (0)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1471
  	while (*fmt) {
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1472
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1473

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1474
  		fmt += read;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1475

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1476
1477
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE:
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1478
1479
  		case FORMAT_TYPE_INVALID:
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1480
  			break;
ed681a91a   Vegard Nossum   vsprintf: unify t...
1481
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1482
1483
1484
1485
1486
  		case FORMAT_TYPE_PRECISION:
  			save_arg(int);
  			break;
  
  		case FORMAT_TYPE_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1487
  			save_arg(char);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1488
1489
1490
  			break;
  
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1491
1492
  			const char *save_str = va_arg(args, char *);
  			size_t len;
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
1493

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1494
1495
  			if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
  					|| (unsigned long)save_str < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
1496
  				save_str = "(null)";
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
1497
1498
1499
1500
  			len = strlen(save_str) + 1;
  			if (str + len < end)
  				memcpy(str, save_str, len);
  			str += len;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1501
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1502
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1503
1504
  
  		case FORMAT_TYPE_PTR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1505
1506
  			save_arg(void *);
  			/* skip all alphanumeric pointer suffixes */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1507
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1508
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1509
  			break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1510
  		case FORMAT_TYPE_NRCHARS: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1511
  			/* skip %n 's argument */
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1512
  			u8 qualifier = spec.qualifier;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1513
1514
1515
  			void *skip_arg;
  			if (qualifier == 'l')
  				skip_arg = va_arg(args, long *);
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1516
  			else if (_tolower(qualifier) == 'z')
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1517
1518
1519
  				skip_arg = va_arg(args, size_t *);
  			else
  				skip_arg = va_arg(args, int *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1520
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1521
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1522
1523
1524
1525
1526
  
  		default:
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1527
  				save_arg(long long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1528
1529
1530
  				break;
  			case FORMAT_TYPE_ULONG:
  			case FORMAT_TYPE_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1531
  				save_arg(unsigned long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1532
1533
  				break;
  			case FORMAT_TYPE_SIZE_T:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1534
  				save_arg(size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1535
1536
  				break;
  			case FORMAT_TYPE_PTRDIFF:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1537
  				save_arg(ptrdiff_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1538
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1539
1540
1541
1542
  			case FORMAT_TYPE_UBYTE:
  			case FORMAT_TYPE_BYTE:
  				save_arg(char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1543
1544
  			case FORMAT_TYPE_USHORT:
  			case FORMAT_TYPE_SHORT:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1545
  				save_arg(short);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1546
1547
  				break;
  			default:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1548
  				save_arg(int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1549
  			}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1550
1551
  		}
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1552

7b9186f5e   André Goddard Rosa   vsprintf: give it...
1553
  	return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1554
  #undef save_arg
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
  }
  EXPORT_SYMBOL_GPL(vbin_printf);
  
  /**
   * bstr_printf - Format a string from binary arguments and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @bin_buf: Binary arguments for the format string
   *
   * This function like C99 vsnprintf, but the difference is that vsnprintf gets
   * arguments from stack, and bstr_printf gets arguments from @bin_buf which is
   * a binary buffer that generated by vbin_printf.
   *
   * The format follows C99 vsnprintf, but has some extensions:
0efb4d207   Steven Rostedt   vsnprintf: remove...
1570
   *  see vsnprintf comment for details.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
   *
   * The return value is the number of characters which would
   * be generated for the given input, excluding the trailing
   * '\0', as per ISO C99. If you want to have the exact
   * number of characters written into @buf as return value
   * (not including the trailing '\0'), use vscnprintf(). If the
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   */
  int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
  {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1582
  	struct printf_spec spec = {0};
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1583
1584
  	char *str, *end;
  	const char *args = (const char *)bin_buf;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1585

2f30b1f9e   Marcin Slusarz   vsprintf: use WAR...
1586
  	if (WARN_ON_ONCE((int) size < 0))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1587
  		return 0;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
  
  	str = buf;
  	end = buf + size;
  
  #define get_arg(type)							\
  ({									\
  	typeof(type) value;						\
  	if (sizeof(type) == 8) {					\
  		args = PTR_ALIGN(args, sizeof(u32));			\
  		*(u32 *)&value = *(u32 *)args;				\
  		*((u32 *)&value + 1) = *(u32 *)(args + 4);		\
  	} else {							\
  		args = PTR_ALIGN(args, sizeof(type));			\
  		value = *(typeof(type) *)args;				\
  	}								\
  	args += sizeof(type);						\
  	value;								\
  })
  
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1612
  	while (*fmt) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1613
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1614
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1615

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1616
  		fmt += read;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1617

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1618
1619
1620
1621
1622
1623
1624
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE: {
  			int copy = read;
  			if (str < end) {
  				if (copy > end - str)
  					copy = end - str;
  				memcpy(str, old_fmt, copy);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1625
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1626
1627
  			str += read;
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1628
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
1629
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1630
1631
  			spec.field_width = get_arg(int);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1632

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1633
1634
1635
  		case FORMAT_TYPE_PRECISION:
  			spec.precision = get_arg(int);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1636

d4be151b2   André Goddard Rosa   vsprintf: move lo...
1637
1638
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1639
1640
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1641
1642
1643
1644
1645
1646
1647
1648
1649
  					if (str < end)
  						*str = ' ';
  					++str;
  				}
  			}
  			c = (unsigned char) get_arg(char);
  			if (str < end)
  				*str = c;
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1650
  			while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1651
1652
1653
1654
  				if (str < end)
  					*str = ' ';
  				++str;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1655
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1656
  		}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1657

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1658
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1659
  			const char *str_arg = args;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1660
  			args += strlen(str_arg) + 1;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1661
1662
  			str = string(str, end, (char *)str_arg, spec);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1663
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1664
1665
1666
  		case FORMAT_TYPE_PTR:
  			str = pointer(fmt+1, str, end, get_arg(void *), spec);
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1667
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1668
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1669

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1670
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1671
  		case FORMAT_TYPE_INVALID:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1672
1673
1674
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1675
1676
1677
1678
1679
  			break;
  
  		case FORMAT_TYPE_NRCHARS:
  			/* skip */
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1680
1681
  		default: {
  			unsigned long long num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1682
1683
1684
1685
1686
1687
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
  				num = get_arg(long long);
  				break;
  			case FORMAT_TYPE_ULONG:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1688
1689
1690
1691
1692
1693
1694
1695
1696
  			case FORMAT_TYPE_LONG:
  				num = get_arg(unsigned long);
  				break;
  			case FORMAT_TYPE_SIZE_T:
  				num = get_arg(size_t);
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = get_arg(ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1697
1698
1699
1700
1701
1702
  			case FORMAT_TYPE_UBYTE:
  				num = get_arg(unsigned char);
  				break;
  			case FORMAT_TYPE_BYTE:
  				num = get_arg(signed char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
  			case FORMAT_TYPE_USHORT:
  				num = get_arg(unsigned short);
  				break;
  			case FORMAT_TYPE_SHORT:
  				num = get_arg(short);
  				break;
  			case FORMAT_TYPE_UINT:
  				num = get_arg(unsigned int);
  				break;
  			default:
  				num = get_arg(int);
  			}
  
  			str = number(str, end, num, spec);
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1717
1718
1719
  		} /* default: */
  		} /* switch(spec.type) */
  	} /* while(*fmt) */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1720

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1721
1722
1723
1724
1725
1726
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
  			end[-1] = '\0';
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1727

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
  #undef get_arg
  
  	/* the trailing null byte doesn't count towards the total */
  	return str - buf;
  }
  EXPORT_SYMBOL_GPL(bstr_printf);
  
  /**
   * bprintf - Parse a format string and place args' binary value in a buffer
   * @bin_buf: The buffer to place args' binary value
   * @size: The size of the buffer(by words(32bits), not characters)
   * @fmt: The format string to use
   * @...: Arguments for the format string
   *
   * The function returns the number of words(u32) written
   * into @bin_buf.
   */
  int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...)
  {
  	va_list args;
  	int ret;
  
  	va_start(args, fmt);
  	ret = vbin_printf(bin_buf, size, fmt, args);
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1753

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1754
1755
1756
1757
1758
  	return ret;
  }
  EXPORT_SYMBOL_GPL(bprintf);
  
  #endif /* CONFIG_BINARY_PRINTF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759
1760
1761
1762
1763
1764
  /**
   * vsscanf - Unformat a buffer into a list of arguments
   * @buf:	input buffer
   * @fmt:	format of buffer
   * @args:	arguments
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1765
  int vsscanf(const char *buf, const char *fmt, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
1767
1768
1769
1770
  {
  	const char *str = buf;
  	char *next;
  	char digit;
  	int num = 0;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1771
1772
1773
  	u8 qualifier;
  	u8 base;
  	s16 field_width;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1774
  	bool is_sign;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1775

7b9186f5e   André Goddard Rosa   vsprintf: give it...
1776
  	while (*fmt && *str) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
1778
1779
1780
1781
  		/* skip any white space in format */
  		/* white space in format matchs any amount of
  		 * white space, including none, in the input.
  		 */
  		if (isspace(*fmt)) {
e7d2860b6   André Goddard Rosa   tree-wide: conver...
1782
1783
  			fmt = skip_spaces(++fmt);
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
  		}
  
  		/* anything that is not a conversion must match exactly */
  		if (*fmt != '%' && *fmt) {
  			if (*fmt++ != *str++)
  				break;
  			continue;
  		}
  
  		if (!*fmt)
  			break;
  		++fmt;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1796

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
1798
1799
1800
  		/* skip this conversion.
  		 * advance both strings to next white space
  		 */
  		if (*fmt == '*') {
8fccae2c9   Andy Spencer   sscanf(): fix %*s%n
1801
  			while (!isspace(*fmt) && *fmt != '%' && *fmt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
  				fmt++;
  			while (!isspace(*str) && *str)
  				str++;
  			continue;
  		}
  
  		/* get field width */
  		field_width = -1;
  		if (isdigit(*fmt))
  			field_width = skip_atoi(&fmt);
  
  		/* get conversion qualifier */
  		qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1815
1816
  		if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
  		    _tolower(*fmt) == 'z') {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
  			qualifier = *fmt++;
  			if (unlikely(qualifier == *fmt)) {
  				if (qualifier == 'h') {
  					qualifier = 'H';
  					fmt++;
  				} else if (qualifier == 'l') {
  					qualifier = 'L';
  					fmt++;
  				}
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1828
1829
1830
  
  		if (!*fmt || !*str)
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1831
1832
  		base = 10;
  		is_sign = 0;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1833
  		switch (*fmt++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834
1835
  		case 'c':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1836
  			char *s = (char *)va_arg(args, char*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
  			if (field_width == -1)
  				field_width = 1;
  			do {
  				*s++ = *str++;
  			} while (--field_width > 0 && *str);
  			num++;
  		}
  		continue;
  		case 's':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1847
1848
  			char *s = (char *)va_arg(args, char *);
  			if (field_width == -1)
4be929be3   Alexey Dobriyan   kernel-wide: repl...
1849
  				field_width = SHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
  			/* first, skip leading white space in buffer */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
1851
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1852
1853
  
  			/* now copy until next white space */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1854
  			while (*str && !isspace(*str) && field_width--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1855
  				*s++ = *str++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1856
1857
1858
1859
1860
1861
1862
  			*s = '\0';
  			num++;
  		}
  		continue;
  		case 'n':
  			/* return number of characters read so far */
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1863
  			int *i = (int *)va_arg(args, int*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
  			*i = str - buf;
  		}
  		continue;
  		case 'o':
  			base = 8;
  			break;
  		case 'x':
  		case 'X':
  			base = 16;
  			break;
  		case 'i':
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1875
  			base = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1876
1877
1878
1879
1880
1881
  		case 'd':
  			is_sign = 1;
  		case 'u':
  			break;
  		case '%':
  			/* looking for '%' in str */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1882
  			if (*str++ != '%')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
  				return num;
  			continue;
  		default:
  			/* invalid format; stop here */
  			return num;
  		}
  
  		/* have some sort of integer conversion.
  		 * first, skip white space in buffer.
  		 */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
1893
  		str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1894
1895
1896
1897
1898
1899
  
  		digit = *str;
  		if (is_sign && digit == '-')
  			digit = *(str + 1);
  
  		if (!digit
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1900
1901
1902
1903
1904
  		    || (base == 16 && !isxdigit(digit))
  		    || (base == 10 && !isdigit(digit))
  		    || (base == 8 && (!isdigit(digit) || digit > '7'))
  		    || (base == 0 && !isdigit(digit)))
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1905

7b9186f5e   André Goddard Rosa   vsprintf: give it...
1906
  		switch (qualifier) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1907
1908
  		case 'H':	/* that's 'hh' in format */
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1909
1910
  				signed char *s = (signed char *)va_arg(args, signed char *);
  				*s = (signed char)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1912
1913
  				unsigned char *s = (unsigned char *)va_arg(args, unsigned char *);
  				*s = (unsigned char)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1914
1915
1916
1917
  			}
  			break;
  		case 'h':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1918
1919
  				short *s = (short *)va_arg(args, short *);
  				*s = (short)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1920
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1921
1922
  				unsigned short *s = (unsigned short *)va_arg(args, unsigned short *);
  				*s = (unsigned short)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1923
1924
1925
1926
  			}
  			break;
  		case 'l':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1927
1928
  				long *l = (long *)va_arg(args, long *);
  				*l = simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1930
1931
  				unsigned long *l = (unsigned long *)va_arg(args, unsigned long *);
  				*l = simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1932
1933
1934
1935
  			}
  			break;
  		case 'L':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1936
1937
  				long long *l = (long long *)va_arg(args, long long *);
  				*l = simple_strtoll(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1938
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1939
1940
  				unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *);
  				*l = simple_strtoull(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1941
1942
1943
1944
1945
  			}
  			break;
  		case 'Z':
  		case 'z':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1946
1947
  			size_t *s = (size_t *)va_arg(args, size_t *);
  			*s = (size_t)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1948
1949
1950
1951
  		}
  		break;
  		default:
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1952
1953
  				int *i = (int *)va_arg(args, int *);
  				*i = (int)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1954
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1955
1956
  				unsigned int *i = (unsigned int *)va_arg(args, unsigned int*);
  				*i = (unsigned int)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1957
1958
1959
1960
1961
1962
1963
1964
1965
  			}
  			break;
  		}
  		num++;
  
  		if (!next)
  			break;
  		str = next;
  	}
c6b40d16d   Johannes Berg   fix sscanf %n mat...
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
  
  	/*
  	 * Now we've come all the way through so either the input string or the
  	 * format ended. In the former case, there can be a %n at the current
  	 * position in the format that needs to be filled.
  	 */
  	if (*fmt == '%' && *(fmt + 1) == 'n') {
  		int *p = (int *)va_arg(args, int *);
  		*p = str - buf;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1976
1977
  	return num;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1978
1979
1980
1981
1982
1983
1984
1985
  EXPORT_SYMBOL(vsscanf);
  
  /**
   * sscanf - Unformat a buffer into a list of arguments
   * @buf:	input buffer
   * @fmt:	formatting of buffer
   * @...:	resulting arguments
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1986
  int sscanf(const char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1987
1988
1989
  {
  	va_list args;
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1990
1991
  	va_start(args, fmt);
  	i = vsscanf(buf, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1993

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1994
1995
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1996
  EXPORT_SYMBOL(sscanf);