Blame view

lib/vsprintf.c 58.4 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
   * 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>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
19
  #include <linux/module.h>	/* for KSYM_SYMBOL_LEN */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/ctype.h>
  #include <linux/kernel.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
24
  #include <linux/kallsyms.h>
53809751a   Jan Beulich   sscanf: don't ign...
25
  #include <linux/math64.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
26
  #include <linux/uaccess.h>
332d2e783   Linus Torvalds   Implement %pR to ...
27
  #include <linux/ioport.h>
4b6ccca70   Al Viro   add formats for d...
28
  #include <linux/dcache.h>
312b4e226   Ryan Mallon   vsprintf: check r...
29
  #include <linux/cred.h>
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
30
  #include <net/addrconf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

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

1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
35
  #include "kstrtox.h"
aa46a63ef   Harvey Harrison   lib: pull base-gu...
36

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
38
   * simple_strtoull - convert a string to an unsigned long long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
   * @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
462e47110   Eldad Zack   simple_strto*: an...
42
43
   *
   * This function is obsolete. Please use kstrtoull instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
45
  unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  {
1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
47
48
  	unsigned long long result;
  	unsigned int rv;
aa46a63ef   Harvey Harrison   lib: pull base-gu...
49

1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
50
51
52
53
  	cp = _parse_integer_fixup_radix(cp, &base);
  	rv = _parse_integer(cp, base, &result);
  	/* FIXME */
  	cp += (rv & ~KSTRTOX_OVERFLOW);
aa46a63ef   Harvey Harrison   lib: pull base-gu...
54

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  	if (endp)
  		*endp = (char *)cp;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
57

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  	return result;
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
60
  EXPORT_SYMBOL(simple_strtoull);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
63
   * simple_strtoul - convert a string to an unsigned long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
   * @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
462e47110   Eldad Zack   simple_strto*: an...
67
68
   *
   * This function is obsolete. Please use kstrtoul instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
70
  unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
72
  	return simple_strtoull(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
74
  EXPORT_SYMBOL(simple_strtoul);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
77
   * simple_strtol - convert a string to a signed long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
   * @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
462e47110   Eldad Zack   simple_strto*: an...
81
82
   *
   * This function is obsolete. Please use kstrtol instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
84
  long simple_strtol(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
86
87
  	if (*cp == '-')
  		return -simple_strtoul(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
88

922ac25c9   André Goddard Rosa   vsprintf: reuse a...
89
  	return simple_strtoul(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
91
  EXPORT_SYMBOL(simple_strtol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
  
  /**
   * 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
462e47110   Eldad Zack   simple_strto*: an...
98
99
   *
   * This function is obsolete. Please use kstrtoll instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
   */
22d27051b   Harvey Harrison   lib: trivial whit...
101
  long long simple_strtoll(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
103
  	if (*cp == '-')
22d27051b   Harvey Harrison   lib: trivial whit...
104
  		return -simple_strtoull(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
105

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

cf3b429b0   Joe Perches   vsprintf.c: use n...
110
111
  static noinline_for_stack
  int skip_atoi(const char **s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
113
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
  
  	while (isdigit(**s))
  		i = i*10 + *((*s)++) - '0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
117

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
  	return i;
  }
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
120
121
122
  /* 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
133fd9f5c   Denys Vlasenko   vsprintf: further...
123
124
125
   * using ideas described at <http://www.cs.uiowa.edu/~jones/bcd/divide.html>
   * (with permission from the author, Douglas W. Jones).
   */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
126

133fd9f5c   Denys Vlasenko   vsprintf: further...
127
128
  #if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64
  /* Formats correctly any integer in [0, 999999999] */
cf3b429b0   Joe Perches   vsprintf.c: use n...
129
  static noinline_for_stack
133fd9f5c   Denys Vlasenko   vsprintf: further...
130
  char *put_dec_full9(char *buf, unsigned q)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
131
  {
133fd9f5c   Denys Vlasenko   vsprintf: further...
132
  	unsigned r;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
133

133fd9f5c   Denys Vlasenko   vsprintf: further...
134
135
136
137
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
166
167
168
169
170
  	/*
  	 * Possible ways to approx. divide by 10
  	 * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit)
  	 * (x * 0xcccd) >> 19     x <      81920 (x < 262149 when 64-bit mul)
  	 * (x * 0x6667) >> 18     x <      43699
  	 * (x * 0x3334) >> 17     x <      16389
  	 * (x * 0x199a) >> 16     x <      16389
  	 * (x * 0x0ccd) >> 15     x <      16389
  	 * (x * 0x0667) >> 14     x <       2739
  	 * (x * 0x0334) >> 13     x <       1029
  	 * (x * 0x019a) >> 12     x <       1029
  	 * (x * 0x00cd) >> 11     x <       1029 shorter code than * 0x67 (on i386)
  	 * (x * 0x0067) >> 10     x <        179
  	 * (x * 0x0034) >>  9     x <         69 same
  	 * (x * 0x001a) >>  8     x <         69 same
  	 * (x * 0x000d) >>  7     x <         69 same, shortest code (on i386)
  	 * (x * 0x0007) >>  6     x <         19
  	 * See <http://www.cs.uiowa.edu/~jones/bcd/divide.html>
  	 */
  	r      = (q * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (q - 10 * r) + '0'; /* 1 */
  	q      = (r * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (r - 10 * q) + '0'; /* 2 */
  	r      = (q * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (q - 10 * r) + '0'; /* 3 */
  	q      = (r * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (r - 10 * q) + '0'; /* 4 */
  	r      = (q * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (q - 10 * r) + '0'; /* 5 */
  	/* Now value is under 10000, can avoid 64-bit multiply */
  	q      = (r * 0x199a) >> 16;
  	*buf++ = (r - 10 * q)  + '0'; /* 6 */
  	r      = (q * 0xcd) >> 11;
  	*buf++ = (q - 10 * r)  + '0'; /* 7 */
  	q      = (r * 0xcd) >> 11;
  	*buf++ = (r - 10 * q) + '0'; /* 8 */
  	*buf++ = q + '0'; /* 9 */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
171
172
  	return buf;
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
173
174
175
176
177
178
  #endif
  
  /* Similar to above but do not pad with zeros.
   * Code can be easily arranged to print 9 digits too, but our callers
   * always call put_dec_full9() instead when the number has 9 decimal digits.
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
179
  static noinline_for_stack
133fd9f5c   Denys Vlasenko   vsprintf: further...
180
  char *put_dec_trunc8(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
181
  {
133fd9f5c   Denys Vlasenko   vsprintf: further...
182
183
184
  	unsigned q;
  
  	/* Copy of previous function's body with added early returns */
cb239d0a9   George Spelvin   lib: vsprintf: op...
185
186
187
188
189
  	while (r >= 10000) {
  		q = r + '0';
  		r  = (r * (uint64_t)0x1999999a) >> 32;
  		*buf++ = q - 10*r;
  	}
f40005165   George Spelvin   lib: vsprintf: fi...
190
191
  	q      = (r * 0x199a) >> 16;	/* r <= 9999 */
  	*buf++ = (r - 10 * q)  + '0';
133fd9f5c   Denys Vlasenko   vsprintf: further...
192
193
  	if (q == 0)
  		return buf;
f40005165   George Spelvin   lib: vsprintf: fi...
194
195
  	r      = (q * 0xcd) >> 11;	/* q <= 999 */
  	*buf++ = (q - 10 * r)  + '0';
133fd9f5c   Denys Vlasenko   vsprintf: further...
196
197
  	if (r == 0)
  		return buf;
f40005165   George Spelvin   lib: vsprintf: fi...
198
199
  	q      = (r * 0xcd) >> 11;	/* r <= 99 */
  	*buf++ = (r - 10 * q) + '0';
133fd9f5c   Denys Vlasenko   vsprintf: further...
200
201
  	if (q == 0)
  		return buf;
f40005165   George Spelvin   lib: vsprintf: fi...
202
  	*buf++ = q + '0';		 /* q <= 9 */
133fd9f5c   Denys Vlasenko   vsprintf: further...
203
204
  	return buf;
  }
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
205

133fd9f5c   Denys Vlasenko   vsprintf: further...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  /* There are two algorithms to print larger numbers.
   * One is generic: divide by 1000000000 and repeatedly print
   * groups of (up to) 9 digits. It's conceptually simple,
   * but requires a (unsigned long long) / 1000000000 division.
   *
   * Second algorithm splits 64-bit unsigned long long into 16-bit chunks,
   * manipulates them cleverly and generates groups of 4 decimal digits.
   * It so happens that it does NOT require long long division.
   *
   * If long is > 32 bits, division of 64-bit values is relatively easy,
   * and we will use the first algorithm.
   * If long long is > 64 bits (strange architecture with VERY large long long),
   * second algorithm can't be used, and we again use the first one.
   *
   * Else (if long is 32 bits and long long is 64 bits) we use second one.
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
222

133fd9f5c   Denys Vlasenko   vsprintf: further...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  #if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64
  
  /* First algorithm: generic */
  
  static
  char *put_dec(char *buf, unsigned long long n)
  {
  	if (n >= 100*1000*1000) {
  		while (n >= 1000*1000*1000)
  			buf = put_dec_full9(buf, do_div(n, 1000*1000*1000));
  		if (n >= 100*1000*1000)
  			return put_dec_full9(buf, n);
  	}
  	return put_dec_trunc8(buf, n);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
237
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
238
239
240
241
  
  #else
  
  /* Second algorithm: valid only for 64-bit long longs */
e49317d41   George Spelvin   lib: vsprintf: op...
242
  /* See comment in put_dec_full9 for choice of constants */
cf3b429b0   Joe Perches   vsprintf.c: use n...
243
  static noinline_for_stack
2359172a7   George Spelvin   lib: vsprintf: op...
244
  void put_dec_full4(char *buf, unsigned q)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
245
  {
133fd9f5c   Denys Vlasenko   vsprintf: further...
246
  	unsigned r;
e49317d41   George Spelvin   lib: vsprintf: op...
247
  	r      = (q * 0xccd) >> 15;
2359172a7   George Spelvin   lib: vsprintf: op...
248
  	buf[0] = (q - 10 * r) + '0';
e49317d41   George Spelvin   lib: vsprintf: op...
249
  	q      = (r * 0xcd) >> 11;
2359172a7   George Spelvin   lib: vsprintf: op...
250
  	buf[1] = (r - 10 * q)  + '0';
133fd9f5c   Denys Vlasenko   vsprintf: further...
251
  	r      = (q * 0xcd) >> 11;
2359172a7   George Spelvin   lib: vsprintf: op...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  	buf[2] = (q - 10 * r)  + '0';
  	buf[3] = r + '0';
  }
  
  /*
   * Call put_dec_full4 on x % 10000, return x / 10000.
   * The approximation x/10000 == (x * 0x346DC5D7) >> 43
   * holds for all x < 1,128,869,999.  The largest value this
   * helper will ever be asked to convert is 1,125,520,955.
   * (d1 in the put_dec code, assuming n is all-ones).
   */
  static
  unsigned put_dec_helper4(char *buf, unsigned x)
  {
          uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43;
  
          put_dec_full4(buf, x - q * 10000);
          return q;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
270
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  /* Based on code by Douglas W. Jones found at
   * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
   * (with permission from the author).
   * Performs no 64-bit division and hence should be fast on 32-bit machines.
   */
  static
  char *put_dec(char *buf, unsigned long long n)
  {
  	uint32_t d3, d2, d1, q, h;
  
  	if (n < 100*1000*1000)
  		return put_dec_trunc8(buf, n);
  
  	d1  = ((uint32_t)n >> 16); /* implicit "& 0xffff" */
  	h   = (n >> 32);
  	d2  = (h      ) & 0xffff;
  	d3  = (h >> 16); /* implicit "& 0xffff" */
  
  	q   = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff);
2359172a7   George Spelvin   lib: vsprintf: op...
290
291
292
293
294
295
296
  	q = put_dec_helper4(buf, q);
  
  	q += 7671 * d3 + 9496 * d2 + 6 * d1;
  	q = put_dec_helper4(buf+4, q);
  
  	q += 4749 * d3 + 42 * d2;
  	q = put_dec_helper4(buf+8, q);
133fd9f5c   Denys Vlasenko   vsprintf: further...
297

2359172a7   George Spelvin   lib: vsprintf: op...
298
299
300
301
302
  	q += 281 * d3;
  	buf += 12;
  	if (q)
  		buf = put_dec_trunc8(buf, q);
  	else while (buf[-1] == '0')
133fd9f5c   Denys Vlasenko   vsprintf: further...
303
304
305
306
307
308
  		--buf;
  
  	return buf;
  }
  
  #endif
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
309
310
311
312
313
314
315
316
  /*
   * Convert passed number to decimal string.
   * Returns the length of string.  On buffer overflow, returns 0.
   *
   * If speed is not important, use snprintf(). It's easy to read the code.
   */
  int num_to_str(char *buf, int size, unsigned long long num)
  {
133fd9f5c   Denys Vlasenko   vsprintf: further...
317
  	char tmp[sizeof(num) * 3];
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
318
  	int idx, len;
133fd9f5c   Denys Vlasenko   vsprintf: further...
319
320
321
322
323
324
325
  	/* put_dec() may work incorrectly for num = 0 (generate "", not "0") */
  	if (num <= 9) {
  		tmp[0] = '0' + num;
  		len = 1;
  	} else {
  		len = put_dec(tmp, num) - tmp;
  	}
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
326
327
328
329
330
  
  	if (len > size)
  		return 0;
  	for (idx = 0; idx < len; ++idx)
  		buf[idx] = tmp[len - idx - 1];
133fd9f5c   Denys Vlasenko   vsprintf: further...
331
  	return len;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
332
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
  #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...
338
339
  #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
340

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
341
342
  enum format_type {
  	FORMAT_TYPE_NONE, /* Just a string part */
ed681a91a   Vegard Nossum   vsprintf: unify t...
343
  	FORMAT_TYPE_WIDTH,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
344
345
346
347
348
349
350
351
352
  	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...
353
354
  	FORMAT_TYPE_UBYTE,
  	FORMAT_TYPE_BYTE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
355
356
357
358
  	FORMAT_TYPE_USHORT,
  	FORMAT_TYPE_SHORT,
  	FORMAT_TYPE_UINT,
  	FORMAT_TYPE_INT,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
359
360
361
362
363
  	FORMAT_TYPE_SIZE_T,
  	FORMAT_TYPE_PTRDIFF
  };
  
  struct printf_spec {
4e310fda9   Joe Perches   vsprintf: Change ...
364
  	u8	type;		/* format_type enum */
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
365
  	u8	flags;		/* flags to number() */
4e310fda9   Joe Perches   vsprintf: Change ...
366
367
368
369
  	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...
370
  };
cf3b429b0   Joe Perches   vsprintf.c: use n...
371
372
373
  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
374
  {
9b706aee7   Denys Vlasenko   x86: trivial prin...
375
376
377
378
379
380
  	/* 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...
381
  	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  	int i;
7c2034223   Pierre Carrier   lib/vsprintf.c: "...
383
  	bool is_zero = num == 0LL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384

9b706aee7   Denys Vlasenko   x86: trivial prin...
385
386
  	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
  	 * produces same digits or (maybe lowercased) letters */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
387
388
389
  	locase = (spec.flags & SMALL);
  	if (spec.flags & LEFT)
  		spec.flags &= ~ZEROPAD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  	sign = 0;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
391
  	if (spec.flags & SIGN) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
392
  		if ((signed long long)num < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  			sign = '-';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
394
  			num = -(signed long long)num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
395
396
  			spec.field_width--;
  		} else if (spec.flags & PLUS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  			sign = '+';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
398
399
  			spec.field_width--;
  		} else if (spec.flags & SPACE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  			sign = ' ';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
401
  			spec.field_width--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
404
  	if (need_pfx) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
405
  		if (spec.base == 16)
7c2034223   Pierre Carrier   lib/vsprintf.c: "...
406
407
  			spec.field_width -= 2;
  		else if (!is_zero)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
408
  			spec.field_width--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
410
411
  
  	/* generate full string in tmp[], in reverse order */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  	i = 0;
133fd9f5c   Denys Vlasenko   vsprintf: further...
413
414
  	if (num < spec.base)
  		tmp[i++] = digits[num] | locase;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
415
416
  	/* Generic code, for any base:
  	else do {
9b706aee7   Denys Vlasenko   x86: trivial prin...
417
  		tmp[i++] = (digits[do_div(num,base)] | locase);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
418
419
  	} while (num != 0);
  	*/
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
420
421
  	else if (spec.base != 10) { /* 8 or 16 */
  		int mask = spec.base - 1;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
422
  		int shift = 3;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
423
424
425
  
  		if (spec.base == 16)
  			shift = 4;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
426
  		do {
9b706aee7   Denys Vlasenko   x86: trivial prin...
427
  			tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
b39a73409   Denis Vlasenko   vsprintf.c: optim...
428
429
  			num >>= shift;
  		} while (num);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
430
431
432
  	} else { /* base 10 */
  		i = put_dec(tmp, num) - tmp;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
433
434
  
  	/* printing 100 using %2d gives "100", not "00" */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
435
436
  	if (i > spec.precision)
  		spec.precision = i;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
437
  	/* leading space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
438
439
  	spec.field_width -= spec.precision;
  	if (!(spec.flags & (ZEROPAD+LEFT))) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
440
  		while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
441
  			if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
  				*buf = ' ';
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
446
  	/* sign */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  	if (sign) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
448
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
  			*buf = sign;
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
452
453
  	/* "0x" / "0" prefix */
  	if (need_pfx) {
7c2034223   Pierre Carrier   lib/vsprintf.c: "...
454
455
456
457
458
  		if (spec.base == 16 || !is_zero) {
  			if (buf < end)
  				*buf = '0';
  			++buf;
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
459
  		if (spec.base == 16) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
460
  			if (buf < end)
9b706aee7   Denys Vlasenko   x86: trivial prin...
461
  				*buf = ('X' | locase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
465
  	/* zero or space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
466
467
468
  	if (!(spec.flags & LEFT)) {
  		char c = (spec.flags & ZEROPAD) ? '0' : ' ';
  		while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
469
  			if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
  				*buf = c;
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
474
  	/* hmm even more zero padding? */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
475
  	while (i <= --spec.precision) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
476
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
  			*buf = '0';
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
480
481
  	/* actual digits of result */
  	while (--i >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
482
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  			*buf = tmp[i];
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
486
  	/* trailing space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
487
  	while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
488
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
491
  			*buf = ' ';
  		++buf;
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
492

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
  	return buf;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
495
496
  static noinline_for_stack
  char *string(char *buf, char *end, const char *s, struct printf_spec spec)
0f9bfa569   Linus Torvalds   vsprintf: split o...
497
498
499
500
  {
  	int len, i;
  
  	if ((unsigned long)s < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
501
  		s = "(null)";
0f9bfa569   Linus Torvalds   vsprintf: split o...
502

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
505
506
  	if (!(spec.flags & LEFT)) {
  		while (len < spec.field_width--) {
0f9bfa569   Linus Torvalds   vsprintf: split o...
507
508
509
510
511
512
513
514
515
516
  			if (buf < end)
  				*buf = ' ';
  			++buf;
  		}
  	}
  	for (i = 0; i < len; ++i) {
  		if (buf < end)
  			*buf = *s;
  		++buf; ++s;
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
517
  	while (len < spec.field_width--) {
0f9bfa569   Linus Torvalds   vsprintf: split o...
518
519
520
521
  		if (buf < end)
  			*buf = ' ';
  		++buf;
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
522

0f9bfa569   Linus Torvalds   vsprintf: split o...
523
524
  	return buf;
  }
4b6ccca70   Al Viro   add formats for d...
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
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
591
592
593
594
595
596
597
598
  static void widen(char *buf, char *end, unsigned len, unsigned spaces)
  {
  	size_t size;
  	if (buf >= end)	/* nowhere to put anything */
  		return;
  	size = end - buf;
  	if (size <= spaces) {
  		memset(buf, ' ', size);
  		return;
  	}
  	if (len) {
  		if (len > size - spaces)
  			len = size - spaces;
  		memmove(buf + spaces, buf, len);
  	}
  	memset(buf, ' ', spaces);
  }
  
  static noinline_for_stack
  char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec,
  		  const char *fmt)
  {
  	const char *array[4], *s;
  	const struct dentry *p;
  	int depth;
  	int i, n;
  
  	switch (fmt[1]) {
  		case '2': case '3': case '4':
  			depth = fmt[1] - '0';
  			break;
  		default:
  			depth = 1;
  	}
  
  	rcu_read_lock();
  	for (i = 0; i < depth; i++, d = p) {
  		p = ACCESS_ONCE(d->d_parent);
  		array[i] = ACCESS_ONCE(d->d_name.name);
  		if (p == d) {
  			if (i)
  				array[i] = "";
  			i++;
  			break;
  		}
  	}
  	s = array[--i];
  	for (n = 0; n != spec.precision; n++, buf++) {
  		char c = *s++;
  		if (!c) {
  			if (!i)
  				break;
  			c = '/';
  			s = array[--i];
  		}
  		if (buf < end)
  			*buf = c;
  	}
  	rcu_read_unlock();
  	if (n < spec.field_width) {
  		/* we want to pad the sucker */
  		unsigned spaces = spec.field_width - n;
  		if (!(spec.flags & LEFT)) {
  			widen(buf - n, end, n, spaces);
  			return buf + spaces;
  		}
  		while (spaces--) {
  			if (buf < end)
  				*buf = ' ';
  			++buf;
  		}
  	}
  	return buf;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
599
600
  static noinline_for_stack
  char *symbol_string(char *buf, char *end, void *ptr,
b0d33c2bd   Joe Perches   vsprintf: Add ext...
601
  		    struct printf_spec spec, const char *fmt)
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
602
  {
b0d33c2bd   Joe Perches   vsprintf: Add ext...
603
  	unsigned long value;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
604
605
  #ifdef CONFIG_KALLSYMS
  	char sym[KSYM_SYMBOL_LEN];
b0d33c2bd   Joe Perches   vsprintf: Add ext...
606
607
608
609
610
611
612
613
  #endif
  
  	if (fmt[1] == 'R')
  		ptr = __builtin_extract_return_addr(ptr);
  	value = (unsigned long)ptr;
  
  #ifdef CONFIG_KALLSYMS
  	if (*fmt == 'B')
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
614
  		sprint_backtrace(sym, value);
b0d33c2bd   Joe Perches   vsprintf: Add ext...
615
  	else if (*fmt != 'f' && *fmt != 's')
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
616
617
  		sprint_symbol(sym, value);
  	else
4796dd200   Stephen Boyd   vsprintf: fix %ps...
618
  		sprint_symbol_no_offset(sym, value);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
619

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
620
  	return string(buf, end, sym, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
621
  #else
7b9186f5e   André Goddard Rosa   vsprintf: give it...
622
  	spec.field_width = 2 * sizeof(void *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
623
624
  	spec.flags |= SPECIAL | SMALL | ZEROPAD;
  	spec.base = 16;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
625

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
626
  	return number(buf, end, value, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
627
628
  #endif
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
629
630
631
  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 ...
632
633
  {
  #ifndef IO_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
634
  #define IO_RSRC_PRINTK_SIZE	6
332d2e783   Linus Torvalds   Implement %pR to ...
635
636
637
  #endif
  
  #ifndef MEM_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
638
  #define MEM_RSRC_PRINTK_SIZE	10
332d2e783   Linus Torvalds   Implement %pR to ...
639
  #endif
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
640
  	static const struct printf_spec io_spec = {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
641
  		.base = 16,
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
642
  		.field_width = IO_RSRC_PRINTK_SIZE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
643
644
645
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
646
647
648
649
650
651
  	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...
652
653
654
655
656
657
  	static const struct printf_spec bus_spec = {
  		.base = 16,
  		.field_width = 2,
  		.precision = -1,
  		.flags = SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
658
  	static const struct printf_spec dec_spec = {
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
659
660
661
662
  		.base = 10,
  		.precision = -1,
  		.flags = 0,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
663
  	static const struct printf_spec str_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
664
665
666
667
  		.field_width = -1,
  		.precision = 10,
  		.flags = LEFT,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
668
  	static const struct printf_spec flag_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
669
670
671
672
  		.base = 16,
  		.precision = -1,
  		.flags = SPECIAL | SMALL,
  	};
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
673
674
675
676
677
  
  	/* 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...
678
  #define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref window disabled]")
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
679
680
681
  #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 ...
682
  	char *p = sym, *pend = sym + sizeof(sym);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
683
  	int decode = (fmt[0] == 'R') ? 1 : 0;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
684
  	const struct printf_spec *specp;
332d2e783   Linus Torvalds   Implement %pR to ...
685
686
  
  	*p++ = '[';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
687
  	if (res->flags & IORESOURCE_IO) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
688
  		p = string(p, pend, "io  ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
689
690
  		specp = &io_spec;
  	} else if (res->flags & IORESOURCE_MEM) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
691
  		p = string(p, pend, "mem ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
692
693
  		specp = &mem_spec;
  	} else if (res->flags & IORESOURCE_IRQ) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
694
  		p = string(p, pend, "irq ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
695
696
  		specp = &dec_spec;
  	} else if (res->flags & IORESOURCE_DMA) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
697
  		p = string(p, pend, "dma ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
698
  		specp = &dec_spec;
0f4050c7d   Bjorn Helgaas   resource: add bus...
699
700
701
  	} else if (res->flags & IORESOURCE_BUS) {
  		p = string(p, pend, "bus ", str_spec);
  		specp = &bus_spec;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
702
  	} else {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
703
  		p = string(p, pend, "??? ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
704
  		specp = &mem_spec;
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
705
  		decode = 0;
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
706
  	}
d19cb803a   Bjorn Helgaas   vsprintf: Add sup...
707
708
709
710
711
712
713
714
715
  	if (decode && res->flags & IORESOURCE_UNSET) {
  		p = string(p, pend, "size ", str_spec);
  		p = number(p, pend, resource_size(res), *specp);
  	} else {
  		p = number(p, pend, res->start, *specp);
  		if (res->start != res->end) {
  			*p++ = '-';
  			p = number(p, pend, res->end, *specp);
  		}
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
716
  	}
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
717
  	if (decode) {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
718
719
720
721
  		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...
722
723
  		if (res->flags & IORESOURCE_WINDOW)
  			p = string(p, pend, " window", str_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
724
725
  		if (res->flags & IORESOURCE_DISABLED)
  			p = string(p, pend, " disabled", str_spec);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
726
727
728
  	} else {
  		p = string(p, pend, " flags ", str_spec);
  		p = number(p, pend, res->flags, flag_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
729
  	}
332d2e783   Linus Torvalds   Implement %pR to ...
730
  	*p++ = ']';
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
731
  	*p = '\0';
332d2e783   Linus Torvalds   Implement %pR to ...
732

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
733
  	return string(buf, end, sym, spec);
332d2e783   Linus Torvalds   Implement %pR to ...
734
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
735
  static noinline_for_stack
31550a16a   Andy Shevchenko   vsprintf: add sup...
736
737
738
  char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
  		 const char *fmt)
  {
360603a1b   Steven Rostedt   sprintf: hex_stri...
739
  	int i, len = 1;		/* if we pass '%ph[CDN]', field width remains
31550a16a   Andy Shevchenko   vsprintf: add sup...
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
777
778
779
  				   negative value, fallback to the default */
  	char separator;
  
  	if (spec.field_width == 0)
  		/* nothing to print */
  		return buf;
  
  	if (ZERO_OR_NULL_PTR(addr))
  		/* NULL pointer */
  		return string(buf, end, NULL, spec);
  
  	switch (fmt[1]) {
  	case 'C':
  		separator = ':';
  		break;
  	case 'D':
  		separator = '-';
  		break;
  	case 'N':
  		separator = 0;
  		break;
  	default:
  		separator = ' ';
  		break;
  	}
  
  	if (spec.field_width > 0)
  		len = min_t(int, spec.field_width, 64);
  
  	for (i = 0; i < len && buf < end - 1; i++) {
  		buf = hex_byte_pack(buf, addr[i]);
  
  		if (buf < end && separator && i != len - 1)
  			*buf++ = separator;
  	}
  
  	return buf;
  }
  
  static noinline_for_stack
cf3b429b0   Joe Perches   vsprintf.c: use n...
780
781
  char *mac_address_string(char *buf, char *end, u8 *addr,
  			 struct printf_spec spec, const char *fmt)
dd45c9cf6   Harvey Harrison   printk: add %pM f...
782
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
783
  	char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
dd45c9cf6   Harvey Harrison   printk: add %pM f...
784
785
  	char *p = mac_addr;
  	int i;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
786
  	char separator;
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
787
  	bool reversed = false;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
788

76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
789
790
  	switch (fmt[1]) {
  	case 'F':
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
791
  		separator = '-';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
792
793
794
795
796
797
798
  		break;
  
  	case 'R':
  		reversed = true;
  		/* fall through */
  
  	default:
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
799
  		separator = ':';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
800
  		break;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
801
  	}
dd45c9cf6   Harvey Harrison   printk: add %pM f...
802
803
  
  	for (i = 0; i < 6; i++) {
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
804
805
806
807
  		if (reversed)
  			p = hex_byte_pack(p, addr[5 - i]);
  		else
  			p = hex_byte_pack(p, addr[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
808
  		if (fmt[0] == 'M' && i != 5)
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
809
  			*p++ = separator;
dd45c9cf6   Harvey Harrison   printk: add %pM f...
810
811
  	}
  	*p = '\0';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
812
  	return string(buf, end, mac_addr, spec);
dd45c9cf6   Harvey Harrison   printk: add %pM f...
813
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
814
815
  static noinline_for_stack
  char *ip4_string(char *p, const u8 *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
816
817
  {
  	int i;
0159f24ee   Joe Perches   lib/vsprintf.c: A...
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
  	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...
843
844
  	for (i = 0; i < 4; i++) {
  		char temp[3];	/* hold each IP quad in reverse order */
133fd9f5c   Denys Vlasenko   vsprintf: further...
845
  		int digits = put_dec_trunc8(temp, addr[index]) - temp;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
846
847
848
849
850
851
852
853
854
855
856
  		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...
857
  		index += step;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
858
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
859
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
860

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
861
862
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
863
864
  static noinline_for_stack
  char *ip6_compressed_string(char *p, const char *addr)
689afa7da   Harvey Harrison   printk: add %p6 f...
865
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
866
  	int i, j, range;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
867
868
869
870
  	unsigned char zerolength[8];
  	int longest = 1;
  	int colonpos = -1;
  	u16 word;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
871
  	u8 hi, lo;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
872
  	bool needcolon = false;
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
873
874
875
876
877
878
  	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...
879
880
881
882
883
884
885
886
887
888
889
  
  	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...
890
  			if (in6.s6_addr16[j] != 0)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
891
892
893
894
895
896
897
898
899
900
  				break;
  			zerolength[i]++;
  		}
  	}
  	for (i = 0; i < range; i++) {
  		if (zerolength[i] > longest) {
  			longest = zerolength[i];
  			colonpos = i;
  		}
  	}
29cf519ee   Joe Perches   vsprintf: Update ...
901
902
  	if (longest == 1)		/* don't compress a single 0 */
  		colonpos = -1;
689afa7da   Harvey Harrison   printk: add %p6 f...
903

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  	/* 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...
919
  		word = ntohs(in6.s6_addr16[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
920
921
922
923
  		hi = word >> 8;
  		lo = word & 0xff;
  		if (hi) {
  			if (hi > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
924
  				p = hex_byte_pack(p, hi);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
925
926
  			else
  				*p++ = hex_asc_lo(hi);
55036ba76   Andy Shevchenko   lib: rename pack_...
927
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
928
  		}
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
929
  		else if (lo > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
930
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
931
932
933
934
935
936
937
938
  		else
  			*p++ = hex_asc_lo(lo);
  		needcolon = true;
  	}
  
  	if (useIPv4) {
  		if (needcolon)
  			*p++ = ':';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
939
  		p = ip4_string(p, &in6.s6_addr[12], "I4");
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
940
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
941
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
942

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
943
944
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
945
946
  static noinline_for_stack
  char *ip6_string(char *p, const char *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
947
948
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
949

689afa7da   Harvey Harrison   printk: add %p6 f...
950
  	for (i = 0; i < 8; i++) {
55036ba76   Andy Shevchenko   lib: rename pack_...
951
952
  		p = hex_byte_pack(p, *addr++);
  		p = hex_byte_pack(p, *addr++);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
953
  		if (fmt[0] == 'I' && i != 7)
689afa7da   Harvey Harrison   printk: add %p6 f...
954
955
956
  			*p++ = ':';
  	}
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
957

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
958
959
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
960
961
962
  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...
963
964
965
966
  {
  	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...
967
  		ip6_compressed_string(ip6_addr, addr);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
968
  	else
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
969
  		ip6_string(ip6_addr, addr, fmt);
689afa7da   Harvey Harrison   printk: add %p6 f...
970

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
971
  	return string(buf, end, ip6_addr, spec);
689afa7da   Harvey Harrison   printk: add %p6 f...
972
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
973
974
975
  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, ...
976
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
977
  	char ip4_addr[sizeof("255.255.255.255")];
4aa996066   Harvey Harrison   printk: add %I4, ...
978

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
981
  	return string(buf, end, ip4_addr, spec);
4aa996066   Harvey Harrison   printk: add %I4, ...
982
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
983
  static noinline_for_stack
106796430   Daniel Borkmann   lib: vsprintf: ad...
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
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
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
  char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa,
  			 struct printf_spec spec, const char *fmt)
  {
  	bool have_p = false, have_s = false, have_f = false, have_c = false;
  	char ip6_addr[sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") +
  		      sizeof(":12345") + sizeof("/123456789") +
  		      sizeof("%1234567890")];
  	char *p = ip6_addr, *pend = ip6_addr + sizeof(ip6_addr);
  	const u8 *addr = (const u8 *) &sa->sin6_addr;
  	char fmt6[2] = { fmt[0], '6' };
  	u8 off = 0;
  
  	fmt++;
  	while (isalpha(*++fmt)) {
  		switch (*fmt) {
  		case 'p':
  			have_p = true;
  			break;
  		case 'f':
  			have_f = true;
  			break;
  		case 's':
  			have_s = true;
  			break;
  		case 'c':
  			have_c = true;
  			break;
  		}
  	}
  
  	if (have_p || have_s || have_f) {
  		*p = '[';
  		off = 1;
  	}
  
  	if (fmt6[0] == 'I' && have_c)
  		p = ip6_compressed_string(ip6_addr + off, addr);
  	else
  		p = ip6_string(ip6_addr + off, addr, fmt6);
  
  	if (have_p || have_s || have_f)
  		*p++ = ']';
  
  	if (have_p) {
  		*p++ = ':';
  		p = number(p, pend, ntohs(sa->sin6_port), spec);
  	}
  	if (have_f) {
  		*p++ = '/';
  		p = number(p, pend, ntohl(sa->sin6_flowinfo &
  					  IPV6_FLOWINFO_MASK), spec);
  	}
  	if (have_s) {
  		*p++ = '%';
  		p = number(p, pend, sa->sin6_scope_id, spec);
  	}
  	*p = '\0';
  
  	return string(buf, end, ip6_addr, spec);
  }
  
  static noinline_for_stack
  char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
  			 struct printf_spec spec, const char *fmt)
  {
  	bool have_p = false;
  	char *p, ip4_addr[sizeof("255.255.255.255") + sizeof(":12345")];
  	char *pend = ip4_addr + sizeof(ip4_addr);
  	const u8 *addr = (const u8 *) &sa->sin_addr.s_addr;
  	char fmt4[3] = { fmt[0], '4', 0 };
  
  	fmt++;
  	while (isalpha(*++fmt)) {
  		switch (*fmt) {
  		case 'p':
  			have_p = true;
  			break;
  		case 'h':
  		case 'l':
  		case 'n':
  		case 'b':
  			fmt4[2] = *fmt;
  			break;
  		}
  	}
  
  	p = ip4_string(ip4_addr, addr, fmt4);
  	if (have_p) {
  		*p++ = ':';
  		p = number(p, pend, ntohs(sa->sin_port), spec);
  	}
  	*p = '\0';
  
  	return string(buf, end, ip4_addr, spec);
  }
  
  static noinline_for_stack
cf3b429b0   Joe Perches   vsprintf.c: use n...
1081
1082
  char *uuid_string(char *buf, char *end, const u8 *addr,
  		  struct printf_spec spec, const char *fmt)
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
  {
  	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++) {
55036ba76   Andy Shevchenko   lib: rename pack_...
1104
  		p = hex_byte_pack(p, addr[index[i]]);
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  		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);
  }
c8f44affb   Michał Mirosław   net: introduce an...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
  static
  char *netdev_feature_string(char *buf, char *end, const u8 *addr,
  		      struct printf_spec spec)
  {
  	spec.flags |= SPECIAL | SMALL | ZEROPAD;
  	if (spec.field_width == -1)
  		spec.field_width = 2 + 2 * sizeof(netdev_features_t);
  	spec.base = 16;
  
  	return number(buf, end, *(const netdev_features_t *)addr, spec);
  }
aaf07621b   Joe Perches   vsprintf: add %pa...
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  static noinline_for_stack
  char *address_val(char *buf, char *end, const void *addr,
  		  struct printf_spec spec, const char *fmt)
  {
  	unsigned long long num;
  
  	spec.flags |= SPECIAL | SMALL | ZEROPAD;
  	spec.base = 16;
  
  	switch (fmt[1]) {
  	case 'd':
  		num = *(const dma_addr_t *)addr;
  		spec.field_width = sizeof(dma_addr_t) * 2 + 2;
  		break;
  	case 'p':
  	default:
  		num = *(const phys_addr_t *)addr;
  		spec.field_width = sizeof(phys_addr_t) * 2 + 2;
  		break;
  	}
  
  	return number(buf, end, num, spec);
  }
411f05f12   Ingo Molnar   vsprintf: Turn kp...
1160
  int kptr_restrict __read_mostly;
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1161

4d8a743cd   Linus Torvalds   vsprintf: add inf...
1162
1163
1164
1165
1166
  /*
   * 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 ...
1167
1168
   * Right now we handle:
   *
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1169
1170
   * - 'F' For symbolic function descriptor pointers with offset
   * - 'f' For simple symbolic function names without offset
0efb4d207   Steven Rostedt   vsnprintf: remove...
1171
1172
   * - 'S' For symbolic direct pointers with offset
   * - 's' For symbolic direct pointers without offset
b0d33c2bd   Joe Perches   vsprintf: Add ext...
1173
   * - '[FfSs]R' as above with __builtin_extract_return_addr() translation
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
1174
   * - 'B' For backtraced symbolic direct pointers with offset
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1175
1176
   * - '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...
1177
1178
   * - '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...
1179
   * - 'm' For a 6-byte MAC address, it prints the hex address without colons
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1180
   * - 'MF' For a 6-byte MAC FDDI address, it prints the address
c8e000604   Joe Perches   lib: Kill bit-rev...
1181
   *       with a dash-separated hex notation
7c59154e7   Andy Shevchenko   lib/vsprintf: upd...
1182
   * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1183
1184
1185
   * - '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
106796430   Daniel Borkmann   lib: vsprintf: ad...
1186
1187
1188
   *       [S][pfs]
   *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
   *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1189
1190
1191
   * - '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)
106796430   Daniel Borkmann   lib: vsprintf: ad...
1192
1193
1194
1195
1196
   *       [S][pfs]
   *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
   *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
   * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
   * - 'I[6S]c' for IPv6 addresses printed as specified by
29cf519ee   Joe Perches   vsprintf: Update ...
1197
   *       http://tools.ietf.org/html/rfc5952
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
   * - '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...
1209
1210
1211
1212
1213
   * - '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...
1214
   * - 'K' For a kernel pointer that should be hidden from unprivileged users
c8f44affb   Michał Mirosław   net: introduce an...
1215
   * - 'NF' For a netdev_features_t
31550a16a   Andy Shevchenko   vsprintf: add sup...
1216
1217
1218
1219
1220
1221
1222
   * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
   *            a certain separator (' ' by default):
   *              C colon
   *              D dash
   *              N no separator
   *            The maximum supported length is 64 bytes of the input. Consider
   *            to use print_hex_dump() for the larger input.
aaf07621b   Joe Perches   vsprintf: add %pa...
1223
1224
   * - 'a[pd]' For address types [p] phys_addr_t, [d] dma_addr_t and derivatives
   *           (default assumed to be phys_addr_t, passed by reference)
c0d92a57a   Olof Johansson   lib/vsprintf.c: d...
1225
1226
   * - 'd[234]' For a dentry name (optionally 2-4 last components)
   * - 'D[234]' Same as 'd' but for a struct file
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1227
   *
332d2e783   Linus Torvalds   Implement %pR to ...
1228
1229
1230
   * 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...
1231
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
1232
1233
1234
  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...
1235
  {
725fe002d   Grant Likely   vsprintf: correct...
1236
  	int default_width = 2 * sizeof(void *) + (spec.flags & SPECIAL ? 2 : 0);
9f36e2c44   Kees Cook   printk: use %pK f...
1237
  	if (!ptr && *fmt != 'K') {
5e0579812   Joe Perches   vsprintf.c: use d...
1238
1239
1240
1241
1242
  		/*
  		 * Print (null) with the same width as a pointer so it makes
  		 * tabular output look nice.
  		 */
  		if (spec.field_width == -1)
725fe002d   Grant Likely   vsprintf: correct...
1243
  			spec.field_width = default_width;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1244
  		return string(buf, end, "(null)", spec);
5e0579812   Joe Perches   vsprintf.c: use d...
1245
  	}
d97106ab5   Linus Torvalds   Make %p print '(n...
1246

0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1247
1248
  	switch (*fmt) {
  	case 'F':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1249
  	case 'f':
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1250
1251
1252
  		ptr = dereference_function_descriptor(ptr);
  		/* Fallthrough */
  	case 'S':
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1253
  	case 's':
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
1254
  	case 'B':
b0d33c2bd   Joe Perches   vsprintf: Add ext...
1255
  		return symbol_string(buf, end, ptr, spec, fmt);
332d2e783   Linus Torvalds   Implement %pR to ...
1256
  	case 'R':
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1257
  	case 'r':
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1258
  		return resource_string(buf, end, ptr, spec, fmt);
31550a16a   Andy Shevchenko   vsprintf: add sup...
1259
1260
  	case 'h':
  		return hex_string(buf, end, ptr, spec, fmt);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1261
1262
  	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
  	case 'm':			/* Contiguous: 000102030405 */
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1263
1264
  					/* [mM]F (FDDI) */
  					/* [mM]R (Reverse order; Bluetooth) */
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
  		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);
106796430   Daniel Borkmann   lib: vsprintf: ad...
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
  		case 'S': {
  			const union {
  				struct sockaddr		raw;
  				struct sockaddr_in	v4;
  				struct sockaddr_in6	v6;
  			} *sa = ptr;
  
  			switch (sa->raw.sa_family) {
  			case AF_INET:
  				return ip4_addr_string_sa(buf, end, &sa->v4, spec, fmt);
  			case AF_INET6:
  				return ip6_addr_string_sa(buf, end, &sa->v6, spec, fmt);
  			default:
  				return string(buf, end, "(invalid address)", spec);
  			}}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1295
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1296
  		break;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1297
1298
  	case 'U':
  		return uuid_string(buf, end, ptr, spec, fmt);
7db6f5fb6   Joe Perches   vsprintf: Recursi...
1299
  	case 'V':
5756b76e4   Jan Beulich   vsprintf: make %p...
1300
1301
1302
1303
1304
1305
1306
1307
1308
  		{
  			va_list va;
  
  			va_copy(va, *((struct va_format *)ptr)->va);
  			buf += vsnprintf(buf, end > buf ? end - buf : 0,
  					 ((struct va_format *)ptr)->fmt, va);
  			va_end(va);
  			return buf;
  		}
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1309
1310
1311
1312
1313
  	case 'K':
  		/*
  		 * %pK cannot be used in IRQ context because its test
  		 * for CAP_SYSLOG would be meaningless.
  		 */
3715c5309   Dan Rosenberg   lib/vsprintf.c: k...
1314
1315
  		if (kptr_restrict && (in_irq() || in_serving_softirq() ||
  				      in_nmi())) {
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1316
  			if (spec.field_width == -1)
725fe002d   Grant Likely   vsprintf: correct...
1317
  				spec.field_width = default_width;
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1318
  			return string(buf, end, "pK-error", spec);
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1319
  		}
312b4e226   Ryan Mallon   vsprintf: check r...
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
  
  		switch (kptr_restrict) {
  		case 0:
  			/* Always print %pK values */
  			break;
  		case 1: {
  			/*
  			 * Only print the real pointer value if the current
  			 * process has CAP_SYSLOG and is running with the
  			 * same credentials it started with. This is because
  			 * access to files is checked at open() time, but %pK
  			 * checks permission at read() time. We don't want to
  			 * leak pointer values if a binary opens a file using
  			 * %pK and then elevates privileges before reading it.
  			 */
  			const struct cred *cred = current_cred();
  
  			if (!has_capability_noaudit(current, CAP_SYSLOG) ||
  			    !uid_eq(cred->euid, cred->uid) ||
  			    !gid_eq(cred->egid, cred->gid))
  				ptr = NULL;
  			break;
  		}
  		case 2:
  		default:
  			/* Always print 0's for %pK */
26297607e   Joe Perches   vsprintf: neaten ...
1346
  			ptr = NULL;
312b4e226   Ryan Mallon   vsprintf: check r...
1347
1348
  			break;
  		}
26297607e   Joe Perches   vsprintf: neaten ...
1349
  		break;
312b4e226   Ryan Mallon   vsprintf: check r...
1350

c8f44affb   Michał Mirosław   net: introduce an...
1351
1352
1353
1354
1355
1356
  	case 'N':
  		switch (fmt[1]) {
  		case 'F':
  			return netdev_feature_string(buf, end, ptr, spec);
  		}
  		break;
7d7992108   Stepan Moskovchenko   lib/vsprintf.c: a...
1357
  	case 'a':
aaf07621b   Joe Perches   vsprintf: add %pa...
1358
  		return address_val(buf, end, ptr, spec, fmt);
4b6ccca70   Al Viro   add formats for d...
1359
1360
1361
1362
1363
1364
  	case 'd':
  		return dentry_name(buf, end, ptr, spec, fmt);
  	case 'D':
  		return dentry_name(buf, end,
  				   ((const struct file *)ptr)->f_path.dentry,
  				   spec, fmt);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1365
1366
1367
  	}
  	spec.flags |= SMALL;
  	if (spec.field_width == -1) {
725fe002d   Grant Likely   vsprintf: correct...
1368
  		spec.field_width = default_width;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
  		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...
1396
1397
  static noinline_for_stack
  int format_decode(const char *fmt, struct printf_spec *spec)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1398
1399
  {
  	const char *start = fmt;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1400
1401
  
  	/* we finished early by reading the field width */
ed681a91a   Vegard Nossum   vsprintf: unify t...
1402
  	if (spec->type == FORMAT_TYPE_WIDTH) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
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
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
  		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...
1460
  		spec->type = FORMAT_TYPE_WIDTH;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
  		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...
1475
  			spec->type = FORMAT_TYPE_PRECISION;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1476
1477
1478
1479
1480
1481
1482
  			return ++fmt - start;
  		}
  	}
  
  qualifier:
  	/* get the conversion qualifier */
  	spec->qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1483
1484
  	if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
  	    _tolower(*fmt) == 'z' || *fmt == 't') {
a4e94ef0d   Zhaolei   printk: add suppo...
1485
1486
1487
1488
1489
1490
1491
1492
1493
  		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...
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
  		}
  	}
  
  	/* 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 */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
  	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...
1530
  		spec->flags |= SIGN;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1531
  	case 'u':
4aa996066   Harvey Harrison   printk: add %I4, ...
1532
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1533

708d96fd0   Ryan Mallon   vsprintf: remove ...
1534
1535
1536
1537
1538
1539
1540
1541
1542
  	case 'n':
  		/*
  		 * Since %n poses a greater security risk than utility, treat
  		 * it as an invalid format specifier. Warn about its use so
  		 * that new instances don't get added.
  		 */
  		WARN_ONCE(1, "Please remove ignored %%n in '%s'
  ", fmt);
  		/* Fall-through */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1543
1544
1545
  	default:
  		spec->type = FORMAT_TYPE_INVALID;
  		return fmt - start;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1546
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1547
1548
1549
1550
  
  	if (spec->qualifier == 'L')
  		spec->type = FORMAT_TYPE_LONG_LONG;
  	else if (spec->qualifier == 'l') {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1551
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1552
1553
1554
  			spec->type = FORMAT_TYPE_LONG;
  		else
  			spec->type = FORMAT_TYPE_ULONG;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1555
  	} else if (_tolower(spec->qualifier) == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1556
1557
1558
  		spec->type = FORMAT_TYPE_SIZE_T;
  	} else if (spec->qualifier == 't') {
  		spec->type = FORMAT_TYPE_PTRDIFF;
a4e94ef0d   Zhaolei   printk: add suppo...
1559
1560
1561
1562
1563
  	} 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...
1564
  	} else if (spec->qualifier == 'h') {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1565
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1566
1567
1568
1569
  			spec->type = FORMAT_TYPE_SHORT;
  		else
  			spec->type = FORMAT_TYPE_USHORT;
  	} else {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1570
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1571
1572
1573
  			spec->type = FORMAT_TYPE_INT;
  		else
  			spec->type = FORMAT_TYPE_UINT;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1574
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1575
1576
  
  	return ++fmt - start;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1577
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1578
1579
1580
1581
1582
1583
1584
  /**
   * 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...
1585
   * This function follows C99 vsnprintf, but has some extensions:
91adcd2c4   Steven Rostedt   vsprintf: add %ps...
1586
1587
   * %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...
1588
1589
   * %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...
1590
   * %pB output the name of a backtrace symbol with its offset
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1591
1592
1593
   * %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
7c59154e7   Andy Shevchenko   lib/vsprintf: upd...
1594
1595
   * %pMR output a 6-byte MAC address with colons in reversed order
   * %pMF output a 6-byte MAC address with dashes
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1596
   * %pm output a 6-byte MAC address without colons
7c59154e7   Andy Shevchenko   lib/vsprintf: upd...
1597
   * %pmR output a 6-byte MAC address without colons in reversed order
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1598
1599
1600
1601
   * %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...
1602
   * %pI6c print an IPv6 address as specified by RFC 5952
106796430   Daniel Borkmann   lib: vsprintf: ad...
1603
1604
   * %pIS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
   * %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1605
1606
   * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
   *   case.
31550a16a   Andy Shevchenko   vsprintf: add sup...
1607
1608
   * %*ph[CDN] a variable-length hex string with a separator (supports up to 64
   *           bytes of the input)
0efb4d207   Steven Rostedt   vsnprintf: remove...
1609
   * %n is ignored
20036fdca   Andi Kleen   Add kerneldoc doc...
1610
   *
80f548e04   Andrew Morton   lib/vsprintf.c: r...
1611
1612
   * ** Please update Documentation/printk-formats.txt when making changes **
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1613
1614
1615
1616
   * 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 ...
1617
   * (not including the trailing '\0'), use vscnprintf(). If the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618
1619
1620
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1621
   * If you're not already dealing with a va_list consider using snprintf().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1622
1623
1624
   */
  int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1625
  	unsigned long long num;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1626
  	char *str, *end;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1627
  	struct printf_spec spec = {0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1629
1630
  	/* Reject out-of-range values early.  Large positive sizes are
  	   used for unknown buffer sizes. */
2f30b1f9e   Marcin Slusarz   vsprintf: use WAR...
1631
  	if (WARN_ON_ONCE((int) size < 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1632
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633
1634
  
  	str = buf;
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1635
  	end = buf + size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1636

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1637
1638
1639
1640
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1641
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1642
1643
  	while (*fmt) {
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1644
  		int read = format_decode(fmt, &spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1648
1649
1650
1651
1652
1653
1654
  		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
1655
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1656
1657
  			str += read;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
1659
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1660
1661
  			spec.field_width = va_arg(args, int);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1663
1664
1665
  		case FORMAT_TYPE_PRECISION:
  			spec.precision = va_arg(args, int);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666

d4be151b2   André Goddard Rosa   vsprintf: move lo...
1667
1668
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1669
1670
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1671
  					if (str < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1672
1673
  						*str = ' ';
  					++str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1675
1676
1677
1678
1679
1680
1681
  				}
  			}
  			c = (unsigned char) va_arg(args, int);
  			if (str < end)
  				*str = c;
  			++str;
  			while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1682
  				if (str < end)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1683
  					*str = ' ';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1684
  				++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1685
1686
  			}
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1687
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1693
1694
1695
1696
1697
1698
  		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
1699

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1700
1701
1702
1703
1704
  		case FORMAT_TYPE_PERCENT_CHAR:
  			if (str < end)
  				*str = '%';
  			++str;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1705

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1706
1707
1708
1709
  		case FORMAT_TYPE_INVALID:
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1710
  			break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
  		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:
ef1249602   Jason Gunthorpe   lib/vsprintf.c: f...
1723
1724
1725
1726
  				if (spec.flags & SIGN)
  					num = va_arg(args, ssize_t);
  				else
  					num = va_arg(args, size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1727
1728
1729
1730
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = va_arg(args, ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1731
1732
1733
1734
1735
1736
  			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...
1737
1738
1739
1740
1741
1742
  			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...
1743
1744
  			case FORMAT_TYPE_INT:
  				num = (int) va_arg(args, int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1745
1746
1747
1748
1749
1750
  				break;
  			default:
  				num = va_arg(args, unsigned int);
  			}
  
  			str = number(str, end, num, spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1751
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1752
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1753

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1754
1755
1756
1757
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
0a6047eef   Linus Torvalds   Fix vsnprintf off...
1758
  			end[-1] = '\0';
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1759
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1760

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1764
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
  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...
1775
   * the @buf not including the trailing '\0'. If @size is == 0 the function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
1777
   * returns 0.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1778
   * If you're not already dealing with a va_list consider using scnprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
1779
1780
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1781
1782
1783
1784
   */
  int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1785
  	i = vsnprintf(buf, size, fmt, args);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1786
1787
1788
1789
1790
  	if (likely(i < size))
  		return i;
  	if (size != 0)
  		return size - 1;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1791
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
  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...
1805
1806
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1808
  int snprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809
1810
1811
1812
1813
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1814
  	i = vsnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1815
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1816

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817
1818
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
  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...
1829
   * the trailing '\0'. If @size is == 0 the function returns 0.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1830
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1831
  int scnprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
1833
1834
1835
1836
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1837
  	i = vscnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1839

b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1840
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
  }
  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 ...
1851
   * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1852
1853
   * buffer overflows.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1854
   * If you're not already dealing with a va_list consider using sprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
1855
1856
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1857
1858
1859
1860
1861
   */
  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
1862
1863
1864
1865
1866
1867
1868
1869
1870
  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 ...
1871
   * into @buf. Use snprintf() or scnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1872
   * buffer overflows.
20036fdca   Andi Kleen   Add kerneldoc doc...
1873
1874
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1876
  int sprintf(char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1877
1878
1879
1880
1881
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1882
  	i = vsnprintf(buf, INT_MAX, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1883
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1884

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1885
1886
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1887
  EXPORT_SYMBOL(sprintf);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
  #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...
1914
  	struct printf_spec spec = {0};
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1915
  	char *str, *end;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
  
  	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...
1939
  	while (*fmt) {
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1940
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1941

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1944
1945
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE:
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1946
1947
  		case FORMAT_TYPE_INVALID:
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1948
  			break;
ed681a91a   Vegard Nossum   vsprintf: unify t...
1949
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1950
1951
1952
1953
1954
  		case FORMAT_TYPE_PRECISION:
  			save_arg(int);
  			break;
  
  		case FORMAT_TYPE_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1955
  			save_arg(char);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1956
1957
1958
  			break;
  
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1959
1960
  			const char *save_str = va_arg(args, char *);
  			size_t len;
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
1961

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1962
1963
  			if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
  					|| (unsigned long)save_str < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
1964
  				save_str = "(null)";
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
1965
1966
1967
1968
  			len = strlen(save_str) + 1;
  			if (str + len < end)
  				memcpy(str, save_str, len);
  			str += len;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1969
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1970
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1971
1972
  
  		case FORMAT_TYPE_PTR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1973
1974
  			save_arg(void *);
  			/* skip all alphanumeric pointer suffixes */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1975
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1976
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1977
  			break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1978
1979
1980
1981
  		default:
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1982
  				save_arg(long long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1983
1984
1985
  				break;
  			case FORMAT_TYPE_ULONG:
  			case FORMAT_TYPE_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1986
  				save_arg(unsigned long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1987
1988
  				break;
  			case FORMAT_TYPE_SIZE_T:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1989
  				save_arg(size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1990
1991
  				break;
  			case FORMAT_TYPE_PTRDIFF:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1992
  				save_arg(ptrdiff_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1993
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1994
1995
1996
1997
  			case FORMAT_TYPE_UBYTE:
  			case FORMAT_TYPE_BYTE:
  				save_arg(char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1998
1999
  			case FORMAT_TYPE_USHORT:
  			case FORMAT_TYPE_SHORT:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2000
  				save_arg(short);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2001
2002
  				break;
  			default:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2003
  				save_arg(int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2004
  			}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2005
2006
  		}
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2007

7b9186f5e   André Goddard Rosa   vsprintf: give it...
2008
  	return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2009
  #undef save_arg
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
  }
  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...
2025
   *  see vsnprintf comment for details.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
   *
   * 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...
2037
  	struct printf_spec spec = {0};
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2038
2039
  	char *str, *end;
  	const char *args = (const char *)bin_buf;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2040

2f30b1f9e   Marcin Slusarz   vsprintf: use WAR...
2041
  	if (WARN_ON_ONCE((int) size < 0))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2042
  		return 0;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
  
  	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...
2067
  	while (*fmt) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2068
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2069
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2070

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2073
2074
2075
2076
2077
2078
2079
  		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...
2080
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2081
2082
  			str += read;
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2083
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
2084
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2085
2086
  			spec.field_width = get_arg(int);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2087

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2088
2089
2090
  		case FORMAT_TYPE_PRECISION:
  			spec.precision = get_arg(int);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2091

d4be151b2   André Goddard Rosa   vsprintf: move lo...
2092
2093
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2094
2095
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2096
2097
2098
2099
2100
2101
2102
2103
2104
  					if (str < end)
  						*str = ' ';
  					++str;
  				}
  			}
  			c = (unsigned char) get_arg(char);
  			if (str < end)
  				*str = c;
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2105
  			while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2106
2107
2108
2109
  				if (str < end)
  					*str = ' ';
  				++str;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2110
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2111
  		}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2112

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2113
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2114
  			const char *str_arg = args;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2115
  			args += strlen(str_arg) + 1;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2116
2117
  			str = string(str, end, (char *)str_arg, spec);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2118
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2119
2120
2121
  		case FORMAT_TYPE_PTR:
  			str = pointer(fmt+1, str, end, get_arg(void *), spec);
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2122
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2123
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2124

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2125
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2126
  		case FORMAT_TYPE_INVALID:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2127
2128
2129
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2130
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2131
2132
  		default: {
  			unsigned long long num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2133
2134
2135
2136
2137
2138
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
  				num = get_arg(long long);
  				break;
  			case FORMAT_TYPE_ULONG:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2139
2140
2141
2142
2143
2144
2145
2146
2147
  			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...
2148
2149
2150
2151
2152
2153
  			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...
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
  			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...
2168
2169
2170
  		} /* default: */
  		} /* switch(spec.type) */
  	} /* while(*fmt) */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2171

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2172
2173
2174
2175
2176
2177
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
  			end[-1] = '\0';
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2178

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
  #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...
2204

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2205
2206
2207
2208
2209
  	return ret;
  }
  EXPORT_SYMBOL_GPL(bprintf);
  
  #endif /* CONFIG_BINARY_PRINTF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
2211
2212
2213
2214
2215
  /**
   * 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...
2216
  int vsscanf(const char *buf, const char *fmt, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2217
2218
2219
2220
2221
  {
  	const char *str = buf;
  	char *next;
  	char digit;
  	int num = 0;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
2222
  	u8 qualifier;
53809751a   Jan Beulich   sscanf: don't ign...
2223
2224
2225
2226
2227
  	unsigned int base;
  	union {
  		long long s;
  		unsigned long long u;
  	} val;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
2228
  	s16 field_width;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2229
  	bool is_sign;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2230

da99075c1   Jan Beulich   lib/vsprintf.c: i...
2231
  	while (*fmt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2232
2233
2234
2235
2236
  		/* 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...
2237
2238
  			fmt = skip_spaces(++fmt);
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
  		}
  
  		/* 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...
2251

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2252
2253
2254
2255
  		/* skip this conversion.
  		 * advance both strings to next white space
  		 */
  		if (*fmt == '*') {
da99075c1   Jan Beulich   lib/vsprintf.c: i...
2256
2257
  			if (!*str)
  				break;
8fccae2c9   Andy Spencer   sscanf(): fix %*s%n
2258
  			while (!isspace(*fmt) && *fmt != '%' && *fmt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259
2260
2261
2262
2263
2264
2265
2266
  				fmt++;
  			while (!isspace(*str) && *str)
  				str++;
  			continue;
  		}
  
  		/* get field width */
  		field_width = -1;
53809751a   Jan Beulich   sscanf: don't ign...
2267
  		if (isdigit(*fmt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2268
  			field_width = skip_atoi(&fmt);
53809751a   Jan Beulich   sscanf: don't ign...
2269
2270
2271
  			if (field_width <= 0)
  				break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
2273
2274
  
  		/* get conversion qualifier */
  		qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
2275
2276
  		if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
  		    _tolower(*fmt) == 'z') {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
  			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
2288

da99075c1   Jan Beulich   lib/vsprintf.c: i...
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
  		if (!*fmt)
  			break;
  
  		if (*fmt == 'n') {
  			/* return number of characters read so far */
  			*va_arg(args, int *) = str - buf;
  			++fmt;
  			continue;
  		}
  
  		if (!*str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2300
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2301
2302
  		base = 10;
  		is_sign = 0;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2303
  		switch (*fmt++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
2305
  		case 'c':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2306
  			char *s = (char *)va_arg(args, char*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
  			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...
2317
2318
  			char *s = (char *)va_arg(args, char *);
  			if (field_width == -1)
4be929be3   Alexey Dobriyan   kernel-wide: repl...
2319
  				field_width = SHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2320
  			/* first, skip leading white space in buffer */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
2321
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2322
2323
  
  			/* now copy until next white space */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2324
  			while (*str && !isspace(*str) && field_width--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2325
  				*s++ = *str++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
2327
2328
2329
  			*s = '\0';
  			num++;
  		}
  		continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2330
2331
2332
2333
2334
2335
2336
2337
  		case 'o':
  			base = 8;
  			break;
  		case 'x':
  		case 'X':
  			base = 16;
  			break;
  		case 'i':
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2338
  			base = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2339
2340
2341
2342
2343
2344
  		case 'd':
  			is_sign = 1;
  		case 'u':
  			break;
  		case '%':
  			/* looking for '%' in str */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2345
  			if (*str++ != '%')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
  				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...
2356
  		str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2357
2358
2359
2360
2361
2362
  
  		digit = *str;
  		if (is_sign && digit == '-')
  			digit = *(str + 1);
  
  		if (!digit
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2363
2364
2365
2366
2367
  		    || (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
2368

53809751a   Jan Beulich   sscanf: don't ign...
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
  		if (is_sign)
  			val.s = qualifier != 'L' ?
  				simple_strtol(str, &next, base) :
  				simple_strtoll(str, &next, base);
  		else
  			val.u = qualifier != 'L' ?
  				simple_strtoul(str, &next, base) :
  				simple_strtoull(str, &next, base);
  
  		if (field_width > 0 && next - str > field_width) {
  			if (base == 0)
  				_parse_integer_fixup_radix(str, &base);
  			while (next - str > field_width) {
  				if (is_sign)
  					val.s = div_s64(val.s, base);
  				else
  					val.u = div_u64(val.u, base);
  				--next;
  			}
  		}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2389
  		switch (qualifier) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2390
  		case 'H':	/* that's 'hh' in format */
53809751a   Jan Beulich   sscanf: don't ign...
2391
2392
2393
2394
  			if (is_sign)
  				*va_arg(args, signed char *) = val.s;
  			else
  				*va_arg(args, unsigned char *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2395
2396
  			break;
  		case 'h':
53809751a   Jan Beulich   sscanf: don't ign...
2397
2398
2399
2400
  			if (is_sign)
  				*va_arg(args, short *) = val.s;
  			else
  				*va_arg(args, unsigned short *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2401
2402
  			break;
  		case 'l':
53809751a   Jan Beulich   sscanf: don't ign...
2403
2404
2405
2406
  			if (is_sign)
  				*va_arg(args, long *) = val.s;
  			else
  				*va_arg(args, unsigned long *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2407
2408
  			break;
  		case 'L':
53809751a   Jan Beulich   sscanf: don't ign...
2409
2410
2411
2412
  			if (is_sign)
  				*va_arg(args, long long *) = val.s;
  			else
  				*va_arg(args, unsigned long long *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413
2414
2415
  			break;
  		case 'Z':
  		case 'z':
53809751a   Jan Beulich   sscanf: don't ign...
2416
2417
  			*va_arg(args, size_t *) = val.u;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2418
  		default:
53809751a   Jan Beulich   sscanf: don't ign...
2419
2420
2421
2422
  			if (is_sign)
  				*va_arg(args, int *) = val.s;
  			else
  				*va_arg(args, unsigned int *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2423
2424
2425
2426
2427
2428
2429
2430
  			break;
  		}
  		num++;
  
  		if (!next)
  			break;
  		str = next;
  	}
c6b40d16d   Johannes Berg   fix sscanf %n mat...
2431

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2432
2433
  	return num;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2434
2435
2436
2437
2438
2439
2440
2441
  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...
2442
  int sscanf(const char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2443
2444
2445
  {
  	va_list args;
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2446
2447
  	va_start(args, fmt);
  	i = vsscanf(buf, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2448
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2449

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450
2451
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2452
  EXPORT_SYMBOL(sscanf);