Blame view

lib/vsprintf.c 52.7 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
25
  #include <linux/kallsyms.h>
  #include <linux/uaccess.h>
332d2e783   Linus Torvalds   Implement %pR to ...
26
  #include <linux/ioport.h>
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
27
  #include <net/addrconf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
36
   * simple_strtoull - convert a string to an unsigned long long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
41
  unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  {
1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
43
44
  	unsigned long long result;
  	unsigned int rv;
aa46a63ef   Harvey Harrison   lib: pull base-gu...
45

1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
46
47
48
49
  	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...
50

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
  	return result;
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
56
  EXPORT_SYMBOL(simple_strtoull);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
59
   * simple_strtoul - convert a string to an unsigned long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
64
  unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
66
  	return simple_strtoull(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
68
  EXPORT_SYMBOL(simple_strtoul);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
71
   * simple_strtol - convert a string to a signed long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
76
  long simple_strtol(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
78
79
  	if (*cp == '-')
  		return -simple_strtoul(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
80

922ac25c9   André Goddard Rosa   vsprintf: reuse a...
81
  	return simple_strtoul(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
83
  EXPORT_SYMBOL(simple_strtol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
90
  
  /**
   * simple_strtoll - convert a string to a signed long long
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
22d27051b   Harvey Harrison   lib: trivial whit...
91
  long long simple_strtoll(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
93
  	if (*cp == '-')
22d27051b   Harvey Harrison   lib: trivial whit...
94
  		return -simple_strtoull(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
95

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

cf3b429b0   Joe Perches   vsprintf.c: use n...
100
101
  static noinline_for_stack
  int skip_atoi(const char **s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
103
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
  
  	while (isdigit(**s))
  		i = i*10 + *((*s)++) - '0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
107

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
  	return i;
  }
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
110
111
112
  /* 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...
113
114
115
   * 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...
116

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

133fd9f5c   Denys Vlasenko   vsprintf: further...
124
125
126
127
128
129
130
131
132
133
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
  	/*
  	 * 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...
161
162
  	return buf;
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
163
164
165
166
167
168
  #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...
169
  static noinline_for_stack
133fd9f5c   Denys Vlasenko   vsprintf: further...
170
  char *put_dec_trunc8(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
171
  {
133fd9f5c   Denys Vlasenko   vsprintf: further...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  	unsigned q;
  
  	/* Copy of previous function's body with added early returns */
  	q      = (r * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (r - 10 * q) + '0'; /* 2 */
  	if (q == 0)
  		return buf;
  	r      = (q * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (q - 10 * r) + '0'; /* 3 */
  	if (r == 0)
  		return buf;
  	q      = (r * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (r - 10 * q) + '0'; /* 4 */
  	if (q == 0)
  		return buf;
  	r      = (q * (uint64_t)0x1999999a) >> 32;
  	*buf++ = (q - 10 * r) + '0'; /* 5 */
  	if (r == 0)
  		return buf;
  	q      = (r * 0x199a) >> 16;
  	*buf++ = (r - 10 * q)  + '0'; /* 6 */
  	if (q == 0)
  		return buf;
  	r      = (q * 0xcd) >> 11;
  	*buf++ = (q - 10 * r)  + '0'; /* 7 */
  	if (r == 0)
  		return buf;
  	q      = (r * 0xcd) >> 11;
  	*buf++ = (r - 10 * q) + '0'; /* 8 */
  	if (q == 0)
  		return buf;
  	*buf++ = q + '0'; /* 9 */
  	return buf;
  }
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
206

133fd9f5c   Denys Vlasenko   vsprintf: further...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  /* 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...
223

133fd9f5c   Denys Vlasenko   vsprintf: further...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  #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...
238
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
239
240
241
242
  
  #else
  
  /* Second algorithm: valid only for 64-bit long longs */
cf3b429b0   Joe Perches   vsprintf.c: use n...
243
  static noinline_for_stack
133fd9f5c   Denys Vlasenko   vsprintf: further...
244
  char *put_dec_full4(char *buf, unsigned q)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
245
  {
133fd9f5c   Denys Vlasenko   vsprintf: further...
246
247
248
249
250
251
252
253
254
  	unsigned r;
  	r      = (q * 0xcccd) >> 19;
  	*buf++ = (q - 10 * r) + '0';
  	q      = (r * 0x199a) >> 16;
  	*buf++ = (r - 10 * q)  + '0';
  	r      = (q * 0xcd) >> 11;
  	*buf++ = (q - 10 * r)  + '0';
  	*buf++ = r + '0';
  	return buf;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
255
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  /* 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);
  
  	buf = put_dec_full4(buf, q % 10000);
  	q   = q / 10000;
  
  	d1  = q + 7671 * d3 + 9496 * d2 + 6 * d1;
  	buf = put_dec_full4(buf, d1 % 10000);
  	q   = d1 / 10000;
  
  	d2  = q + 4749 * d3 + 42 * d2;
  	buf = put_dec_full4(buf, d2 % 10000);
  	q   = d2 / 10000;
  
  	d3  = q + 281 * d3;
  	if (!d3)
  		goto done;
  	buf = put_dec_full4(buf, d3 % 10000);
  	q   = d3 / 10000;
  	if (!q)
  		goto done;
  	buf = put_dec_full4(buf, q);
   done:
  	while (buf[-1] == '0')
  		--buf;
  
  	return buf;
  }
  
  #endif
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
303
304
305
306
307
308
309
310
  /*
   * 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...
311
  	char tmp[sizeof(num) * 3];
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
312
  	int idx, len;
133fd9f5c   Denys Vlasenko   vsprintf: further...
313
314
315
316
317
318
319
  	/* 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...
320
321
322
323
324
  
  	if (len > size)
  		return 0;
  	for (idx = 0; idx < len; ++idx)
  		buf[idx] = tmp[len - idx - 1];
133fd9f5c   Denys Vlasenko   vsprintf: further...
325
  	return len;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
326
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
  #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...
332
333
  #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
334

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

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

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

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

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

0f9bfa569   Linus Torvalds   vsprintf: split o...
518
519
  	return buf;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
520
521
522
  static noinline_for_stack
  char *symbol_string(char *buf, char *end, void *ptr,
  		    struct printf_spec spec, char ext)
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
523
524
525
526
  {
  	unsigned long value = (unsigned long) ptr;
  #ifdef CONFIG_KALLSYMS
  	char sym[KSYM_SYMBOL_LEN];
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
527
528
529
  	if (ext == 'B')
  		sprint_backtrace(sym, value);
  	else if (ext != 'f' && ext != 's')
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
530
531
  		sprint_symbol(sym, value);
  	else
4796dd200   Stephen Boyd   vsprintf: fix %ps...
532
  		sprint_symbol_no_offset(sym, value);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
533

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
534
  	return string(buf, end, sym, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
535
  #else
7b9186f5e   André Goddard Rosa   vsprintf: give it...
536
  	spec.field_width = 2 * sizeof(void *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
537
538
  	spec.flags |= SPECIAL | SMALL | ZEROPAD;
  	spec.base = 16;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
539

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
540
  	return number(buf, end, value, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
541
542
  #endif
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
543
544
545
  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 ...
546
547
  {
  #ifndef IO_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
548
  #define IO_RSRC_PRINTK_SIZE	6
332d2e783   Linus Torvalds   Implement %pR to ...
549
550
551
  #endif
  
  #ifndef MEM_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
552
  #define MEM_RSRC_PRINTK_SIZE	10
332d2e783   Linus Torvalds   Implement %pR to ...
553
  #endif
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
554
  	static const struct printf_spec io_spec = {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
555
  		.base = 16,
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
556
  		.field_width = IO_RSRC_PRINTK_SIZE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
557
558
559
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
560
561
562
563
564
565
  	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...
566
567
568
569
570
571
  	static const struct printf_spec bus_spec = {
  		.base = 16,
  		.field_width = 2,
  		.precision = -1,
  		.flags = SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
572
  	static const struct printf_spec dec_spec = {
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
573
574
575
576
  		.base = 10,
  		.precision = -1,
  		.flags = 0,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
577
  	static const struct printf_spec str_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
578
579
580
581
  		.field_width = -1,
  		.precision = 10,
  		.flags = LEFT,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
582
  	static const struct printf_spec flag_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
583
584
585
586
  		.base = 16,
  		.precision = -1,
  		.flags = SPECIAL | SMALL,
  	};
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
587
588
589
590
591
  
  	/* 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...
592
  #define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref window disabled]")
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
593
594
595
  #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 ...
596
  	char *p = sym, *pend = sym + sizeof(sym);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
597
  	int decode = (fmt[0] == 'R') ? 1 : 0;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
598
  	const struct printf_spec *specp;
332d2e783   Linus Torvalds   Implement %pR to ...
599
600
  
  	*p++ = '[';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
601
  	if (res->flags & IORESOURCE_IO) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
602
  		p = string(p, pend, "io  ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
603
604
  		specp = &io_spec;
  	} else if (res->flags & IORESOURCE_MEM) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
605
  		p = string(p, pend, "mem ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
606
607
  		specp = &mem_spec;
  	} else if (res->flags & IORESOURCE_IRQ) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
608
  		p = string(p, pend, "irq ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
609
610
  		specp = &dec_spec;
  	} else if (res->flags & IORESOURCE_DMA) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
611
  		p = string(p, pend, "dma ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
612
  		specp = &dec_spec;
0f4050c7d   Bjorn Helgaas   resource: add bus...
613
614
615
  	} else if (res->flags & IORESOURCE_BUS) {
  		p = string(p, pend, "bus ", str_spec);
  		specp = &bus_spec;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
616
  	} else {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
617
  		p = string(p, pend, "??? ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
618
  		specp = &mem_spec;
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
619
  		decode = 0;
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
620
  	}
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
621
  	p = number(p, pend, res->start, *specp);
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
622
623
  	if (res->start != res->end) {
  		*p++ = '-';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
624
  		p = number(p, pend, res->end, *specp);
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
625
  	}
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
626
  	if (decode) {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
627
628
629
630
  		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...
631
632
  		if (res->flags & IORESOURCE_WINDOW)
  			p = string(p, pend, " window", str_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
633
634
  		if (res->flags & IORESOURCE_DISABLED)
  			p = string(p, pend, " disabled", str_spec);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
635
636
637
  	} else {
  		p = string(p, pend, " flags ", str_spec);
  		p = number(p, pend, res->flags, flag_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
638
  	}
332d2e783   Linus Torvalds   Implement %pR to ...
639
  	*p++ = ']';
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
640
  	*p = '\0';
332d2e783   Linus Torvalds   Implement %pR to ...
641

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
642
  	return string(buf, end, sym, spec);
332d2e783   Linus Torvalds   Implement %pR to ...
643
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
644
  static noinline_for_stack
31550a16a   Andy Shevchenko   vsprintf: add sup...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
  char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
  		 const char *fmt)
  {
  	int i, len = 1;		/* if we pass '%ph[CDN]', field witdh remains
  				   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...
689
690
  char *mac_address_string(char *buf, char *end, u8 *addr,
  			 struct printf_spec spec, const char *fmt)
dd45c9cf6   Harvey Harrison   printk: add %pM f...
691
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
692
  	char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
dd45c9cf6   Harvey Harrison   printk: add %pM f...
693
694
  	char *p = mac_addr;
  	int i;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
695
  	char separator;
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
696
  	bool reversed = false;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
697

76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
698
699
  	switch (fmt[1]) {
  	case 'F':
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
700
  		separator = '-';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
701
702
703
704
705
706
707
  		break;
  
  	case 'R':
  		reversed = true;
  		/* fall through */
  
  	default:
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
708
  		separator = ':';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
709
  		break;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
710
  	}
dd45c9cf6   Harvey Harrison   printk: add %pM f...
711
712
  
  	for (i = 0; i < 6; i++) {
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
713
714
715
716
  		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...
717
  		if (fmt[0] == 'M' && i != 5)
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
718
  			*p++ = separator;
dd45c9cf6   Harvey Harrison   printk: add %pM f...
719
720
  	}
  	*p = '\0';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
721
  	return string(buf, end, mac_addr, spec);
dd45c9cf6   Harvey Harrison   printk: add %pM f...
722
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
723
724
  static noinline_for_stack
  char *ip4_string(char *p, const u8 *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
725
726
  {
  	int i;
0159f24ee   Joe Perches   lib/vsprintf.c: A...
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
  	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...
752
753
  	for (i = 0; i < 4; i++) {
  		char temp[3];	/* hold each IP quad in reverse order */
133fd9f5c   Denys Vlasenko   vsprintf: further...
754
  		int digits = put_dec_trunc8(temp, addr[index]) - temp;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
755
756
757
758
759
760
761
762
763
764
765
  		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...
766
  		index += step;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
767
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
768
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
769

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
770
771
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
772
773
  static noinline_for_stack
  char *ip6_compressed_string(char *p, const char *addr)
689afa7da   Harvey Harrison   printk: add %p6 f...
774
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
775
  	int i, j, range;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
776
777
778
779
  	unsigned char zerolength[8];
  	int longest = 1;
  	int colonpos = -1;
  	u16 word;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
780
  	u8 hi, lo;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
781
  	bool needcolon = false;
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
782
783
784
785
786
787
  	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...
788
789
790
791
792
793
794
795
796
797
798
  
  	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...
799
  			if (in6.s6_addr16[j] != 0)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
800
801
802
803
804
805
806
807
808
809
  				break;
  			zerolength[i]++;
  		}
  	}
  	for (i = 0; i < range; i++) {
  		if (zerolength[i] > longest) {
  			longest = zerolength[i];
  			colonpos = i;
  		}
  	}
29cf519ee   Joe Perches   vsprintf: Update ...
810
811
  	if (longest == 1)		/* don't compress a single 0 */
  		colonpos = -1;
689afa7da   Harvey Harrison   printk: add %p6 f...
812

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
  	/* 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...
828
  		word = ntohs(in6.s6_addr16[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
829
830
831
832
  		hi = word >> 8;
  		lo = word & 0xff;
  		if (hi) {
  			if (hi > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
833
  				p = hex_byte_pack(p, hi);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
834
835
  			else
  				*p++ = hex_asc_lo(hi);
55036ba76   Andy Shevchenko   lib: rename pack_...
836
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
837
  		}
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
838
  		else if (lo > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
839
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
840
841
842
843
844
845
846
847
  		else
  			*p++ = hex_asc_lo(lo);
  		needcolon = true;
  	}
  
  	if (useIPv4) {
  		if (needcolon)
  			*p++ = ':';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
848
  		p = ip4_string(p, &in6.s6_addr[12], "I4");
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
849
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
850
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
851

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
852
853
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
854
855
  static noinline_for_stack
  char *ip6_string(char *p, const char *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
856
857
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
858

689afa7da   Harvey Harrison   printk: add %p6 f...
859
  	for (i = 0; i < 8; i++) {
55036ba76   Andy Shevchenko   lib: rename pack_...
860
861
  		p = hex_byte_pack(p, *addr++);
  		p = hex_byte_pack(p, *addr++);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
862
  		if (fmt[0] == 'I' && i != 7)
689afa7da   Harvey Harrison   printk: add %p6 f...
863
864
865
  			*p++ = ':';
  	}
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
866

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
867
868
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
869
870
871
  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...
872
873
874
875
  {
  	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...
876
  		ip6_compressed_string(ip6_addr, addr);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
877
  	else
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
878
  		ip6_string(ip6_addr, addr, fmt);
689afa7da   Harvey Harrison   printk: add %p6 f...
879

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
880
  	return string(buf, end, ip6_addr, spec);
689afa7da   Harvey Harrison   printk: add %p6 f...
881
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
882
883
884
  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, ...
885
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
886
  	char ip4_addr[sizeof("255.255.255.255")];
4aa996066   Harvey Harrison   printk: add %I4, ...
887

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
890
  	return string(buf, end, ip4_addr, spec);
4aa996066   Harvey Harrison   printk: add %I4, ...
891
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
892
893
894
  static noinline_for_stack
  char *uuid_string(char *buf, char *end, const u8 *addr,
  		  struct printf_spec spec, const char *fmt)
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  {
  	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_...
916
  		p = hex_byte_pack(p, addr[index[i]]);
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
  		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...
938
939
940
941
942
943
944
945
946
947
948
  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);
  }
411f05f12   Ingo Molnar   vsprintf: Turn kp...
949
  int kptr_restrict __read_mostly;
455cd5ab3   Dan Rosenberg   kptr_restrict for...
950

4d8a743cd   Linus Torvalds   vsprintf: add inf...
951
952
953
954
955
  /*
   * 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 ...
956
957
   * Right now we handle:
   *
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
958
959
   * - 'F' For symbolic function descriptor pointers with offset
   * - 'f' For simple symbolic function names without offset
0efb4d207   Steven Rostedt   vsnprintf: remove...
960
961
   * - 'S' For symbolic direct pointers with offset
   * - 's' For symbolic direct pointers without offset
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
962
   * - 'B' For backtraced symbolic direct pointers with offset
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
963
964
   * - '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...
965
966
   * - '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...
967
   * - 'm' For a 6-byte MAC address, it prints the hex address without colons
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
968
   * - 'MF' For a 6-byte MAC FDDI address, it prints the address
c8e000604   Joe Perches   lib: Kill bit-rev...
969
   *       with a dash-separated hex notation
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
970
   * - '[mM]R For a 6-byte MAC address, Reverse order (Bluetooth)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
971
972
973
974
975
976
   * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
   *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
   *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
   * - 'i' [46] for 'raw' IPv4/IPv6 addresses
   *       IPv6 omits the colons (01020304...0f)
   *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
0159f24ee   Joe Perches   lib/vsprintf.c: A...
977
   * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
978
   * - 'I6c' for IPv6 addresses printed as specified by
29cf519ee   Joe Perches   vsprintf: Update ...
979
   *       http://tools.ietf.org/html/rfc5952
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
980
981
982
983
984
985
986
987
988
989
990
   * - '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...
991
992
993
994
995
   * - '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...
996
   * - 'K' For a kernel pointer that should be hidden from unprivileged users
c8f44affb   Michał Mirosław   net: introduce an...
997
   * - 'NF' For a netdev_features_t
31550a16a   Andy Shevchenko   vsprintf: add sup...
998
999
1000
1001
1002
1003
1004
   * - '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.
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1005
   *
332d2e783   Linus Torvalds   Implement %pR to ...
1006
1007
1008
   * 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...
1009
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
1010
1011
1012
  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...
1013
  {
725fe002d   Grant Likely   vsprintf: correct...
1014
  	int default_width = 2 * sizeof(void *) + (spec.flags & SPECIAL ? 2 : 0);
9f36e2c44   Kees Cook   printk: use %pK f...
1015
  	if (!ptr && *fmt != 'K') {
5e0579812   Joe Perches   vsprintf.c: use d...
1016
1017
1018
1019
1020
  		/*
  		 * 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...
1021
  			spec.field_width = default_width;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1022
  		return string(buf, end, "(null)", spec);
5e0579812   Joe Perches   vsprintf.c: use d...
1023
  	}
d97106ab5   Linus Torvalds   Make %p print '(n...
1024

0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1025
1026
  	switch (*fmt) {
  	case 'F':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1027
  	case 'f':
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1028
1029
1030
  		ptr = dereference_function_descriptor(ptr);
  		/* Fallthrough */
  	case 'S':
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1031
  	case 's':
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
1032
  	case 'B':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1033
  		return symbol_string(buf, end, ptr, spec, *fmt);
332d2e783   Linus Torvalds   Implement %pR to ...
1034
  	case 'R':
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1035
  	case 'r':
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1036
  		return resource_string(buf, end, ptr, spec, fmt);
31550a16a   Andy Shevchenko   vsprintf: add sup...
1037
1038
  	case 'h':
  		return hex_string(buf, end, ptr, spec, fmt);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1039
1040
  	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
  	case 'm':			/* Contiguous: 000102030405 */
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1041
1042
  					/* [mM]F (FDDI) */
  					/* [mM]R (Reverse order; Bluetooth) */
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  		return mac_address_string(buf, end, ptr, spec, fmt);
  	case 'I':			/* Formatted IP supported
  					 * 4:	1.2.3.4
  					 * 6:	0001:0203:...:0708
  					 * 6c:	1::708 or 1::1.2.3.4
  					 */
  	case 'i':			/* Contiguous:
  					 * 4:	001.002.003.004
  					 * 6:   000102...0f
  					 */
  		switch (fmt[1]) {
  		case '6':
  			return ip6_addr_string(buf, end, ptr, spec, fmt);
  		case '4':
  			return ip4_addr_string(buf, end, ptr, spec, fmt);
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1059
  		break;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1060
1061
  	case 'U':
  		return uuid_string(buf, end, ptr, spec, fmt);
7db6f5fb6   Joe Perches   vsprintf: Recursi...
1062
  	case 'V':
5756b76e4   Jan Beulich   vsprintf: make %p...
1063
1064
1065
1066
1067
1068
1069
1070
1071
  		{
  			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...
1072
1073
1074
1075
1076
  	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...
1077
1078
  		if (kptr_restrict && (in_irq() || in_serving_softirq() ||
  				      in_nmi())) {
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1079
  			if (spec.field_width == -1)
725fe002d   Grant Likely   vsprintf: correct...
1080
  				spec.field_width = default_width;
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1081
  			return string(buf, end, "pK-error", spec);
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1082
  		}
26297607e   Joe Perches   vsprintf: neaten ...
1083
1084
1085
1086
1087
  		if (!((kptr_restrict == 0) ||
  		      (kptr_restrict == 1 &&
  		       has_capability_noaudit(current, CAP_SYSLOG))))
  			ptr = NULL;
  		break;
c8f44affb   Michał Mirosław   net: introduce an...
1088
1089
1090
1091
1092
1093
  	case 'N':
  		switch (fmt[1]) {
  		case 'F':
  			return netdev_feature_string(buf, end, ptr, spec);
  		}
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1094
1095
1096
  	}
  	spec.flags |= SMALL;
  	if (spec.field_width == -1) {
725fe002d   Grant Likely   vsprintf: correct...
1097
  		spec.field_width = default_width;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
  		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...
1125
1126
  static noinline_for_stack
  int format_decode(const char *fmt, struct printf_spec *spec)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1127
1128
  {
  	const char *start = fmt;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1129
1130
  
  	/* we finished early by reading the field width */
ed681a91a   Vegard Nossum   vsprintf: unify t...
1131
  	if (spec->type == FORMAT_TYPE_WIDTH) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
  		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...
1189
  		spec->type = FORMAT_TYPE_WIDTH;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
  		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...
1204
  			spec->type = FORMAT_TYPE_PRECISION;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1205
1206
1207
1208
1209
1210
1211
  			return ++fmt - start;
  		}
  	}
  
  qualifier:
  	/* get the conversion qualifier */
  	spec->qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1212
1213
  	if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
  	    _tolower(*fmt) == 'z' || *fmt == 't') {
a4e94ef0d   Zhaolei   printk: add suppo...
1214
1215
1216
1217
1218
1219
1220
1221
1222
  		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...
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
  		}
  	}
  
  	/* default base */
  	spec->base = 10;
  	switch (*fmt) {
  	case 'c':
  		spec->type = FORMAT_TYPE_CHAR;
  		return ++fmt - start;
  
  	case 's':
  		spec->type = FORMAT_TYPE_STR;
  		return ++fmt - start;
  
  	case 'p':
  		spec->type = FORMAT_TYPE_PTR;
  		return fmt - start;
  		/* skip alnum */
  
  	case 'n':
  		spec->type = FORMAT_TYPE_NRCHARS;
  		return ++fmt - start;
  
  	case '%':
  		spec->type = FORMAT_TYPE_PERCENT_CHAR;
  		return ++fmt - start;
  
  	/* integer number formats - set up the flags and "break" */
  	case 'o':
  		spec->base = 8;
  		break;
  
  	case 'x':
  		spec->flags |= SMALL;
  
  	case 'X':
  		spec->base = 16;
  		break;
  
  	case 'd':
  	case 'i':
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1264
  		spec->flags |= SIGN;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1265
  	case 'u':
4aa996066   Harvey Harrison   printk: add %I4, ...
1266
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1267
1268
1269
1270
  
  	default:
  		spec->type = FORMAT_TYPE_INVALID;
  		return fmt - start;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1271
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1272
1273
1274
1275
  
  	if (spec->qualifier == 'L')
  		spec->type = FORMAT_TYPE_LONG_LONG;
  	else if (spec->qualifier == 'l') {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1276
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1277
1278
1279
  			spec->type = FORMAT_TYPE_LONG;
  		else
  			spec->type = FORMAT_TYPE_ULONG;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1280
  	} else if (_tolower(spec->qualifier) == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1281
1282
1283
  		spec->type = FORMAT_TYPE_SIZE_T;
  	} else if (spec->qualifier == 't') {
  		spec->type = FORMAT_TYPE_PTRDIFF;
a4e94ef0d   Zhaolei   printk: add suppo...
1284
1285
1286
1287
1288
  	} 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...
1289
  	} else if (spec->qualifier == 'h') {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1290
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1291
1292
1293
1294
  			spec->type = FORMAT_TYPE_SHORT;
  		else
  			spec->type = FORMAT_TYPE_USHORT;
  	} else {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1295
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1296
1297
1298
  			spec->type = FORMAT_TYPE_INT;
  		else
  			spec->type = FORMAT_TYPE_UINT;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1299
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1300
1301
  
  	return ++fmt - start;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1302
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
1305
1306
1307
1308
1309
  /**
   * 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...
1310
   * This function follows C99 vsnprintf, but has some extensions:
91adcd2c4   Steven Rostedt   vsprintf: add %ps...
1311
1312
   * %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...
1313
1314
   * %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...
1315
   * %pB output the name of a backtrace symbol with its offset
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1316
1317
1318
1319
1320
1321
1322
1323
   * %pR output the address range in a struct resource with decoded flags
   * %pr output the address range in a struct resource with raw flags
   * %pM output a 6-byte MAC address with colons
   * %pm output a 6-byte MAC address without colons
   * %pI4 print an IPv4 address without leading zeros
   * %pi4 print an IPv4 address with leading zeros
   * %pI6 print an IPv6 address with colons
   * %pi6 print an IPv6 address without colons
f996f2081   Jan Engelhardt   lib/vsprintf: rep...
1324
   * %pI6c print an IPv6 address as specified by RFC 5952
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1325
1326
   * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
   *   case.
31550a16a   Andy Shevchenko   vsprintf: add sup...
1327
1328
   * %*ph[CDN] a variable-length hex string with a separator (supports up to 64
   *           bytes of the input)
0efb4d207   Steven Rostedt   vsnprintf: remove...
1329
   * %n is ignored
20036fdca   Andi Kleen   Add kerneldoc doc...
1330
   *
80f548e04   Andrew Morton   lib/vsprintf.c: r...
1331
1332
   * ** Please update Documentation/printk-formats.txt when making changes **
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
1334
1335
1336
   * 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 ...
1337
   * (not including the trailing '\0'), use vscnprintf(). If the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
1339
1340
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1341
   * If you're not already dealing with a va_list consider using snprintf().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
1343
1344
   */
  int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
  	unsigned long long num;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1346
  	char *str, *end;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1347
  	struct printf_spec spec = {0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1349
1350
  	/* Reject out-of-range values early.  Large positive sizes are
  	   used for unknown buffer sizes. */
2f30b1f9e   Marcin Slusarz   vsprintf: use WAR...
1351
  	if (WARN_ON_ONCE((int) size < 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
1354
  
  	str = buf;
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1355
  	end = buf + size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1357
1358
1359
1360
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1362
1363
  	while (*fmt) {
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1364
  		int read = format_decode(fmt, &spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1368
1369
1370
1371
1372
1373
1374
  		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
1375
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1376
1377
  			str += read;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
1379
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1380
1381
  			spec.field_width = va_arg(args, int);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1383
1384
1385
  		case FORMAT_TYPE_PRECISION:
  			spec.precision = va_arg(args, int);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1386

d4be151b2   André Goddard Rosa   vsprintf: move lo...
1387
1388
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1389
1390
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1391
  					if (str < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
1393
  						*str = ' ';
  					++str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1395
1396
1397
1398
1399
1400
1401
  				}
  			}
  			c = (unsigned char) va_arg(args, int);
  			if (str < end)
  				*str = c;
  			++str;
  			while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1402
  				if (str < end)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1403
  					*str = ' ';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
  				++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1405
1406
  			}
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1407
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1413
1414
1415
1416
1417
1418
  		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
1419

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1420
1421
1422
1423
1424
  		case FORMAT_TYPE_PERCENT_CHAR:
  			if (str < end)
  				*str = '%';
  			++str;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1425

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1426
1427
1428
1429
  		case FORMAT_TYPE_INVALID:
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1430
1431
1432
  			break;
  
  		case FORMAT_TYPE_NRCHARS: {
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1433
  			u8 qualifier = spec.qualifier;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1434
1435
1436
1437
  
  			if (qualifier == 'l') {
  				long *ip = va_arg(args, long *);
  				*ip = (str - buf);
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1438
  			} else if (_tolower(qualifier) == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1439
1440
1441
1442
1443
1444
1445
  				size_t *ip = va_arg(args, size_t *);
  				*ip = (str - buf);
  			} else {
  				int *ip = va_arg(args, int *);
  				*ip = (str - buf);
  			}
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
  
  		default:
  			switch (spec.type) {
  			case FORMAT_TYPE_LONG_LONG:
  				num = va_arg(args, long long);
  				break;
  			case FORMAT_TYPE_ULONG:
  				num = va_arg(args, unsigned long);
  				break;
  			case FORMAT_TYPE_LONG:
  				num = va_arg(args, long);
  				break;
  			case FORMAT_TYPE_SIZE_T:
  				num = va_arg(args, size_t);
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = va_arg(args, ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1465
1466
1467
1468
1469
1470
  			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...
1471
1472
1473
1474
1475
1476
  			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...
1477
1478
  			case FORMAT_TYPE_INT:
  				num = (int) va_arg(args, int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1479
1480
1481
1482
1483
1484
  				break;
  			default:
  				num = va_arg(args, unsigned int);
  			}
  
  			str = number(str, end, num, spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1485
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1486
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1487

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1488
1489
1490
1491
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
0a6047eef   Linus Torvalds   Fix vsnprintf off...
1492
  			end[-1] = '\0';
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1493
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1494

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1498
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
  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...
1509
   * the @buf not including the trailing '\0'. If @size is == 0 the function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1510
1511
   * returns 0.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1512
   * If you're not already dealing with a va_list consider using scnprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
1513
1514
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
1516
1517
1518
   */
  int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1519
  	i = vsnprintf(buf, size, fmt, args);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1520
1521
1522
1523
1524
  	if (likely(i < size))
  		return i;
  	if (size != 0)
  		return size - 1;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
  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...
1539
1540
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1541
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1542
  int snprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
1544
1545
1546
1547
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1548
  	i = vsnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1550

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1551
1552
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
  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...
1563
   * the trailing '\0'. If @size is == 0 the function returns 0.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1565
  int scnprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1566
1567
1568
1569
1570
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1571
  	i = vscnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1573

b921c69fb   Anton Arapov   lib/vsprintf.c: f...
1574
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
  }
  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 ...
1585
   * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
1587
   * buffer overflows.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1588
   * If you're not already dealing with a va_list consider using sprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
1589
1590
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
1592
1593
1594
1595
   */
  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
1596
1597
1598
1599
1600
1601
1602
1603
1604
  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 ...
1605
   * into @buf. Use snprintf() or scnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
   * buffer overflows.
20036fdca   Andi Kleen   Add kerneldoc doc...
1607
1608
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1609
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1610
  int sprintf(char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
1612
1613
1614
1615
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1616
  	i = vsnprintf(buf, INT_MAX, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1618

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
1620
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621
  EXPORT_SYMBOL(sprintf);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
  #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...
1648
  	struct printf_spec spec = {0};
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1649
  	char *str, *end;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
  
  	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...
1673
  	while (*fmt) {
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1674
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1675

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1678
1679
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE:
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1680
1681
  		case FORMAT_TYPE_INVALID:
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1682
  			break;
ed681a91a   Vegard Nossum   vsprintf: unify t...
1683
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1684
1685
1686
1687
1688
  		case FORMAT_TYPE_PRECISION:
  			save_arg(int);
  			break;
  
  		case FORMAT_TYPE_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1689
  			save_arg(char);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1690
1691
1692
  			break;
  
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1693
1694
  			const char *save_str = va_arg(args, char *);
  			size_t len;
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
1695

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1696
1697
  			if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
  					|| (unsigned long)save_str < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
1698
  				save_str = "(null)";
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
1699
1700
1701
1702
  			len = strlen(save_str) + 1;
  			if (str + len < end)
  				memcpy(str, save_str, len);
  			str += len;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1703
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1704
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1705
1706
  
  		case FORMAT_TYPE_PTR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1707
1708
  			save_arg(void *);
  			/* skip all alphanumeric pointer suffixes */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1709
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1710
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1711
  			break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1712
  		case FORMAT_TYPE_NRCHARS: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1713
  			/* skip %n 's argument */
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1714
  			u8 qualifier = spec.qualifier;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1715
1716
1717
  			void *skip_arg;
  			if (qualifier == 'l')
  				skip_arg = va_arg(args, long *);
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1718
  			else if (_tolower(qualifier) == 'z')
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1719
1720
1721
  				skip_arg = va_arg(args, size_t *);
  			else
  				skip_arg = va_arg(args, int *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1722
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1723
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1724
1725
1726
1727
1728
  
  		default:
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1729
  				save_arg(long long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1730
1731
1732
  				break;
  			case FORMAT_TYPE_ULONG:
  			case FORMAT_TYPE_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1733
  				save_arg(unsigned long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1734
1735
  				break;
  			case FORMAT_TYPE_SIZE_T:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1736
  				save_arg(size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1737
1738
  				break;
  			case FORMAT_TYPE_PTRDIFF:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1739
  				save_arg(ptrdiff_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1740
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1741
1742
1743
1744
  			case FORMAT_TYPE_UBYTE:
  			case FORMAT_TYPE_BYTE:
  				save_arg(char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1745
1746
  			case FORMAT_TYPE_USHORT:
  			case FORMAT_TYPE_SHORT:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1747
  				save_arg(short);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1748
1749
  				break;
  			default:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1750
  				save_arg(int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1751
  			}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1752
1753
  		}
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1754

7b9186f5e   André Goddard Rosa   vsprintf: give it...
1755
  	return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1756
  #undef save_arg
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
  }
  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...
1772
   *  see vsnprintf comment for details.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
   *
   * 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...
1784
  	struct printf_spec spec = {0};
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1785
1786
  	char *str, *end;
  	const char *args = (const char *)bin_buf;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1787

2f30b1f9e   Marcin Slusarz   vsprintf: use WAR...
1788
  	if (WARN_ON_ONCE((int) size < 0))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1789
  		return 0;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
  
  	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...
1814
  	while (*fmt) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1815
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1816
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1817

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1820
1821
1822
1823
1824
1825
1826
  		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...
1827
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1828
1829
  			str += read;
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1830
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
1831
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1832
1833
  			spec.field_width = get_arg(int);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1834

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1835
1836
1837
  		case FORMAT_TYPE_PRECISION:
  			spec.precision = get_arg(int);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1838

d4be151b2   André Goddard Rosa   vsprintf: move lo...
1839
1840
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1841
1842
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1843
1844
1845
1846
1847
1848
1849
1850
1851
  					if (str < end)
  						*str = ' ';
  					++str;
  				}
  			}
  			c = (unsigned char) get_arg(char);
  			if (str < end)
  				*str = c;
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1852
  			while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1853
1854
1855
1856
  				if (str < end)
  					*str = ' ';
  				++str;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1857
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1858
  		}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1859

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1860
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1861
  			const char *str_arg = args;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1862
  			args += strlen(str_arg) + 1;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1863
1864
  			str = string(str, end, (char *)str_arg, spec);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1865
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1866
1867
1868
  		case FORMAT_TYPE_PTR:
  			str = pointer(fmt+1, str, end, get_arg(void *), spec);
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1869
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1870
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1871

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1872
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1873
  		case FORMAT_TYPE_INVALID:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1874
1875
1876
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1877
1878
1879
1880
1881
  			break;
  
  		case FORMAT_TYPE_NRCHARS:
  			/* skip */
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1882
1883
  		default: {
  			unsigned long long num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1884
1885
1886
1887
1888
1889
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
  				num = get_arg(long long);
  				break;
  			case FORMAT_TYPE_ULONG:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1890
1891
1892
1893
1894
1895
1896
1897
1898
  			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...
1899
1900
1901
1902
1903
1904
  			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...
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
  			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...
1919
1920
1921
  		} /* default: */
  		} /* switch(spec.type) */
  	} /* while(*fmt) */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1922

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1923
1924
1925
1926
1927
1928
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
  			end[-1] = '\0';
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1929

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
  #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...
1955

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1956
1957
1958
1959
1960
  	return ret;
  }
  EXPORT_SYMBOL_GPL(bprintf);
  
  #endif /* CONFIG_BINARY_PRINTF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1961
1962
1963
1964
1965
1966
  /**
   * 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...
1967
  int vsscanf(const char *buf, const char *fmt, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1968
1969
1970
1971
1972
  {
  	const char *str = buf;
  	char *next;
  	char digit;
  	int num = 0;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1973
1974
1975
  	u8 qualifier;
  	u8 base;
  	s16 field_width;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1976
  	bool is_sign;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1977

7b9186f5e   André Goddard Rosa   vsprintf: give it...
1978
  	while (*fmt && *str) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1979
1980
1981
1982
1983
  		/* 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...
1984
1985
  			fmt = skip_spaces(++fmt);
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
  		}
  
  		/* 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...
1998

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1999
2000
2001
2002
  		/* skip this conversion.
  		 * advance both strings to next white space
  		 */
  		if (*fmt == '*') {
8fccae2c9   Andy Spencer   sscanf(): fix %*s%n
2003
  			while (!isspace(*fmt) && *fmt != '%' && *fmt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
  				fmt++;
  			while (!isspace(*str) && *str)
  				str++;
  			continue;
  		}
  
  		/* get field width */
  		field_width = -1;
  		if (isdigit(*fmt))
  			field_width = skip_atoi(&fmt);
  
  		/* get conversion qualifier */
  		qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
2017
2018
  		if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
  		    _tolower(*fmt) == 'z') {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
  			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
2030
2031
2032
  
  		if (!*fmt || !*str)
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2033
2034
  		base = 10;
  		is_sign = 0;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2035
  		switch (*fmt++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2036
2037
  		case 'c':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2038
  			char *s = (char *)va_arg(args, char*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
  			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...
2049
2050
  			char *s = (char *)va_arg(args, char *);
  			if (field_width == -1)
4be929be3   Alexey Dobriyan   kernel-wide: repl...
2051
  				field_width = SHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2052
  			/* first, skip leading white space in buffer */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
2053
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
2055
  
  			/* now copy until next white space */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2056
  			while (*str && !isspace(*str) && field_width--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2057
  				*s++ = *str++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2058
2059
2060
2061
2062
2063
2064
  			*s = '\0';
  			num++;
  		}
  		continue;
  		case 'n':
  			/* return number of characters read so far */
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2065
  			int *i = (int *)va_arg(args, int*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
  			*i = str - buf;
  		}
  		continue;
  		case 'o':
  			base = 8;
  			break;
  		case 'x':
  		case 'X':
  			base = 16;
  			break;
  		case 'i':
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2077
  			base = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2078
2079
2080
2081
2082
2083
  		case 'd':
  			is_sign = 1;
  		case 'u':
  			break;
  		case '%':
  			/* looking for '%' in str */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2084
  			if (*str++ != '%')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
  				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...
2095
  		str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2096
2097
2098
2099
2100
2101
  
  		digit = *str;
  		if (is_sign && digit == '-')
  			digit = *(str + 1);
  
  		if (!digit
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2102
2103
2104
2105
2106
  		    || (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
2107

7b9186f5e   André Goddard Rosa   vsprintf: give it...
2108
  		switch (qualifier) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109
2110
  		case 'H':	/* that's 'hh' in format */
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2111
2112
  				signed char *s = (signed char *)va_arg(args, signed char *);
  				*s = (signed char)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2114
2115
  				unsigned char *s = (unsigned char *)va_arg(args, unsigned char *);
  				*s = (unsigned char)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2116
2117
2118
2119
  			}
  			break;
  		case 'h':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2120
2121
  				short *s = (short *)va_arg(args, short *);
  				*s = (short)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2122
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2123
2124
  				unsigned short *s = (unsigned short *)va_arg(args, unsigned short *);
  				*s = (unsigned short)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2125
2126
2127
2128
  			}
  			break;
  		case 'l':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2129
2130
  				long *l = (long *)va_arg(args, long *);
  				*l = simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2131
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2132
2133
  				unsigned long *l = (unsigned long *)va_arg(args, unsigned long *);
  				*l = simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2134
2135
2136
2137
  			}
  			break;
  		case 'L':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2138
2139
  				long long *l = (long long *)va_arg(args, long long *);
  				*l = simple_strtoll(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2140
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2141
2142
  				unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *);
  				*l = simple_strtoull(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
2145
2146
2147
  			}
  			break;
  		case 'Z':
  		case 'z':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2148
2149
  			size_t *s = (size_t *)va_arg(args, size_t *);
  			*s = (size_t)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2150
2151
2152
2153
  		}
  		break;
  		default:
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2154
2155
  				int *i = (int *)va_arg(args, int *);
  				*i = (int)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2156
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2157
2158
  				unsigned int *i = (unsigned int *)va_arg(args, unsigned int*);
  				*i = (unsigned int)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2159
2160
2161
2162
2163
2164
2165
2166
2167
  			}
  			break;
  		}
  		num++;
  
  		if (!next)
  			break;
  		str = next;
  	}
c6b40d16d   Johannes Berg   fix sscanf %n mat...
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
  
  	/*
  	 * Now we've come all the way through so either the input string or the
  	 * format ended. In the former case, there can be a %n at the current
  	 * position in the format that needs to be filled.
  	 */
  	if (*fmt == '%' && *(fmt + 1) == 'n') {
  		int *p = (int *)va_arg(args, int *);
  		*p = str - buf;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2178
2179
  	return num;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2180
2181
2182
2183
2184
2185
2186
2187
  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...
2188
  int sscanf(const char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
2190
2191
  {
  	va_list args;
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2192
2193
  	va_start(args, fmt);
  	i = vsscanf(buf, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2194
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2195

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2196
2197
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2198
  EXPORT_SYMBOL(sscanf);