Blame view

lib/vsprintf.c 70.3 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>
0d1d7a558   Stephen Boyd   lib/vsprintf.c: I...
19
  #include <linux/clk.h>
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
20
  #include <linux/clk-provider.h>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
21
  #include <linux/module.h>	/* for KSYM_SYMBOL_LEN */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/ctype.h>
  #include <linux/kernel.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
26
  #include <linux/kallsyms.h>
53809751a   Jan Beulich   sscanf: don't ign...
27
  #include <linux/math64.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
28
  #include <linux/uaccess.h>
332d2e783   Linus Torvalds   Implement %pR to ...
29
  #include <linux/ioport.h>
4b6ccca70   Al Viro   add formats for d...
30
  #include <linux/dcache.h>
312b4e226   Ryan Mallon   vsprintf: check r...
31
  #include <linux/cred.h>
2b1b0d667   Andy Shevchenko   lib/uuid.c: intro...
32
  #include <linux/uuid.h>
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
33
  #include <linux/of.h>
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
34
  #include <net/addrconf.h>
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
35
36
37
  #ifdef CONFIG_BLOCK
  #include <linux/blkdev.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

edf14cdbf   Vlastimil Babka   mm, printk: intro...
39
  #include "../mm/internal.h"	/* For the trace_print_flags arrays */
4e57b6817   Tim Schmielau   [PATCH] fix missi...
40
  #include <asm/page.h>		/* for PAGE_SIZE */
deac93df2   James Bottomley   lib: Correct prin...
41
  #include <asm/sections.h>	/* for dereference_function_descriptor() */
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
42
  #include <asm/byteorder.h>	/* cpu_to_le16 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

71dca95d5   Andy Shevchenko   lib/vsprintf: add...
44
  #include <linux/string_helpers.h>
1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
45
  #include "kstrtox.h"
aa46a63ef   Harvey Harrison   lib: pull base-gu...
46

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
48
   * simple_strtoull - convert a string to an unsigned long long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
462e47110   Eldad Zack   simple_strto*: an...
52
53
   *
   * This function is obsolete. Please use kstrtoull instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
55
  unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  {
1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
57
58
  	unsigned long long result;
  	unsigned int rv;
aa46a63ef   Harvey Harrison   lib: pull base-gu...
59

1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
60
61
62
63
  	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...
64

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

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

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

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

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

43e5b666c   Rasmus Villemoes   lib/vsprintf.c: r...
125
  	do {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  		i = i*10 + *((*s)++) - '0';
43e5b666c   Rasmus Villemoes   lib/vsprintf.c: r...
127
  	} while (isdigit(**s));
7b9186f5e   André Goddard Rosa   vsprintf: give it...
128

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
  	return i;
  }
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  /*
   * 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 by emitting
   * two characters at a time, using a 200 byte lookup table. This
   * roughly halves the number of multiplications compared to computing
   * the digits one at a time. Implementation strongly inspired by the
   * previous version, which in turn used ideas described at
   * <http://www.cs.uiowa.edu/~jones/bcd/divide.html> (with permission
   * from the author, Douglas W. Jones).
   *
   * It turns out there is precisely one 26 bit fixed-point
   * approximation a of 64/100 for which x/100 == (x * (u64)a) >> 32
   * holds for all x in [0, 10^8-1], namely a = 0x28f5c29. The actual
   * range happens to be somewhat larger (x <= 1073741898), but that's
   * irrelevant for our purpose.
   *
   * For dividing a number in the range [10^4, 10^6-1] by 100, we still
   * need a 32x32->64 bit multiply, so we simply use the same constant.
   *
   * For dividing a number in the range [100, 10^4-1] by 100, there are
   * several options. The simplest is (x * 0x147b) >> 19, which is valid
   * for all x <= 43698.
133fd9f5c   Denys Vlasenko   vsprintf: further...
154
   */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
155

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  static const u16 decpair[100] = {
  #define _(x) (__force u16) cpu_to_le16(((x % 10) | ((x / 10) << 8)) + 0x3030)
  	_( 0), _( 1), _( 2), _( 3), _( 4), _( 5), _( 6), _( 7), _( 8), _( 9),
  	_(10), _(11), _(12), _(13), _(14), _(15), _(16), _(17), _(18), _(19),
  	_(20), _(21), _(22), _(23), _(24), _(25), _(26), _(27), _(28), _(29),
  	_(30), _(31), _(32), _(33), _(34), _(35), _(36), _(37), _(38), _(39),
  	_(40), _(41), _(42), _(43), _(44), _(45), _(46), _(47), _(48), _(49),
  	_(50), _(51), _(52), _(53), _(54), _(55), _(56), _(57), _(58), _(59),
  	_(60), _(61), _(62), _(63), _(64), _(65), _(66), _(67), _(68), _(69),
  	_(70), _(71), _(72), _(73), _(74), _(75), _(76), _(77), _(78), _(79),
  	_(80), _(81), _(82), _(83), _(84), _(85), _(86), _(87), _(88), _(89),
  	_(90), _(91), _(92), _(93), _(94), _(95), _(96), _(97), _(98), _(99),
  #undef _
  };
  
  /*
   * This will print a single '0' even if r == 0, since we would
675cf53c1   Rasmus Villemoes   lib/vsprintf.c: i...
173
174
175
   * immediately jump to out_r where two 0s would be written but only
   * one of them accounted for in buf. This is needed by ip4_string
   * below. All other callers pass a non-zero value of r.
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
176
  */
cf3b429b0   Joe Perches   vsprintf.c: use n...
177
  static noinline_for_stack
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
178
  char *put_dec_trunc8(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
179
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
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
206
207
208
209
210
211
212
213
  	unsigned q;
  
  	/* 1 <= r < 10^8 */
  	if (r < 100)
  		goto out_r;
  
  	/* 100 <= r < 10^8 */
  	q = (r * (u64)0x28f5c29) >> 32;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
  
  	/* 1 <= q < 10^6 */
  	if (q < 100)
  		goto out_q;
  
  	/*  100 <= q < 10^6 */
  	r = (q * (u64)0x28f5c29) >> 32;
  	*((u16 *)buf) = decpair[q - 100*r];
  	buf += 2;
  
  	/* 1 <= r < 10^4 */
  	if (r < 100)
  		goto out_r;
  
  	/* 100 <= r < 10^4 */
  	q = (r * 0x147b) >> 19;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
  out_q:
  	/* 1 <= q < 100 */
  	r = q;
  out_r:
  	/* 1 <= r < 100 */
  	*((u16 *)buf) = decpair[r];
675cf53c1   Rasmus Villemoes   lib/vsprintf.c: i...
214
  	buf += r < 10 ? 1 : 2;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
215
216
  	return buf;
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
217

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
218
  #if BITS_PER_LONG == 64 && BITS_PER_LONG_LONG == 64
cf3b429b0   Joe Perches   vsprintf.c: use n...
219
  static noinline_for_stack
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
220
  char *put_dec_full8(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
221
  {
133fd9f5c   Denys Vlasenko   vsprintf: further...
222
  	unsigned q;
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
223
224
225
226
  	/* 0 <= r < 10^8 */
  	q = (r * (u64)0x28f5c29) >> 32;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
227

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
228
229
230
231
  	/* 0 <= q < 10^6 */
  	r = (q * (u64)0x28f5c29) >> 32;
  	*((u16 *)buf) = decpair[q - 100*r];
  	buf += 2;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
232

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
233
234
235
236
  	/* 0 <= r < 10^4 */
  	q = (r * 0x147b) >> 19;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
133fd9f5c   Denys Vlasenko   vsprintf: further...
237

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
238
239
240
241
242
  	/* 0 <= q < 100 */
  	*((u16 *)buf) = decpair[q];
  	buf += 2;
  	return buf;
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
243

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
244
  static noinline_for_stack
133fd9f5c   Denys Vlasenko   vsprintf: further...
245
246
  char *put_dec(char *buf, unsigned long long n)
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
247
248
249
250
251
252
  	if (n >= 100*1000*1000)
  		buf = put_dec_full8(buf, do_div(n, 100*1000*1000));
  	/* 1 <= n <= 1.6e11 */
  	if (n >= 100*1000*1000)
  		buf = put_dec_full8(buf, do_div(n, 100*1000*1000));
  	/* 1 <= n < 1e8 */
133fd9f5c   Denys Vlasenko   vsprintf: further...
253
  	return put_dec_trunc8(buf, n);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
254
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
255

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
256
  #elif BITS_PER_LONG == 32 && BITS_PER_LONG_LONG == 64
133fd9f5c   Denys Vlasenko   vsprintf: further...
257

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
258
259
  static void
  put_dec_full4(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
260
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
261
262
263
264
265
266
267
268
  	unsigned q;
  
  	/* 0 <= r < 10^4 */
  	q = (r * 0x147b) >> 19;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
  	/* 0 <= q < 100 */
  	*((u16 *)buf) = decpair[q];
2359172a7   George Spelvin   lib: vsprintf: op...
269
270
271
272
273
274
275
  }
  
  /*
   * Call put_dec_full4 on x % 10000, return x / 10000.
   * The approximation x/10000 == (x * 0x346DC5D7) >> 43
   * holds for all x < 1,128,869,999.  The largest value this
   * helper will ever be asked to convert is 1,125,520,955.
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
276
   * (second call in the put_dec code, assuming n is all-ones).
2359172a7   George Spelvin   lib: vsprintf: op...
277
   */
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
278
  static noinline_for_stack
2359172a7   George Spelvin   lib: vsprintf: op...
279
280
281
282
283
284
  unsigned put_dec_helper4(char *buf, unsigned x)
  {
          uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43;
  
          put_dec_full4(buf, x - q * 10000);
          return q;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
285
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
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" */
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
303
304
  	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
  	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
133fd9f5c   Denys Vlasenko   vsprintf: further...
305
  	q   = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff);
2359172a7   George Spelvin   lib: vsprintf: op...
306
307
308
309
310
311
312
  	q = put_dec_helper4(buf, q);
  
  	q += 7671 * d3 + 9496 * d2 + 6 * d1;
  	q = put_dec_helper4(buf+4, q);
  
  	q += 4749 * d3 + 42 * d2;
  	q = put_dec_helper4(buf+8, q);
133fd9f5c   Denys Vlasenko   vsprintf: further...
313

2359172a7   George Spelvin   lib: vsprintf: op...
314
315
316
317
318
  	q += 281 * d3;
  	buf += 12;
  	if (q)
  		buf = put_dec_trunc8(buf, q);
  	else while (buf[-1] == '0')
133fd9f5c   Denys Vlasenko   vsprintf: further...
319
320
321
322
323
324
  		--buf;
  
  	return buf;
  }
  
  #endif
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
325
326
327
328
329
330
331
332
  /*
   * 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)
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
333
334
  	/* put_dec requires 2-byte alignment of the buffer. */
  	char tmp[sizeof(num) * 3] __aligned(2);
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
335
  	int idx, len;
133fd9f5c   Denys Vlasenko   vsprintf: further...
336
337
338
339
340
341
342
  	/* 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...
343
344
345
346
347
  
  	if (len > size)
  		return 0;
  	for (idx = 0; idx < len; ++idx)
  		buf[idx] = tmp[len - idx - 1];
133fd9f5c   Denys Vlasenko   vsprintf: further...
348
  	return len;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
349
  }
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
350
  #define SIGN	1		/* unsigned/signed, must be 1 */
d1c1b1213   Rasmus Villemoes   lib/vsprintf.c: a...
351
  #define LEFT	2		/* left justified */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  #define PLUS	4		/* show plus */
  #define SPACE	8		/* space if plus */
d1c1b1213   Rasmus Villemoes   lib/vsprintf.c: a...
354
  #define ZEROPAD	16		/* pad with zero, must be 16 == '0' - ' ' */
b89dc5d6b   Bjorn Helgaas   vsprintf: clarify...
355
356
  #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
357

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
358
359
  enum format_type {
  	FORMAT_TYPE_NONE, /* Just a string part */
ed681a91a   Vegard Nossum   vsprintf: unify t...
360
  	FORMAT_TYPE_WIDTH,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
361
362
363
364
365
366
367
368
369
  	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...
370
371
  	FORMAT_TYPE_UBYTE,
  	FORMAT_TYPE_BYTE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
372
373
374
375
  	FORMAT_TYPE_USHORT,
  	FORMAT_TYPE_SHORT,
  	FORMAT_TYPE_UINT,
  	FORMAT_TYPE_INT,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
376
377
378
379
380
  	FORMAT_TYPE_SIZE_T,
  	FORMAT_TYPE_PTRDIFF
  };
  
  struct printf_spec {
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
381
382
383
384
385
386
  	unsigned int	type:8;		/* format_type enum */
  	signed int	field_width:24;	/* width of output field */
  	unsigned int	flags:8;	/* flags to number() */
  	unsigned int	base:8;		/* number base, 8, 10 or 16 only */
  	signed int	precision:16;	/* # of digits/chars */
  } __packed;
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
387
388
  #define FIELD_WIDTH_MAX ((1 << 23) - 1)
  #define PRECISION_MAX ((1 << 15) - 1)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
389

cf3b429b0   Joe Perches   vsprintf.c: use n...
390
391
392
  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
393
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
394
395
  	/* put_dec requires 2-byte alignment of the buffer. */
  	char tmp[3 * sizeof(num)] __aligned(2);
9b706aee7   Denys Vlasenko   x86: trivial prin...
396
397
  	char sign;
  	char locase;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
398
  	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
  	int i;
7c2034223   Pierre Carrier   lib/vsprintf.c: "...
400
  	bool is_zero = num == 0LL;
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
401
402
  	int field_width = spec.field_width;
  	int precision = spec.precision;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  	return buf;
  }
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
511
512
513
514
515
516
517
518
519
520
521
522
523
  static noinline_for_stack
  char *special_hex_number(char *buf, char *end, unsigned long long num, int size)
  {
  	struct printf_spec spec;
  
  	spec.type = FORMAT_TYPE_PTR;
  	spec.field_width = 2 + 2 * size;	/* 0x + hex */
  	spec.flags = SPECIAL | SMALL | ZEROPAD;
  	spec.base = 16;
  	spec.precision = -1;
  
  	return number(buf, end, num, spec);
  }
cfccde04e   Rasmus Villemoes   lib/vsprintf.c: p...
524
  static void move_right(char *buf, char *end, unsigned len, unsigned spaces)
4b6ccca70   Al Viro   add formats for d...
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  {
  	size_t size;
  	if (buf >= end)	/* nowhere to put anything */
  		return;
  	size = end - buf;
  	if (size <= spaces) {
  		memset(buf, ' ', size);
  		return;
  	}
  	if (len) {
  		if (len > size - spaces)
  			len = size - spaces;
  		memmove(buf + spaces, buf, len);
  	}
  	memset(buf, ' ', spaces);
  }
cfccde04e   Rasmus Villemoes   lib/vsprintf.c: p...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  /*
   * Handle field width padding for a string.
   * @buf: current buffer position
   * @n: length of string
   * @end: end of output buffer
   * @spec: for field width and flags
   * Returns: new buffer position after padding.
   */
  static noinline_for_stack
  char *widen_string(char *buf, int n, char *end, struct printf_spec spec)
  {
  	unsigned spaces;
  
  	if (likely(n >= spec.field_width))
  		return buf;
  	/* we want to pad the sucker */
  	spaces = spec.field_width - n;
  	if (!(spec.flags & LEFT)) {
  		move_right(buf - n, end, n, spaces);
  		return buf + spaces;
  	}
  	while (spaces--) {
  		if (buf < end)
  			*buf = ' ';
  		++buf;
  	}
  	return buf;
  }
4b6ccca70   Al Viro   add formats for d...
569
  static noinline_for_stack
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
570
571
  char *string(char *buf, char *end, const char *s, struct printf_spec spec)
  {
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
572
573
  	int len = 0;
  	size_t lim = spec.precision;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
574
575
576
  
  	if ((unsigned long)s < PAGE_SIZE)
  		s = "(null)";
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
577
578
579
580
  	while (lim--) {
  		char c = *s++;
  		if (!c)
  			break;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
581
  		if (buf < end)
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
582
  			*buf = c;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
583
  		++buf;
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
584
  		++len;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
585
  	}
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
586
  	return widen_string(buf, len, end, spec);
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
587
588
589
  }
  
  static noinline_for_stack
4b6ccca70   Al Viro   add formats for d...
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
  char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec,
  		  const char *fmt)
  {
  	const char *array[4], *s;
  	const struct dentry *p;
  	int depth;
  	int i, n;
  
  	switch (fmt[1]) {
  		case '2': case '3': case '4':
  			depth = fmt[1] - '0';
  			break;
  		default:
  			depth = 1;
  	}
  
  	rcu_read_lock();
  	for (i = 0; i < depth; i++, d = p) {
  		p = ACCESS_ONCE(d->d_parent);
  		array[i] = ACCESS_ONCE(d->d_name.name);
  		if (p == d) {
  			if (i)
  				array[i] = "";
  			i++;
  			break;
  		}
  	}
  	s = array[--i];
  	for (n = 0; n != spec.precision; n++, buf++) {
  		char c = *s++;
  		if (!c) {
  			if (!i)
  				break;
  			c = '/';
  			s = array[--i];
  		}
  		if (buf < end)
  			*buf = c;
  	}
  	rcu_read_unlock();
cfccde04e   Rasmus Villemoes   lib/vsprintf.c: p...
630
  	return widen_string(buf, n, end, spec);
4b6ccca70   Al Viro   add formats for d...
631
  }
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  #ifdef CONFIG_BLOCK
  static noinline_for_stack
  char *bdev_name(char *buf, char *end, struct block_device *bdev,
  		struct printf_spec spec, const char *fmt)
  {
  	struct gendisk *hd = bdev->bd_disk;
  	
  	buf = string(buf, end, hd->disk_name, spec);
  	if (bdev->bd_part->partno) {
  		if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) {
  			if (buf < end)
  				*buf = 'p';
  			buf++;
  		}
  		buf = number(buf, end, bdev->bd_part->partno, spec);
  	}
  	return buf;
  }
  #endif
cf3b429b0   Joe Perches   vsprintf.c: use n...
651
652
  static noinline_for_stack
  char *symbol_string(char *buf, char *end, void *ptr,
b0d33c2bd   Joe Perches   vsprintf: Add ext...
653
  		    struct printf_spec spec, const char *fmt)
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
654
  {
b0d33c2bd   Joe Perches   vsprintf: Add ext...
655
  	unsigned long value;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
656
657
  #ifdef CONFIG_KALLSYMS
  	char sym[KSYM_SYMBOL_LEN];
b0d33c2bd   Joe Perches   vsprintf: Add ext...
658
659
660
661
662
663
664
665
  #endif
  
  	if (fmt[1] == 'R')
  		ptr = __builtin_extract_return_addr(ptr);
  	value = (unsigned long)ptr;
  
  #ifdef CONFIG_KALLSYMS
  	if (*fmt == 'B')
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
666
  		sprint_backtrace(sym, value);
b0d33c2bd   Joe Perches   vsprintf: Add ext...
667
  	else if (*fmt != 'f' && *fmt != 's')
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
668
669
  		sprint_symbol(sym, value);
  	else
4796dd200   Stephen Boyd   vsprintf: fix %ps...
670
  		sprint_symbol_no_offset(sym, value);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
671

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
672
  	return string(buf, end, sym, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
673
  #else
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
674
  	return special_hex_number(buf, end, value, sizeof(void *));
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
675
676
  #endif
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
677
678
679
  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 ...
680
681
  {
  #ifndef IO_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
682
  #define IO_RSRC_PRINTK_SIZE	6
332d2e783   Linus Torvalds   Implement %pR to ...
683
684
685
  #endif
  
  #ifndef MEM_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
686
  #define MEM_RSRC_PRINTK_SIZE	10
332d2e783   Linus Torvalds   Implement %pR to ...
687
  #endif
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
688
  	static const struct printf_spec io_spec = {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
689
  		.base = 16,
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
690
  		.field_width = IO_RSRC_PRINTK_SIZE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
691
692
693
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
694
695
696
697
698
699
  	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...
700
701
702
703
704
705
  	static const struct printf_spec bus_spec = {
  		.base = 16,
  		.field_width = 2,
  		.precision = -1,
  		.flags = SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
706
  	static const struct printf_spec dec_spec = {
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
707
708
709
710
  		.base = 10,
  		.precision = -1,
  		.flags = 0,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
711
  	static const struct printf_spec str_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
712
713
714
715
  		.field_width = -1,
  		.precision = 10,
  		.flags = LEFT,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
716
  	static const struct printf_spec flag_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
717
718
719
720
  		.base = 16,
  		.precision = -1,
  		.flags = SPECIAL | SMALL,
  	};
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
721
722
723
724
725
  
  	/* 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...
726
  #define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref window disabled]")
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
727
728
729
  #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 ...
730
  	char *p = sym, *pend = sym + sizeof(sym);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
731
  	int decode = (fmt[0] == 'R') ? 1 : 0;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
732
  	const struct printf_spec *specp;
332d2e783   Linus Torvalds   Implement %pR to ...
733
734
  
  	*p++ = '[';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
735
  	if (res->flags & IORESOURCE_IO) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
736
  		p = string(p, pend, "io  ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
737
738
  		specp = &io_spec;
  	} else if (res->flags & IORESOURCE_MEM) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
739
  		p = string(p, pend, "mem ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
740
741
  		specp = &mem_spec;
  	} else if (res->flags & IORESOURCE_IRQ) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
742
  		p = string(p, pend, "irq ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
743
744
  		specp = &dec_spec;
  	} else if (res->flags & IORESOURCE_DMA) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
745
  		p = string(p, pend, "dma ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
746
  		specp = &dec_spec;
0f4050c7d   Bjorn Helgaas   resource: add bus...
747
748
749
  	} else if (res->flags & IORESOURCE_BUS) {
  		p = string(p, pend, "bus ", str_spec);
  		specp = &bus_spec;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
750
  	} else {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
751
  		p = string(p, pend, "??? ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
752
  		specp = &mem_spec;
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
753
  		decode = 0;
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
754
  	}
d19cb803a   Bjorn Helgaas   vsprintf: Add sup...
755
756
757
758
759
760
761
762
763
  	if (decode && res->flags & IORESOURCE_UNSET) {
  		p = string(p, pend, "size ", str_spec);
  		p = number(p, pend, resource_size(res), *specp);
  	} else {
  		p = number(p, pend, res->start, *specp);
  		if (res->start != res->end) {
  			*p++ = '-';
  			p = number(p, pend, res->end, *specp);
  		}
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
764
  	}
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
765
  	if (decode) {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
766
767
768
769
  		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...
770
771
  		if (res->flags & IORESOURCE_WINDOW)
  			p = string(p, pend, " window", str_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
772
773
  		if (res->flags & IORESOURCE_DISABLED)
  			p = string(p, pend, " disabled", str_spec);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
774
775
776
  	} else {
  		p = string(p, pend, " flags ", str_spec);
  		p = number(p, pend, res->flags, flag_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
777
  	}
332d2e783   Linus Torvalds   Implement %pR to ...
778
  	*p++ = ']';
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
779
  	*p = '\0';
332d2e783   Linus Torvalds   Implement %pR to ...
780

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
781
  	return string(buf, end, sym, spec);
332d2e783   Linus Torvalds   Implement %pR to ...
782
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
783
  static noinline_for_stack
31550a16a   Andy Shevchenko   vsprintf: add sup...
784
785
786
  char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
  		 const char *fmt)
  {
360603a1b   Steven Rostedt   sprintf: hex_stri...
787
  	int i, len = 1;		/* if we pass '%ph[CDN]', field width remains
31550a16a   Andy Shevchenko   vsprintf: add sup...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
  				   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);
9c98f2359   Rasmus Villemoes   lib/vsprintf.c: f...
816
817
818
819
820
821
822
  	for (i = 0; i < len; ++i) {
  		if (buf < end)
  			*buf = hex_asc_hi(addr[i]);
  		++buf;
  		if (buf < end)
  			*buf = hex_asc_lo(addr[i]);
  		++buf;
31550a16a   Andy Shevchenko   vsprintf: add sup...
823

9c98f2359   Rasmus Villemoes   lib/vsprintf.c: f...
824
825
826
827
828
  		if (separator && i != len - 1) {
  			if (buf < end)
  				*buf = separator;
  			++buf;
  		}
31550a16a   Andy Shevchenko   vsprintf: add sup...
829
830
831
832
833
834
  	}
  
  	return buf;
  }
  
  static noinline_for_stack
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  char *bitmap_string(char *buf, char *end, unsigned long *bitmap,
  		    struct printf_spec spec, const char *fmt)
  {
  	const int CHUNKSZ = 32;
  	int nr_bits = max_t(int, spec.field_width, 0);
  	int i, chunksz;
  	bool first = true;
  
  	/* reused to print numbers */
  	spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 };
  
  	chunksz = nr_bits & (CHUNKSZ - 1);
  	if (chunksz == 0)
  		chunksz = CHUNKSZ;
  
  	i = ALIGN(nr_bits, CHUNKSZ) - CHUNKSZ;
  	for (; i >= 0; i -= CHUNKSZ) {
  		u32 chunkmask, val;
  		int word, bit;
  
  		chunkmask = ((1ULL << chunksz) - 1);
  		word = i / BITS_PER_LONG;
  		bit = i % BITS_PER_LONG;
  		val = (bitmap[word] >> bit) & chunkmask;
  
  		if (!first) {
  			if (buf < end)
  				*buf = ',';
  			buf++;
  		}
  		first = false;
  
  		spec.field_width = DIV_ROUND_UP(chunksz, 4);
  		buf = number(buf, end, val, spec);
  
  		chunksz = CHUNKSZ;
  	}
  	return buf;
  }
  
  static noinline_for_stack
  char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap,
  			 struct printf_spec spec, const char *fmt)
  {
  	int nr_bits = max_t(int, spec.field_width, 0);
  	/* current bit is 'cur', most recently seen range is [rbot, rtop] */
  	int cur, rbot, rtop;
  	bool first = true;
  
  	/* reused to print numbers */
  	spec = (struct printf_spec){ .base = 10 };
  
  	rbot = cur = find_first_bit(bitmap, nr_bits);
  	while (cur < nr_bits) {
  		rtop = cur;
  		cur = find_next_bit(bitmap, nr_bits, cur + 1);
  		if (cur < nr_bits && cur <= rtop + 1)
  			continue;
  
  		if (!first) {
  			if (buf < end)
  				*buf = ',';
  			buf++;
  		}
  		first = false;
  
  		buf = number(buf, end, rbot, spec);
  		if (rbot < rtop) {
  			if (buf < end)
  				*buf = '-';
  			buf++;
  
  			buf = number(buf, end, rtop, spec);
  		}
  
  		rbot = cur;
  	}
  	return buf;
  }
  
  static noinline_for_stack
cf3b429b0   Joe Perches   vsprintf.c: use n...
916
917
  char *mac_address_string(char *buf, char *end, u8 *addr,
  			 struct printf_spec spec, const char *fmt)
dd45c9cf6   Harvey Harrison   printk: add %pM f...
918
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
919
  	char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
dd45c9cf6   Harvey Harrison   printk: add %pM f...
920
921
  	char *p = mac_addr;
  	int i;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
922
  	char separator;
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
923
  	bool reversed = false;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
924

76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
925
926
  	switch (fmt[1]) {
  	case 'F':
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
927
  		separator = '-';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
928
929
930
931
932
933
934
  		break;
  
  	case 'R':
  		reversed = true;
  		/* fall through */
  
  	default:
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
935
  		separator = ':';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
936
  		break;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
937
  	}
dd45c9cf6   Harvey Harrison   printk: add %pM f...
938
939
  
  	for (i = 0; i < 6; i++) {
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
940
941
942
943
  		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...
944
  		if (fmt[0] == 'M' && i != 5)
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
945
  			*p++ = separator;
dd45c9cf6   Harvey Harrison   printk: add %pM f...
946
947
  	}
  	*p = '\0';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
948
  	return string(buf, end, mac_addr, spec);
dd45c9cf6   Harvey Harrison   printk: add %pM f...
949
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
950
951
  static noinline_for_stack
  char *ip4_string(char *p, const u8 *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
952
953
  {
  	int i;
0159f24ee   Joe Perches   lib/vsprintf.c: A...
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
  	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...
979
  	for (i = 0; i < 4; i++) {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
980
  		char temp[4] __aligned(2);	/* hold each IP quad in reverse order */
133fd9f5c   Denys Vlasenko   vsprintf: further...
981
  		int digits = put_dec_trunc8(temp, addr[index]) - temp;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
982
983
984
985
986
987
988
989
990
991
992
  		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...
993
  		index += step;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
994
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
995
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
996

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
997
998
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
999
1000
  static noinline_for_stack
  char *ip6_compressed_string(char *p, const char *addr)
689afa7da   Harvey Harrison   printk: add %p6 f...
1001
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1002
  	int i, j, range;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1003
1004
1005
1006
  	unsigned char zerolength[8];
  	int longest = 1;
  	int colonpos = -1;
  	u16 word;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1007
  	u8 hi, lo;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1008
  	bool needcolon = false;
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1009
1010
1011
1012
1013
1014
  	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...
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  
  	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...
1026
  			if (in6.s6_addr16[j] != 0)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  				break;
  			zerolength[i]++;
  		}
  	}
  	for (i = 0; i < range; i++) {
  		if (zerolength[i] > longest) {
  			longest = zerolength[i];
  			colonpos = i;
  		}
  	}
29cf519ee   Joe Perches   vsprintf: Update ...
1037
1038
  	if (longest == 1)		/* don't compress a single 0 */
  		colonpos = -1;
689afa7da   Harvey Harrison   printk: add %p6 f...
1039

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
  	/* 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...
1055
  		word = ntohs(in6.s6_addr16[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1056
1057
1058
1059
  		hi = word >> 8;
  		lo = word & 0xff;
  		if (hi) {
  			if (hi > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
1060
  				p = hex_byte_pack(p, hi);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1061
1062
  			else
  				*p++ = hex_asc_lo(hi);
55036ba76   Andy Shevchenko   lib: rename pack_...
1063
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1064
  		}
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
1065
  		else if (lo > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
1066
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1067
1068
1069
1070
1071
1072
1073
1074
  		else
  			*p++ = hex_asc_lo(lo);
  		needcolon = true;
  	}
  
  	if (useIPv4) {
  		if (needcolon)
  			*p++ = ':';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
1075
  		p = ip4_string(p, &in6.s6_addr[12], "I4");
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1076
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1077
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1078

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1079
1080
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1081
1082
  static noinline_for_stack
  char *ip6_string(char *p, const char *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1083
1084
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1085

689afa7da   Harvey Harrison   printk: add %p6 f...
1086
  	for (i = 0; i < 8; i++) {
55036ba76   Andy Shevchenko   lib: rename pack_...
1087
1088
  		p = hex_byte_pack(p, *addr++);
  		p = hex_byte_pack(p, *addr++);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1089
  		if (fmt[0] == 'I' && i != 7)
689afa7da   Harvey Harrison   printk: add %p6 f...
1090
1091
1092
  			*p++ = ':';
  	}
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1093

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1094
1095
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1096
1097
1098
  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...
1099
1100
1101
1102
  {
  	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...
1103
  		ip6_compressed_string(ip6_addr, addr);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1104
  	else
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1105
  		ip6_string(ip6_addr, addr, fmt);
689afa7da   Harvey Harrison   printk: add %p6 f...
1106

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1107
  	return string(buf, end, ip6_addr, spec);
689afa7da   Harvey Harrison   printk: add %p6 f...
1108
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1109
1110
1111
  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, ...
1112
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1113
  	char ip4_addr[sizeof("255.255.255.255")];
4aa996066   Harvey Harrison   printk: add %I4, ...
1114

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1117
  	return string(buf, end, ip4_addr, spec);
4aa996066   Harvey Harrison   printk: add %I4, ...
1118
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1119
  static noinline_for_stack
106796430   Daniel Borkmann   lib: vsprintf: ad...
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
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
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
  char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa,
  			 struct printf_spec spec, const char *fmt)
  {
  	bool have_p = false, have_s = false, have_f = false, have_c = false;
  	char ip6_addr[sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") +
  		      sizeof(":12345") + sizeof("/123456789") +
  		      sizeof("%1234567890")];
  	char *p = ip6_addr, *pend = ip6_addr + sizeof(ip6_addr);
  	const u8 *addr = (const u8 *) &sa->sin6_addr;
  	char fmt6[2] = { fmt[0], '6' };
  	u8 off = 0;
  
  	fmt++;
  	while (isalpha(*++fmt)) {
  		switch (*fmt) {
  		case 'p':
  			have_p = true;
  			break;
  		case 'f':
  			have_f = true;
  			break;
  		case 's':
  			have_s = true;
  			break;
  		case 'c':
  			have_c = true;
  			break;
  		}
  	}
  
  	if (have_p || have_s || have_f) {
  		*p = '[';
  		off = 1;
  	}
  
  	if (fmt6[0] == 'I' && have_c)
  		p = ip6_compressed_string(ip6_addr + off, addr);
  	else
  		p = ip6_string(ip6_addr + off, addr, fmt6);
  
  	if (have_p || have_s || have_f)
  		*p++ = ']';
  
  	if (have_p) {
  		*p++ = ':';
  		p = number(p, pend, ntohs(sa->sin6_port), spec);
  	}
  	if (have_f) {
  		*p++ = '/';
  		p = number(p, pend, ntohl(sa->sin6_flowinfo &
  					  IPV6_FLOWINFO_MASK), spec);
  	}
  	if (have_s) {
  		*p++ = '%';
  		p = number(p, pend, sa->sin6_scope_id, spec);
  	}
  	*p = '\0';
  
  	return string(buf, end, ip6_addr, spec);
  }
  
  static noinline_for_stack
  char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
  			 struct printf_spec spec, const char *fmt)
  {
  	bool have_p = false;
  	char *p, ip4_addr[sizeof("255.255.255.255") + sizeof(":12345")];
  	char *pend = ip4_addr + sizeof(ip4_addr);
  	const u8 *addr = (const u8 *) &sa->sin_addr.s_addr;
  	char fmt4[3] = { fmt[0], '4', 0 };
  
  	fmt++;
  	while (isalpha(*++fmt)) {
  		switch (*fmt) {
  		case 'p':
  			have_p = true;
  			break;
  		case 'h':
  		case 'l':
  		case 'n':
  		case 'b':
  			fmt4[2] = *fmt;
  			break;
  		}
  	}
  
  	p = ip4_string(ip4_addr, addr, fmt4);
  	if (have_p) {
  		*p++ = ':';
  		p = number(p, pend, ntohs(sa->sin_port), spec);
  	}
  	*p = '\0';
  
  	return string(buf, end, ip4_addr, spec);
  }
  
  static noinline_for_stack
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1217
1218
1219
1220
1221
1222
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
1264
  char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
  		     const char *fmt)
  {
  	bool found = true;
  	int count = 1;
  	unsigned int flags = 0;
  	int len;
  
  	if (spec.field_width == 0)
  		return buf;				/* nothing to print */
  
  	if (ZERO_OR_NULL_PTR(addr))
  		return string(buf, end, NULL, spec);	/* NULL pointer */
  
  
  	do {
  		switch (fmt[count++]) {
  		case 'a':
  			flags |= ESCAPE_ANY;
  			break;
  		case 'c':
  			flags |= ESCAPE_SPECIAL;
  			break;
  		case 'h':
  			flags |= ESCAPE_HEX;
  			break;
  		case 'n':
  			flags |= ESCAPE_NULL;
  			break;
  		case 'o':
  			flags |= ESCAPE_OCTAL;
  			break;
  		case 'p':
  			flags |= ESCAPE_NP;
  			break;
  		case 's':
  			flags |= ESCAPE_SPACE;
  			break;
  		default:
  			found = false;
  			break;
  		}
  	} while (found);
  
  	if (!flags)
  		flags = ESCAPE_ANY_NP;
  
  	len = spec.field_width < 0 ? 1 : spec.field_width;
41416f233   Rasmus Villemoes   lib/string_helper...
1265
1266
1267
1268
1269
1270
  	/*
  	 * string_escape_mem() writes as many characters as it can to
  	 * the given buffer, and returns the total size of the output
  	 * had the buffer been big enough.
  	 */
  	buf += string_escape_mem(addr, len, buf, buf < end ? end - buf : 0, flags, NULL);
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1271
1272
1273
1274
1275
  
  	return buf;
  }
  
  static noinline_for_stack
cf3b429b0   Joe Perches   vsprintf.c: use n...
1276
1277
  char *uuid_string(char *buf, char *end, const u8 *addr,
  		  struct printf_spec spec, const char *fmt)
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1278
  {
2b1b0d667   Andy Shevchenko   lib/uuid.c: intro...
1279
  	char uuid[UUID_STRING_LEN + 1];
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1280
1281
  	char *p = uuid;
  	int i;
f9727a17d   Christoph Hellwig   uuid: rename uuid...
1282
  	const u8 *index = uuid_index;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1283
1284
1285
1286
1287
1288
  	bool uc = false;
  
  	switch (*(++fmt)) {
  	case 'L':
  		uc = true;		/* fall-through */
  	case 'l':
f9727a17d   Christoph Hellwig   uuid: rename uuid...
1289
  		index = guid_index;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1290
1291
1292
1293
1294
1295
1296
  		break;
  	case 'B':
  		uc = true;
  		break;
  	}
  
  	for (i = 0; i < 16; i++) {
aa4ea1c3b   Andy Shevchenko   lib/vsprintf: sim...
1297
1298
1299
1300
  		if (uc)
  			p = hex_byte_pack_upper(p, addr[index[i]]);
  		else
  			p = hex_byte_pack(p, addr[index[i]]);
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
  		switch (i) {
  		case 3:
  		case 5:
  		case 7:
  		case 9:
  			*p++ = '-';
  			break;
  		}
  	}
  
  	*p = 0;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1312
1313
  	return string(buf, end, uuid, spec);
  }
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1314
1315
  static noinline_for_stack
  char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt)
c8f44affb   Michał Mirosław   net: introduce an...
1316
  {
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
  	unsigned long long num;
  	int size;
  
  	switch (fmt[1]) {
  	case 'F':
  		num = *(const netdev_features_t *)addr;
  		size = sizeof(netdev_features_t);
  		break;
  	default:
  		num = (unsigned long)addr;
  		size = sizeof(unsigned long);
  		break;
  	}
c8f44affb   Michał Mirosław   net: introduce an...
1330

3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1331
  	return special_hex_number(buf, end, num, size);
c8f44affb   Michał Mirosław   net: introduce an...
1332
  }
aaf07621b   Joe Perches   vsprintf: add %pa...
1333
  static noinline_for_stack
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1334
  char *address_val(char *buf, char *end, const void *addr, const char *fmt)
aaf07621b   Joe Perches   vsprintf: add %pa...
1335
1336
  {
  	unsigned long long num;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1337
  	int size;
aaf07621b   Joe Perches   vsprintf: add %pa...
1338
1339
1340
1341
  
  	switch (fmt[1]) {
  	case 'd':
  		num = *(const dma_addr_t *)addr;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1342
  		size = sizeof(dma_addr_t);
aaf07621b   Joe Perches   vsprintf: add %pa...
1343
1344
1345
1346
  		break;
  	case 'p':
  	default:
  		num = *(const phys_addr_t *)addr;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1347
  		size = sizeof(phys_addr_t);
aaf07621b   Joe Perches   vsprintf: add %pa...
1348
1349
  		break;
  	}
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1350
  	return special_hex_number(buf, end, num, size);
aaf07621b   Joe Perches   vsprintf: add %pa...
1351
  }
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1352
1353
1354
1355
1356
1357
1358
1359
  static noinline_for_stack
  char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
  	    const char *fmt)
  {
  	if (!IS_ENABLED(CONFIG_HAVE_CLK) || !clk)
  		return string(buf, end, NULL, spec);
  
  	switch (fmt[1]) {
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1360
1361
1362
1363
1364
  	case 'n':
  	default:
  #ifdef CONFIG_COMMON_CLK
  		return string(buf, end, __clk_get_name(clk), spec);
  #else
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1365
  		return special_hex_number(buf, end, (unsigned long)clk, sizeof(unsigned long));
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1366
1367
1368
  #endif
  	}
  }
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
  static
  char *format_flags(char *buf, char *end, unsigned long flags,
  					const struct trace_print_flags *names)
  {
  	unsigned long mask;
  	const struct printf_spec strspec = {
  		.field_width = -1,
  		.precision = -1,
  	};
  	const struct printf_spec numspec = {
  		.flags = SPECIAL|SMALL,
  		.field_width = -1,
  		.precision = -1,
  		.base = 16,
  	};
  
  	for ( ; flags && names->name; names++) {
  		mask = names->mask;
  		if ((flags & mask) != mask)
  			continue;
  
  		buf = string(buf, end, names->name, strspec);
  
  		flags &= ~mask;
  		if (flags) {
  			if (buf < end)
  				*buf = '|';
  			buf++;
  		}
  	}
  
  	if (flags)
  		buf = number(buf, end, flags, numspec);
  
  	return buf;
  }
  
  static noinline_for_stack
  char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
  {
  	unsigned long flags;
  	const struct trace_print_flags *names;
  
  	switch (fmt[1]) {
  	case 'p':
  		flags = *(unsigned long *)flags_ptr;
  		/* Remove zone id */
  		flags &= (1UL << NR_PAGEFLAGS) - 1;
  		names = pageflag_names;
  		break;
  	case 'v':
  		flags = *(unsigned long *)flags_ptr;
  		names = vmaflag_names;
  		break;
  	case 'g':
  		flags = *(gfp_t *)flags_ptr;
  		names = gfpflag_names;
  		break;
  	default:
  		WARN_ONCE(1, "Unsupported flags modifier: %c
  ", fmt[1]);
  		return buf;
  	}
  
  	return format_flags(buf, end, flags, names);
  }
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
  static const char *device_node_name_for_depth(const struct device_node *np, int depth)
  {
  	for ( ; np && depth; depth--)
  		np = np->parent;
  
  	return kbasename(np->full_name);
  }
  
  static noinline_for_stack
  char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)
  {
  	int depth;
  	const struct device_node *parent = np->parent;
  	static const struct printf_spec strspec = {
  		.field_width = -1,
  		.precision = -1,
  	};
  
  	/* special case for root node */
  	if (!parent)
  		return string(buf, end, "/", strspec);
  
  	for (depth = 0; parent->parent; depth++)
  		parent = parent->parent;
  
  	for ( ; depth >= 0; depth--) {
  		buf = string(buf, end, "/", strspec);
  		buf = string(buf, end, device_node_name_for_depth(np, depth),
  			     strspec);
  	}
  	return buf;
  }
  
  static noinline_for_stack
  char *device_node_string(char *buf, char *end, struct device_node *dn,
  			 struct printf_spec spec, const char *fmt)
  {
  	char tbuf[sizeof("xxxx") + 1];
  	const char *p;
  	int ret;
  	char *buf_start = buf;
  	struct property *prop;
  	bool has_mult, pass;
  	static const struct printf_spec num_spec = {
  		.flags = SMALL,
  		.field_width = -1,
  		.precision = -1,
  		.base = 10,
  	};
  
  	struct printf_spec str_spec = spec;
  	str_spec.field_width = -1;
  
  	if (!IS_ENABLED(CONFIG_OF))
  		return string(buf, end, "(!OF)", spec);
  
  	if ((unsigned long)dn < PAGE_SIZE)
  		return string(buf, end, "(null)", spec);
  
  	/* simple case without anything any more format specifiers */
  	fmt++;
  	if (fmt[0] == '\0' || strcspn(fmt,"fnpPFcC") > 0)
  		fmt = "f";
  
  	for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) {
  		if (pass) {
  			if (buf < end)
  				*buf = ':';
  			buf++;
  		}
  
  		switch (*fmt) {
  		case 'f':	/* full_name */
  			buf = device_node_gen_full_name(dn, buf, end);
  			break;
  		case 'n':	/* name */
  			buf = string(buf, end, dn->name, str_spec);
  			break;
  		case 'p':	/* phandle */
  			buf = number(buf, end, (unsigned int)dn->phandle, num_spec);
  			break;
  		case 'P':	/* path-spec */
  			p = kbasename(of_node_full_name(dn));
  			if (!p[1])
  				p = "/";
  			buf = string(buf, end, p, str_spec);
  			break;
  		case 'F':	/* flags */
  			tbuf[0] = of_node_check_flag(dn, OF_DYNAMIC) ? 'D' : '-';
  			tbuf[1] = of_node_check_flag(dn, OF_DETACHED) ? 'd' : '-';
  			tbuf[2] = of_node_check_flag(dn, OF_POPULATED) ? 'P' : '-';
  			tbuf[3] = of_node_check_flag(dn, OF_POPULATED_BUS) ? 'B' : '-';
  			tbuf[4] = 0;
  			buf = string(buf, end, tbuf, str_spec);
  			break;
  		case 'c':	/* major compatible string */
  			ret = of_property_read_string(dn, "compatible", &p);
  			if (!ret)
  				buf = string(buf, end, p, str_spec);
  			break;
  		case 'C':	/* full compatible string */
  			has_mult = false;
  			of_property_for_each_string(dn, "compatible", prop, p) {
  				if (has_mult)
  					buf = string(buf, end, ",", str_spec);
  				buf = string(buf, end, "\"", str_spec);
  				buf = string(buf, end, p, str_spec);
  				buf = string(buf, end, "\"", str_spec);
  
  				has_mult = true;
  			}
  			break;
  		default:
  			break;
  		}
  	}
  
  	return widen_string(buf, buf - buf_start, end, spec);
  }
411f05f12   Ingo Molnar   vsprintf: Turn kp...
1554
  int kptr_restrict __read_mostly;
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1555

4d8a743cd   Linus Torvalds   vsprintf: add inf...
1556
1557
1558
1559
1560
  /*
   * 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.
   *
0b523769e   Joe Perches   checkpatch: add a...
1561
1562
1563
   * Please update scripts/checkpatch.pl when adding/removing conversion
   * characters.  (Search for "check for vsprintf extension").
   *
332d2e783   Linus Torvalds   Implement %pR to ...
1564
1565
   * Right now we handle:
   *
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1566
1567
   * - 'F' For symbolic function descriptor pointers with offset
   * - 'f' For simple symbolic function names without offset
0efb4d207   Steven Rostedt   vsnprintf: remove...
1568
1569
   * - 'S' For symbolic direct pointers with offset
   * - 's' For symbolic direct pointers without offset
b0d33c2bd   Joe Perches   vsprintf: Add ext...
1570
   * - '[FfSs]R' as above with __builtin_extract_return_addr() translation
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
1571
   * - 'B' For backtraced symbolic direct pointers with offset
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1572
1573
   * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
   * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
1574
1575
1576
1577
   * - 'b[l]' For a bitmap, the number of bits is determined by the field
   *       width which must be explicitly specified either as part of the
   *       format string '%32b[l]' or through '%*b[l]', [l] selects
   *       range-list format instead of hex format
dd45c9cf6   Harvey Harrison   printk: add %pM f...
1578
1579
   * - '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...
1580
   * - 'm' For a 6-byte MAC address, it prints the hex address without colons
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1581
   * - 'MF' For a 6-byte MAC FDDI address, it prints the address
c8e000604   Joe Perches   lib: Kill bit-rev...
1582
   *       with a dash-separated hex notation
7c59154e7   Andy Shevchenko   lib/vsprintf: upd...
1583
   * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1584
1585
1586
   * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
   *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
   *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
106796430   Daniel Borkmann   lib: vsprintf: ad...
1587
1588
1589
   *       [S][pfs]
   *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
   *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1590
1591
1592
   * - 'i' [46] for 'raw' IPv4/IPv6 addresses
   *       IPv6 omits the colons (01020304...0f)
   *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
106796430   Daniel Borkmann   lib: vsprintf: ad...
1593
1594
1595
1596
1597
   *       [S][pfs]
   *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
   *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
   * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
   * - 'I[6S]c' for IPv6 addresses printed as specified by
29cf519ee   Joe Perches   vsprintf: Update ...
1598
   *       http://tools.ietf.org/html/rfc5952
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
   * - 'E[achnops]' For an escaped buffer, where rules are defined by combination
   *                of the following flags (see string_escape_mem() for the
   *                details):
   *                  a - ESCAPE_ANY
   *                  c - ESCAPE_SPECIAL
   *                  h - ESCAPE_HEX
   *                  n - ESCAPE_NULL
   *                  o - ESCAPE_OCTAL
   *                  p - ESCAPE_NP
   *                  s - ESCAPE_SPACE
   *                By default ESCAPE_ANY_NP is used.
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
   * - '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...
1621
1622
1623
1624
1625
   * - '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...
1626
   * - 'K' For a kernel pointer that should be hidden from unprivileged users
c8f44affb   Michał Mirosław   net: introduce an...
1627
   * - 'NF' For a netdev_features_t
31550a16a   Andy Shevchenko   vsprintf: add sup...
1628
1629
1630
1631
1632
1633
1634
   * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
   *            a certain separator (' ' by default):
   *              C colon
   *              D dash
   *              N no separator
   *            The maximum supported length is 64 bytes of the input. Consider
   *            to use print_hex_dump() for the larger input.
aaf07621b   Joe Perches   vsprintf: add %pa...
1635
1636
   * - 'a[pd]' For address types [p] phys_addr_t, [d] dma_addr_t and derivatives
   *           (default assumed to be phys_addr_t, passed by reference)
c0d92a57a   Olof Johansson   lib/vsprintf.c: d...
1637
1638
   * - 'd[234]' For a dentry name (optionally 2-4 last components)
   * - 'D[234]' Same as 'd' but for a struct file
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
1639
   * - 'g' For block_device name (gendisk + partition number)
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1640
1641
1642
1643
1644
   * - 'C' For a clock, it prints the name (Common Clock Framework) or address
   *       (legacy clock framework) of the clock
   * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
   *        (legacy clock framework) of the clock
   * - 'Cr' For a clock, it prints the current rate of the clock
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1645
1646
1647
1648
1649
   * - 'G' For flags to be printed as a collection of symbolic strings that would
   *       construct the specific value. Supported flags given by option:
   *       p page flags (see struct page) given as pointer to unsigned long
   *       g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
   *       v vma flags (VM_*) given as pointer to unsigned long
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
   * - 'O' For a kobject based struct. Must be one of the following:
   *       - 'OF[fnpPcCF]'  For a device tree object
   *                        Without any optional arguments prints the full_name
   *                        f device node full_name
   *                        n device node name
   *                        p device node phandle
   *                        P device node path spec (name + @unit)
   *                        F device node flags
   *                        c major compatible string
   *                        C full compatible string
5e4ee7b13   Martin Kletzander   printk: synchroni...
1660
1661
   *
   * ** Please update also Documentation/printk-formats.txt when making changes **
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1662
   *
332d2e783   Linus Torvalds   Implement %pR to ...
1663
1664
1665
   * 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...
1666
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
1667
1668
1669
  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...
1670
  {
80c9eb46f   Rasmus Villemoes   lib/vsprintf.c: r...
1671
  	const int default_width = 2 * sizeof(void *);
725fe002d   Grant Likely   vsprintf: correct...
1672

9f36e2c44   Kees Cook   printk: use %pK f...
1673
  	if (!ptr && *fmt != 'K') {
5e0579812   Joe Perches   vsprintf.c: use d...
1674
1675
1676
1677
1678
  		/*
  		 * 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...
1679
  			spec.field_width = default_width;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1680
  		return string(buf, end, "(null)", spec);
5e0579812   Joe Perches   vsprintf.c: use d...
1681
  	}
d97106ab5   Linus Torvalds   Make %p print '(n...
1682

0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1683
1684
  	switch (*fmt) {
  	case 'F':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1685
  	case 'f':
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1686
1687
1688
  		ptr = dereference_function_descriptor(ptr);
  		/* Fallthrough */
  	case 'S':
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1689
  	case 's':
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
1690
  	case 'B':
b0d33c2bd   Joe Perches   vsprintf: Add ext...
1691
  		return symbol_string(buf, end, ptr, spec, fmt);
332d2e783   Linus Torvalds   Implement %pR to ...
1692
  	case 'R':
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1693
  	case 'r':
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1694
  		return resource_string(buf, end, ptr, spec, fmt);
31550a16a   Andy Shevchenko   vsprintf: add sup...
1695
1696
  	case 'h':
  		return hex_string(buf, end, ptr, spec, fmt);
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
1697
1698
1699
1700
1701
1702
1703
  	case 'b':
  		switch (fmt[1]) {
  		case 'l':
  			return bitmap_list_string(buf, end, ptr, spec, fmt);
  		default:
  			return bitmap_string(buf, end, ptr, spec, fmt);
  		}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1704
1705
  	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
  	case 'm':			/* Contiguous: 000102030405 */
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1706
1707
  					/* [mM]F (FDDI) */
  					/* [mM]R (Reverse order; Bluetooth) */
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
  		return mac_address_string(buf, end, ptr, spec, fmt);
  	case 'I':			/* Formatted IP supported
  					 * 4:	1.2.3.4
  					 * 6:	0001:0203:...:0708
  					 * 6c:	1::708 or 1::1.2.3.4
  					 */
  	case 'i':			/* Contiguous:
  					 * 4:	001.002.003.004
  					 * 6:   000102...0f
  					 */
  		switch (fmt[1]) {
  		case '6':
  			return ip6_addr_string(buf, end, ptr, spec, fmt);
  		case '4':
  			return ip4_addr_string(buf, end, ptr, spec, fmt);
106796430   Daniel Borkmann   lib: vsprintf: ad...
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
  		case 'S': {
  			const union {
  				struct sockaddr		raw;
  				struct sockaddr_in	v4;
  				struct sockaddr_in6	v6;
  			} *sa = ptr;
  
  			switch (sa->raw.sa_family) {
  			case AF_INET:
  				return ip4_addr_string_sa(buf, end, &sa->v4, spec, fmt);
  			case AF_INET6:
  				return ip6_addr_string_sa(buf, end, &sa->v6, spec, fmt);
  			default:
  				return string(buf, end, "(invalid address)", spec);
  			}}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1738
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1739
  		break;
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1740
1741
  	case 'E':
  		return escaped_string(buf, end, ptr, spec, fmt);
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1742
1743
  	case 'U':
  		return uuid_string(buf, end, ptr, spec, fmt);
7db6f5fb6   Joe Perches   vsprintf: Recursi...
1744
  	case 'V':
5756b76e4   Jan Beulich   vsprintf: make %p...
1745
1746
1747
1748
1749
1750
1751
1752
1753
  		{
  			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...
1754
  	case 'K':
312b4e226   Ryan Mallon   vsprintf: check r...
1755
1756
1757
1758
1759
  		switch (kptr_restrict) {
  		case 0:
  			/* Always print %pK values */
  			break;
  		case 1: {
7eb391299   Jason A. Donenfeld   vsprintf: kptr_re...
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
  			const struct cred *cred;
  
  			/*
  			 * kptr_restrict==1 cannot be used in IRQ context
  			 * because its test for CAP_SYSLOG would be meaningless.
  			 */
  			if (in_irq() || in_serving_softirq() || in_nmi()) {
  				if (spec.field_width == -1)
  					spec.field_width = default_width;
  				return string(buf, end, "pK-error", spec);
  			}
312b4e226   Ryan Mallon   vsprintf: check r...
1771
1772
1773
1774
1775
1776
1777
1778
1779
  			/*
  			 * Only print the real pointer value if the current
  			 * process has CAP_SYSLOG and is running with the
  			 * same credentials it started with. This is because
  			 * access to files is checked at open() time, but %pK
  			 * checks permission at read() time. We don't want to
  			 * leak pointer values if a binary opens a file using
  			 * %pK and then elevates privileges before reading it.
  			 */
7eb391299   Jason A. Donenfeld   vsprintf: kptr_re...
1780
  			cred = current_cred();
312b4e226   Ryan Mallon   vsprintf: check r...
1781
1782
1783
1784
1785
1786
1787
1788
1789
  			if (!has_capability_noaudit(current, CAP_SYSLOG) ||
  			    !uid_eq(cred->euid, cred->uid) ||
  			    !gid_eq(cred->egid, cred->gid))
  				ptr = NULL;
  			break;
  		}
  		case 2:
  		default:
  			/* Always print 0's for %pK */
26297607e   Joe Perches   vsprintf: neaten ...
1790
  			ptr = NULL;
312b4e226   Ryan Mallon   vsprintf: check r...
1791
1792
  			break;
  		}
26297607e   Joe Perches   vsprintf: neaten ...
1793
  		break;
312b4e226   Ryan Mallon   vsprintf: check r...
1794

c8f44affb   Michał Mirosław   net: introduce an...
1795
  	case 'N':
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1796
  		return netdev_bits(buf, end, ptr, fmt);
7d7992108   Stepan Moskovchenko   lib/vsprintf.c: a...
1797
  	case 'a':
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1798
  		return address_val(buf, end, ptr, fmt);
4b6ccca70   Al Viro   add formats for d...
1799
1800
  	case 'd':
  		return dentry_name(buf, end, ptr, spec, fmt);
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1801
1802
  	case 'C':
  		return clock(buf, end, ptr, spec, fmt);
4b6ccca70   Al Viro   add formats for d...
1803
1804
1805
1806
  	case 'D':
  		return dentry_name(buf, end,
  				   ((const struct file *)ptr)->f_path.dentry,
  				   spec, fmt);
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
1807
1808
1809
1810
  #ifdef CONFIG_BLOCK
  	case 'g':
  		return bdev_name(buf, end, ptr, spec, fmt);
  #endif
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1811
1812
  	case 'G':
  		return flags_string(buf, end, ptr, fmt);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1813
1814
1815
1816
1817
  	case 'O':
  		switch (fmt[1]) {
  		case 'F':
  			return device_node_string(buf, end, ptr, spec, fmt + 1);
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1818
1819
1820
  	}
  	spec.flags |= SMALL;
  	if (spec.field_width == -1) {
725fe002d   Grant Likely   vsprintf: correct...
1821
  		spec.field_width = default_width;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
  		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
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
1839
   * 'Z' changed to 'z' --adobriyan 2017-01-25
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
   * '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...
1850
1851
  static noinline_for_stack
  int format_decode(const char *fmt, struct printf_spec *spec)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1852
1853
  {
  	const char *start = fmt;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1854
  	char qualifier;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1855
1856
  
  	/* we finished early by reading the field width */
ed681a91a   Vegard Nossum   vsprintf: unify t...
1857
  	if (spec->type == FORMAT_TYPE_WIDTH) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
  		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...
1915
  		spec->type = FORMAT_TYPE_WIDTH;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
  		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...
1930
  			spec->type = FORMAT_TYPE_PRECISION;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1931
1932
1933
1934
1935
1936
  			return ++fmt - start;
  		}
  	}
  
  qualifier:
  	/* get the conversion qualifier */
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1937
  	qualifier = 0;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1938
  	if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
1939
  	    *fmt == 'z' || *fmt == 't') {
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1940
1941
1942
1943
  		qualifier = *fmt++;
  		if (unlikely(qualifier == *fmt)) {
  			if (qualifier == 'l') {
  				qualifier = 'L';
a4e94ef0d   Zhaolei   printk: add suppo...
1944
  				++fmt;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1945
1946
  			} else if (qualifier == 'h') {
  				qualifier = 'H';
a4e94ef0d   Zhaolei   printk: add suppo...
1947
1948
  				++fmt;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
  		}
  	}
  
  	/* 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;
ffbfed03b   Rasmus Villemoes   lib/vsprintf.c: c...
1965
  		return ++fmt - start;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1966

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
  	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...
1985
  		spec->flags |= SIGN;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1986
  	case 'u':
4aa996066   Harvey Harrison   printk: add %I4, ...
1987
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1988

708d96fd0   Ryan Mallon   vsprintf: remove ...
1989
1990
  	case 'n':
  		/*
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
1991
1992
1993
  		 * Since %n poses a greater security risk than
  		 * utility, treat it as any other invalid or
  		 * unsupported format specifier.
708d96fd0   Ryan Mallon   vsprintf: remove ...
1994
  		 */
708d96fd0   Ryan Mallon   vsprintf: remove ...
1995
  		/* Fall-through */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1996
  	default:
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
1997
1998
  		WARN_ONCE(1, "Please remove unsupported %%%c in format string
  ", *fmt);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1999
2000
  		spec->type = FORMAT_TYPE_INVALID;
  		return fmt - start;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
2001
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2002

d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2003
  	if (qualifier == 'L')
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2004
  		spec->type = FORMAT_TYPE_LONG_LONG;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2005
  	else if (qualifier == 'l') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
2006
2007
  		BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG);
  		spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN);
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
2008
  	} else if (qualifier == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2009
  		spec->type = FORMAT_TYPE_SIZE_T;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2010
  	} else if (qualifier == 't') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2011
  		spec->type = FORMAT_TYPE_PTRDIFF;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2012
  	} else if (qualifier == 'H') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
2013
2014
  		BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE);
  		spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN);
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2015
  	} else if (qualifier == 'h') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
2016
2017
  		BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT);
  		spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2018
  	} else {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
2019
2020
  		BUILD_BUG_ON(FORMAT_TYPE_UINT + SIGN != FORMAT_TYPE_INT);
  		spec->type = FORMAT_TYPE_UINT + (spec->flags & SIGN);
78a8bf69b   Linus Torvalds   vsprintf: split o...
2021
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2022
2023
  
  	return ++fmt - start;
78a8bf69b   Linus Torvalds   vsprintf: split o...
2024
  }
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
  static void
  set_field_width(struct printf_spec *spec, int width)
  {
  	spec->field_width = width;
  	if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) {
  		spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
  	}
  }
  
  static void
  set_precision(struct printf_spec *spec, int prec)
  {
  	spec->precision = prec;
  	if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) {
  		spec->precision = clamp(prec, 0, PRECISION_MAX);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2042
2043
2044
2045
2046
2047
2048
  /**
   * 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
   *
d7ec9a05d   Rasmus Villemoes   lib/vsprintf.c: u...
2049
2050
2051
   * This function generally follows C99 vsnprintf, but has some
   * extensions and a few limitations:
   *
6cc89134c   mchehab@s-opensource.com   kernel-api.rst: f...
2052
2053
   *  - ``%n`` is unsupported
   *  - ``%p*`` is handled by pointer()
5e4ee7b13   Martin Kletzander   printk: synchroni...
2054
2055
2056
   *
   * See pointer() or Documentation/printk-formats.txt for more
   * extensive description.
20036fdca   Andi Kleen   Add kerneldoc doc...
2057
   *
6cc89134c   mchehab@s-opensource.com   kernel-api.rst: f...
2058
   * **Please update the documentation in both places when making changes**
80f548e04   Andrew Morton   lib/vsprintf.c: r...
2059
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2060
2061
2062
2063
   * 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 ...
2064
   * (not including the trailing '\0'), use vscnprintf(). If the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2065
2066
2067
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
2068
   * If you're not already dealing with a va_list consider using snprintf().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
2070
2071
   */
  int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2072
  	unsigned long long num;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2073
  	char *str, *end;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2074
  	struct printf_spec spec = {0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2076
2077
  	/* Reject out-of-range values early.  Large positive sizes are
  	   used for unknown buffer sizes. */
2aa2f9e21   Rasmus Villemoes   lib/vsprintf.c: i...
2078
  	if (WARN_ON_ONCE(size > INT_MAX))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2079
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2080
2081
  
  	str = buf;
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2082
  	end = buf + size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2083

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2084
2085
2086
2087
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2088
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2089
2090
  	while (*fmt) {
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2091
  		int read = format_decode(fmt, &spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2095
2096
2097
2098
2099
2100
2101
  		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
2102
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2103
2104
  			str += read;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
2106
  		case FORMAT_TYPE_WIDTH:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2107
  			set_field_width(&spec, va_arg(args, int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2108
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2110
  		case FORMAT_TYPE_PRECISION:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2111
  			set_precision(&spec, va_arg(args, int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2112
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113

d4be151b2   André Goddard Rosa   vsprintf: move lo...
2114
2115
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2116
2117
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2118
  					if (str < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2119
2120
  						*str = ' ';
  					++str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2121

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2122
2123
2124
2125
2126
2127
2128
  				}
  			}
  			c = (unsigned char) va_arg(args, int);
  			if (str < end)
  				*str = c;
  			++str;
  			while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2129
  				if (str < end)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2130
  					*str = ' ';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2131
  				++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2132
2133
  			}
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2134
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2135

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2140
  		case FORMAT_TYPE_PTR:
ffbfed03b   Rasmus Villemoes   lib/vsprintf.c: c...
2141
  			str = pointer(fmt, str, end, va_arg(args, void *),
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2142
2143
2144
2145
  				      spec);
  			while (isalnum(*fmt))
  				fmt++;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2146

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2147
2148
2149
2150
2151
  		case FORMAT_TYPE_PERCENT_CHAR:
  			if (str < end)
  				*str = '%';
  			++str;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2153
  		case FORMAT_TYPE_INVALID:
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2154
2155
2156
2157
2158
2159
2160
2161
2162
  			/*
  			 * Presumably the arguments passed gcc's type
  			 * checking, but there is no safe or sane way
  			 * for us to continue parsing the format and
  			 * fetching from the va_list; the remaining
  			 * specifiers and arguments would be out of
  			 * sync.
  			 */
  			goto out;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2163

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
  		default:
  			switch (spec.type) {
  			case FORMAT_TYPE_LONG_LONG:
  				num = va_arg(args, long long);
  				break;
  			case FORMAT_TYPE_ULONG:
  				num = va_arg(args, unsigned long);
  				break;
  			case FORMAT_TYPE_LONG:
  				num = va_arg(args, long);
  				break;
  			case FORMAT_TYPE_SIZE_T:
ef1249602   Jason Gunthorpe   lib/vsprintf.c: f...
2176
2177
2178
2179
  				if (spec.flags & SIGN)
  					num = va_arg(args, ssize_t);
  				else
  					num = va_arg(args, size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2180
2181
2182
2183
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = va_arg(args, ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
2184
2185
2186
2187
2188
2189
  			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...
2190
2191
2192
2193
2194
2195
  			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...
2196
2197
  			case FORMAT_TYPE_INT:
  				num = (int) va_arg(args, int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2198
2199
2200
2201
2202
2203
  				break;
  			default:
  				num = va_arg(args, unsigned int);
  			}
  
  			str = number(str, end, num, spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2204
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2205
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2206

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2207
  out:
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2208
2209
2210
2211
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
0a6047eef   Linus Torvalds   Fix vsnprintf off...
2212
  			end[-1] = '\0';
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2213
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2214

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2218
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
  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...
2229
   * the @buf not including the trailing '\0'. If @size is == 0 the function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2230
2231
   * returns 0.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
2232
   * If you're not already dealing with a va_list consider using scnprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
2233
2234
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2235
2236
2237
2238
   */
  int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2239
  	i = vsnprintf(buf, size, fmt, args);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2240
2241
2242
2243
2244
  	if (likely(i < size))
  		return i;
  	if (size != 0)
  		return size - 1;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2245
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
  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...
2259
2260
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2261
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2262
  int snprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2263
2264
2265
2266
2267
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2268
  	i = vsnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2269
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2270

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2271
2272
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
  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...
2283
   * the trailing '\0'. If @size is == 0 the function returns 0.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2285
  int scnprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2286
2287
2288
2289
2290
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2291
  	i = vscnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2292
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2293

b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2294
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
  }
  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 ...
2305
   * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2306
2307
   * buffer overflows.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
2308
   * If you're not already dealing with a va_list consider using sprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
2309
2310
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311
2312
2313
2314
2315
   */
  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
2316
2317
2318
2319
2320
2321
2322
2323
2324
  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 ...
2325
   * into @buf. Use snprintf() or scnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
   * buffer overflows.
20036fdca   Andi Kleen   Add kerneldoc doc...
2327
2328
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2329
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2330
  int sprintf(char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2331
2332
2333
2334
2335
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2336
  	i = vsnprintf(buf, INT_MAX, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2337
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2338

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2339
2340
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2341
  EXPORT_SYMBOL(sprintf);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
  #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
da3dae54e   Masanari Iida   Documentation: Do...
2357
   * is skipped.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
   *
   * 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...
2368
  	struct printf_spec spec = {0};
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2369
  	char *str, *end;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
  
  	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...
2393
  	while (*fmt) {
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2394
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2395

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2398
2399
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE:
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2400
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2401
  			break;
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2402
2403
  		case FORMAT_TYPE_INVALID:
  			goto out;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2404

ed681a91a   Vegard Nossum   vsprintf: unify t...
2405
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2406
2407
2408
2409
2410
  		case FORMAT_TYPE_PRECISION:
  			save_arg(int);
  			break;
  
  		case FORMAT_TYPE_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2411
  			save_arg(char);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2412
2413
2414
  			break;
  
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2415
2416
  			const char *save_str = va_arg(args, char *);
  			size_t len;
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
2417

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2418
2419
  			if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
  					|| (unsigned long)save_str < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
2420
  				save_str = "(null)";
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
2421
2422
2423
2424
  			len = strlen(save_str) + 1;
  			if (str + len < end)
  				memcpy(str, save_str, len);
  			str += len;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2425
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2426
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2427
2428
  
  		case FORMAT_TYPE_PTR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2429
2430
  			save_arg(void *);
  			/* skip all alphanumeric pointer suffixes */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2431
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2432
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2433
  			break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2434
2435
2436
2437
  		default:
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2438
  				save_arg(long long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2439
2440
2441
  				break;
  			case FORMAT_TYPE_ULONG:
  			case FORMAT_TYPE_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2442
  				save_arg(unsigned long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2443
2444
  				break;
  			case FORMAT_TYPE_SIZE_T:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2445
  				save_arg(size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2446
2447
  				break;
  			case FORMAT_TYPE_PTRDIFF:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2448
  				save_arg(ptrdiff_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2449
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
2450
2451
2452
2453
  			case FORMAT_TYPE_UBYTE:
  			case FORMAT_TYPE_BYTE:
  				save_arg(char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2454
2455
  			case FORMAT_TYPE_USHORT:
  			case FORMAT_TYPE_SHORT:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2456
  				save_arg(short);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2457
2458
  				break;
  			default:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2459
  				save_arg(int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2460
  			}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2461
2462
  		}
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2463

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2464
  out:
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2465
  	return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2466
  #undef save_arg
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
  }
  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...
2482
   *  see vsnprintf comment for details.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
   *
   * 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...
2494
  	struct printf_spec spec = {0};
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2495
2496
  	char *str, *end;
  	const char *args = (const char *)bin_buf;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2497

762abb515   Rasmus Villemoes   lib/vsprintf.c: a...
2498
  	if (WARN_ON_ONCE(size > INT_MAX))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2499
  		return 0;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
  
  	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...
2524
  	while (*fmt) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2525
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2526
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2527

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2530
2531
2532
2533
2534
2535
2536
  		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...
2537
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2538
2539
  			str += read;
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2540
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
2541
  		case FORMAT_TYPE_WIDTH:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2542
  			set_field_width(&spec, get_arg(int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2543
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2544

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2545
  		case FORMAT_TYPE_PRECISION:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2546
  			set_precision(&spec, get_arg(int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2547
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2548

d4be151b2   André Goddard Rosa   vsprintf: move lo...
2549
2550
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2551
2552
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2553
2554
2555
2556
2557
2558
2559
2560
2561
  					if (str < end)
  						*str = ' ';
  					++str;
  				}
  			}
  			c = (unsigned char) get_arg(char);
  			if (str < end)
  				*str = c;
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2562
  			while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2563
2564
2565
2566
  				if (str < end)
  					*str = ' ';
  				++str;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2567
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2568
  		}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2569

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2570
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2571
  			const char *str_arg = args;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2572
  			args += strlen(str_arg) + 1;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2573
2574
  			str = string(str, end, (char *)str_arg, spec);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2575
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2576
  		case FORMAT_TYPE_PTR:
ffbfed03b   Rasmus Villemoes   lib/vsprintf.c: c...
2577
  			str = pointer(fmt, str, end, get_arg(void *), spec);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2578
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2579
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2580
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2581

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2582
  		case FORMAT_TYPE_PERCENT_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2583
2584
2585
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2586
  			break;
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2587
2588
  		case FORMAT_TYPE_INVALID:
  			goto out;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2589
2590
  		default: {
  			unsigned long long num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2591
2592
2593
2594
2595
2596
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
  				num = get_arg(long long);
  				break;
  			case FORMAT_TYPE_ULONG:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2597
2598
2599
2600
2601
2602
2603
2604
2605
  			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...
2606
2607
2608
2609
2610
2611
  			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...
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
  			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...
2626
2627
2628
  		} /* default: */
  		} /* switch(spec.type) */
  	} /* while(*fmt) */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2629

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2630
  out:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2631
2632
2633
2634
2635
2636
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
  			end[-1] = '\0';
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2637

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
  #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...
2663

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2664
2665
2666
2667
2668
  	return ret;
  }
  EXPORT_SYMBOL_GPL(bprintf);
  
  #endif /* CONFIG_BINARY_PRINTF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2669
2670
2671
2672
2673
2674
  /**
   * 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...
2675
  int vsscanf(const char *buf, const char *fmt, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2676
2677
2678
2679
2680
  {
  	const char *str = buf;
  	char *next;
  	char digit;
  	int num = 0;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
2681
  	u8 qualifier;
53809751a   Jan Beulich   sscanf: don't ign...
2682
2683
2684
2685
2686
  	unsigned int base;
  	union {
  		long long s;
  		unsigned long long u;
  	} val;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
2687
  	s16 field_width;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2688
  	bool is_sign;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2689

da99075c1   Jan Beulich   lib/vsprintf.c: i...
2690
  	while (*fmt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2691
2692
2693
2694
2695
  		/* 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...
2696
2697
  			fmt = skip_spaces(++fmt);
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
  		}
  
  		/* 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...
2710

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2711
2712
2713
2714
  		/* skip this conversion.
  		 * advance both strings to next white space
  		 */
  		if (*fmt == '*') {
da99075c1   Jan Beulich   lib/vsprintf.c: i...
2715
2716
  			if (!*str)
  				break;
f9310b2f9   Jessica Yu   sscanf: implement...
2717
2718
2719
2720
  			while (!isspace(*fmt) && *fmt != '%' && *fmt) {
  				/* '%*[' not yet supported, invalid format */
  				if (*fmt == '[')
  					return num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2721
  				fmt++;
f9310b2f9   Jessica Yu   sscanf: implement...
2722
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2723
2724
2725
2726
2727
2728
2729
  			while (!isspace(*str) && *str)
  				str++;
  			continue;
  		}
  
  		/* get field width */
  		field_width = -1;
53809751a   Jan Beulich   sscanf: don't ign...
2730
  		if (isdigit(*fmt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2731
  			field_width = skip_atoi(&fmt);
53809751a   Jan Beulich   sscanf: don't ign...
2732
2733
2734
  			if (field_width <= 0)
  				break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2735
2736
2737
  
  		/* get conversion qualifier */
  		qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
2738
  		if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
2739
  		    *fmt == 'z') {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
  			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
2751

da99075c1   Jan Beulich   lib/vsprintf.c: i...
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
  		if (!*fmt)
  			break;
  
  		if (*fmt == 'n') {
  			/* return number of characters read so far */
  			*va_arg(args, int *) = str - buf;
  			++fmt;
  			continue;
  		}
  
  		if (!*str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2763
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2764
  		base = 10;
3f623eba2   Fabian Frederick   lib/vsprintf.c: f...
2765
  		is_sign = false;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2766

7b9186f5e   André Goddard Rosa   vsprintf: give it...
2767
  		switch (*fmt++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2768
2769
  		case 'c':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2770
  			char *s = (char *)va_arg(args, char*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
  			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...
2781
2782
  			char *s = (char *)va_arg(args, char *);
  			if (field_width == -1)
4be929be3   Alexey Dobriyan   kernel-wide: repl...
2783
  				field_width = SHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2784
  			/* first, skip leading white space in buffer */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
2785
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2786
2787
  
  			/* now copy until next white space */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2788
  			while (*str && !isspace(*str) && field_width--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2789
  				*s++ = *str++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2790
2791
2792
2793
  			*s = '\0';
  			num++;
  		}
  		continue;
f9310b2f9   Jessica Yu   sscanf: implement...
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
  		/*
  		 * Warning: This implementation of the '[' conversion specifier
  		 * deviates from its glibc counterpart in the following ways:
  		 * (1) It does NOT support ranges i.e. '-' is NOT a special
  		 *     character
  		 * (2) It cannot match the closing bracket ']' itself
  		 * (3) A field width is required
  		 * (4) '%*[' (discard matching input) is currently not supported
  		 *
  		 * Example usage:
  		 * ret = sscanf("00:0a:95","%2[^:]:%2[^:]:%2[^:]",
  		 *		buf1, buf2, buf3);
  		 * if (ret < 3)
  		 *    // etc..
  		 */
  		case '[':
  		{
  			char *s = (char *)va_arg(args, char *);
  			DECLARE_BITMAP(set, 256) = {0};
  			unsigned int len = 0;
  			bool negate = (*fmt == '^');
  
  			/* field width is required */
  			if (field_width == -1)
  				return num;
  
  			if (negate)
  				++fmt;
  
  			for ( ; *fmt && *fmt != ']'; ++fmt, ++len)
  				set_bit((u8)*fmt, set);
  
  			/* no ']' or no character set found */
  			if (!*fmt || !len)
  				return num;
  			++fmt;
  
  			if (negate) {
  				bitmap_complement(set, set, 256);
  				/* exclude null '\0' byte */
  				clear_bit(0, set);
  			}
  
  			/* match must be non-empty */
  			if (!test_bit((u8)*str, set))
  				return num;
  
  			while (test_bit((u8)*str, set) && field_width--)
  				*s++ = *str++;
  			*s = '\0';
  			++num;
  		}
  		continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2847
2848
2849
2850
2851
2852
2853
2854
  		case 'o':
  			base = 8;
  			break;
  		case 'x':
  		case 'X':
  			base = 16;
  			break;
  		case 'i':
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2855
  			base = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2856
  		case 'd':
3f623eba2   Fabian Frederick   lib/vsprintf.c: f...
2857
  			is_sign = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2858
2859
2860
2861
  		case 'u':
  			break;
  		case '%':
  			/* looking for '%' in str */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2862
  			if (*str++ != '%')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
  				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...
2873
  		str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2874
2875
2876
2877
2878
2879
  
  		digit = *str;
  		if (is_sign && digit == '-')
  			digit = *(str + 1);
  
  		if (!digit
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2880
2881
2882
2883
2884
  		    || (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
2885

53809751a   Jan Beulich   sscanf: don't ign...
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
  		if (is_sign)
  			val.s = qualifier != 'L' ?
  				simple_strtol(str, &next, base) :
  				simple_strtoll(str, &next, base);
  		else
  			val.u = qualifier != 'L' ?
  				simple_strtoul(str, &next, base) :
  				simple_strtoull(str, &next, base);
  
  		if (field_width > 0 && next - str > field_width) {
  			if (base == 0)
  				_parse_integer_fixup_radix(str, &base);
  			while (next - str > field_width) {
  				if (is_sign)
  					val.s = div_s64(val.s, base);
  				else
  					val.u = div_u64(val.u, base);
  				--next;
  			}
  		}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2906
  		switch (qualifier) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2907
  		case 'H':	/* that's 'hh' in format */
53809751a   Jan Beulich   sscanf: don't ign...
2908
2909
2910
2911
  			if (is_sign)
  				*va_arg(args, signed char *) = val.s;
  			else
  				*va_arg(args, unsigned char *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2912
2913
  			break;
  		case 'h':
53809751a   Jan Beulich   sscanf: don't ign...
2914
2915
2916
2917
  			if (is_sign)
  				*va_arg(args, short *) = val.s;
  			else
  				*va_arg(args, unsigned short *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2918
2919
  			break;
  		case 'l':
53809751a   Jan Beulich   sscanf: don't ign...
2920
2921
2922
2923
  			if (is_sign)
  				*va_arg(args, long *) = val.s;
  			else
  				*va_arg(args, unsigned long *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2924
2925
  			break;
  		case 'L':
53809751a   Jan Beulich   sscanf: don't ign...
2926
2927
2928
2929
  			if (is_sign)
  				*va_arg(args, long long *) = val.s;
  			else
  				*va_arg(args, unsigned long long *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2930
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2931
  		case 'z':
53809751a   Jan Beulich   sscanf: don't ign...
2932
2933
  			*va_arg(args, size_t *) = val.u;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2934
  		default:
53809751a   Jan Beulich   sscanf: don't ign...
2935
2936
2937
2938
  			if (is_sign)
  				*va_arg(args, int *) = val.s;
  			else
  				*va_arg(args, unsigned int *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2939
2940
2941
2942
2943
2944
2945
2946
  			break;
  		}
  		num++;
  
  		if (!next)
  			break;
  		str = next;
  	}
c6b40d16d   Johannes Berg   fix sscanf %n mat...
2947

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2948
2949
  	return num;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2950
2951
2952
2953
2954
2955
2956
2957
  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...
2958
  int sscanf(const char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2959
2960
2961
  {
  	va_list args;
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2962
2963
  	va_start(args, fmt);
  	i = vsscanf(buf, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2964
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2965

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2966
2967
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2968
  EXPORT_SYMBOL(sscanf);