Blame view

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

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

9b706aee7   Denys Vlasenko   x86: trivial prin...
33
34
  /* Works only for digits and letters, but small and fast */
  #define TOLOWER(x) ((x) | 0x20)
aa46a63ef   Harvey Harrison   lib: pull base-gu...
35
36
37
38
39
40
41
42
43
44
45
  static unsigned int simple_guess_base(const char *cp)
  {
  	if (cp[0] == '0') {
  		if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
  			return 16;
  		else
  			return 8;
  	} else {
  		return 10;
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
47
   * simple_strtoull - convert a string to an unsigned long long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
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
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
52
  unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
54
  	unsigned long long result = 0;
aa46a63ef   Harvey Harrison   lib: pull base-gu...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  
  	if (!base)
  		base = simple_guess_base(cp);
  
  	if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
  		cp += 2;
  
  	while (isxdigit(*cp)) {
  		unsigned int value;
  
  		value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
  		if (value >= base)
  			break;
  		result = result * base + value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
  		cp++;
  	}
  	if (endp)
  		*endp = (char *)cp;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
73

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

922ac25c9   André Goddard Rosa   vsprintf: reuse a...
101
  	return simple_strtoul(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
103
  EXPORT_SYMBOL(simple_strtol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
109
110
  
  /**
   * simple_strtoll - convert a string to a signed long long
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
   */
22d27051b   Harvey Harrison   lib: trivial whit...
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

06b2a76d2   Yi Yang   Add new string fu...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  /**
   * strict_strtoul - convert a string to an unsigned long strictly
   * @cp: The string to be converted
   * @base: The number base to use
   * @res: The converted result value
   *
   * strict_strtoul converts a string to an unsigned long only if the
   * string is really an unsigned long string, any string containing
   * any invalid char at the tail will be rejected and -EINVAL is returned,
   * only a newline char at the tail is acceptible because people generally
   * change a module parameter in the following way:
   *
   * 	echo 1024 > /sys/module/e1000/parameters/copybreak
   *
   * echo will append a newline to the tail.
   *
   * It returns 0 if conversion is successful and *res is set to the converted
   * value, otherwise it returns -EINVAL and *res is set to 0.
   *
   * simple_strtoul just ignores the successive invalid characters and
   * return the converted value of prefix part of the string.
   */
9d85db224   Harvey Harrison   lib: remove defin...
142
143
144
145
  int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
  {
  	char *tail;
  	unsigned long val;
9d85db224   Harvey Harrison   lib: remove defin...
146
147
  
  	*res = 0;
559b140a3   Michal Nazarewicz   lib: vsprintf: us...
148
  	if (!*cp)
9d85db224   Harvey Harrison   lib: remove defin...
149
150
151
  		return -EINVAL;
  
  	val = simple_strtoul(cp, &tail, base);
e899aa823   Pavel Machek   strict_strto* is ...
152
153
  	if (tail == cp)
  		return -EINVAL;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
154

559b140a3   Michal Nazarewicz   lib: vsprintf: us...
155
156
  	if ((tail[0] == '\0') || (tail[0] == '
  ' && tail[1] == '\0')) {
9d85db224   Harvey Harrison   lib: remove defin...
157
158
159
160
161
162
163
  		*res = val;
  		return 0;
  	}
  
  	return -EINVAL;
  }
  EXPORT_SYMBOL(strict_strtoul);
06b2a76d2   Yi Yang   Add new string fu...
164
165
166
167
168
169
170
171
172
173
174
175
176
  
  /**
   * strict_strtol - convert a string to a long strictly
   * @cp: The string to be converted
   * @base: The number base to use
   * @res: The converted result value
   *
   * strict_strtol is similiar to strict_strtoul, but it allows the first
   * character of a string is '-'.
   *
   * It returns 0 if conversion is successful and *res is set to the converted
   * value, otherwise it returns -EINVAL and *res is set to 0.
   */
9d85db224   Harvey Harrison   lib: remove defin...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  int strict_strtol(const char *cp, unsigned int base, long *res)
  {
  	int ret;
  	if (*cp == '-') {
  		ret = strict_strtoul(cp + 1, base, (unsigned long *)res);
  		if (!ret)
  			*res = -(*res);
  	} else {
  		ret = strict_strtoul(cp, base, (unsigned long *)res);
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL(strict_strtol);
06b2a76d2   Yi Yang   Add new string fu...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  
  /**
   * strict_strtoull - convert a string to an unsigned long long strictly
   * @cp: The string to be converted
   * @base: The number base to use
   * @res: The converted result value
   *
   * strict_strtoull converts a string to an unsigned long long only if the
   * string is really an unsigned long long string, any string containing
   * any invalid char at the tail will be rejected and -EINVAL is returned,
   * only a newline char at the tail is acceptible because people generally
   * change a module parameter in the following way:
   *
   * 	echo 1024 > /sys/module/e1000/parameters/copybreak
   *
   * echo will append a newline to the tail of the string.
   *
   * It returns 0 if conversion is successful and *res is set to the converted
   * value, otherwise it returns -EINVAL and *res is set to 0.
   *
   * simple_strtoull just ignores the successive invalid characters and
   * return the converted value of prefix part of the string.
   */
9d85db224   Harvey Harrison   lib: remove defin...
214
215
216
217
  int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res)
  {
  	char *tail;
  	unsigned long long val;
9d85db224   Harvey Harrison   lib: remove defin...
218
219
  
  	*res = 0;
559b140a3   Michal Nazarewicz   lib: vsprintf: us...
220
  	if (!*cp)
9d85db224   Harvey Harrison   lib: remove defin...
221
222
223
  		return -EINVAL;
  
  	val = simple_strtoull(cp, &tail, base);
e899aa823   Pavel Machek   strict_strto* is ...
224
225
  	if (tail == cp)
  		return -EINVAL;
559b140a3   Michal Nazarewicz   lib: vsprintf: us...
226
227
  	if ((tail[0] == '\0') || (tail[0] == '
  ' && tail[1] == '\0')) {
9d85db224   Harvey Harrison   lib: remove defin...
228
229
230
231
232
233
234
  		*res = val;
  		return 0;
  	}
  
  	return -EINVAL;
  }
  EXPORT_SYMBOL(strict_strtoull);
06b2a76d2   Yi Yang   Add new string fu...
235
236
237
238
239
240
241
242
243
244
245
246
247
  
  /**
   * strict_strtoll - convert a string to a long long strictly
   * @cp: The string to be converted
   * @base: The number base to use
   * @res: The converted result value
   *
   * strict_strtoll is similiar to strict_strtoull, but it allows the first
   * character of a string is '-'.
   *
   * It returns 0 if conversion is successful and *res is set to the converted
   * value, otherwise it returns -EINVAL and *res is set to 0.
   */
9d85db224   Harvey Harrison   lib: remove defin...
248
249
250
251
252
253
254
255
256
257
  int strict_strtoll(const char *cp, unsigned int base, long long *res)
  {
  	int ret;
  	if (*cp == '-') {
  		ret = strict_strtoull(cp + 1, base, (unsigned long long *)res);
  		if (!ret)
  			*res = -(*res);
  	} else {
  		ret = strict_strtoull(cp, base, (unsigned long long *)res);
  	}
06b2a76d2   Yi Yang   Add new string fu...
258

9d85db224   Harvey Harrison   lib: remove defin...
259
260
  	return ret;
  }
06b2a76d2   Yi Yang   Add new string fu...
261
  EXPORT_SYMBOL(strict_strtoll);
06b2a76d2   Yi Yang   Add new string fu...
262

cf3b429b0   Joe Perches   vsprintf.c: use n...
263
264
  static noinline_for_stack
  int skip_atoi(const char **s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
266
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
  
  	while (isdigit(**s))
  		i = i*10 + *((*s)++) - '0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
270

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
  	return i;
  }
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
273
274
275
276
277
278
279
280
281
282
  /* Decimal conversion is by far the most typical, and is used
   * for /proc and /sys data. This directly impacts e.g. top performance
   * with many processes running. We optimize it for speed
   * using code from
   * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
   * (with permission from the author, Douglas W. Jones). */
  
  /* Formats correctly any integer in [0,99999].
   * Outputs from one to five digits depending on input.
   * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
cf3b429b0   Joe Perches   vsprintf.c: use n...
283
284
  static noinline_for_stack
  char *put_dec_trunc(char *buf, unsigned q)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  {
  	unsigned d3, d2, d1, d0;
  	d1 = (q>>4) & 0xf;
  	d2 = (q>>8) & 0xf;
  	d3 = (q>>12);
  
  	d0 = 6*(d3 + d2 + d1) + (q & 0xf);
  	q = (d0 * 0xcd) >> 11;
  	d0 = d0 - 10*q;
  	*buf++ = d0 + '0'; /* least significant digit */
  	d1 = q + 9*d3 + 5*d2 + d1;
  	if (d1 != 0) {
  		q = (d1 * 0xcd) >> 11;
  		d1 = d1 - 10*q;
  		*buf++ = d1 + '0'; /* next digit */
  
  		d2 = q + 2*d2;
  		if ((d2 != 0) || (d3 != 0)) {
  			q = (d2 * 0xd) >> 7;
  			d2 = d2 - 10*q;
  			*buf++ = d2 + '0'; /* next digit */
  
  			d3 = q + 4*d3;
  			if (d3 != 0) {
  				q = (d3 * 0xcd) >> 11;
  				d3 = d3 - 10*q;
  				*buf++ = d3 + '0';  /* next digit */
  				if (q != 0)
7b9186f5e   André Goddard Rosa   vsprintf: give it...
313
  					*buf++ = q + '0'; /* most sign. digit */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
314
315
316
  			}
  		}
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
317

4277eedd7   Denis Vlasenko   vsprintf.c: optim...
318
319
320
  	return buf;
  }
  /* Same with if's removed. Always emits five digits */
cf3b429b0   Joe Perches   vsprintf.c: use n...
321
322
  static noinline_for_stack
  char *put_dec_full(char *buf, unsigned q)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
323
324
325
326
327
328
329
  {
  	/* BTW, if q is in [0,9999], 8-bit ints will be enough, */
  	/* but anyway, gcc produces better code with full-sized ints */
  	unsigned d3, d2, d1, d0;
  	d1 = (q>>4) & 0xf;
  	d2 = (q>>8) & 0xf;
  	d3 = (q>>12);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
330
331
332
333
334
335
336
337
338
  	/*
  	 * Possible ways to approx. divide by 10
  	 * gcc -O2 replaces multiply with shifts and adds
  	 * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
  	 * (x * 0x67) >> 10:  1100111
  	 * (x * 0x34) >> 9:    110100 - same
  	 * (x * 0x1a) >> 8:     11010 - same
  	 * (x * 0x0d) >> 7:      1101 - same, shortest code (on i386)
  	 */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  	d0 = 6*(d3 + d2 + d1) + (q & 0xf);
  	q = (d0 * 0xcd) >> 11;
  	d0 = d0 - 10*q;
  	*buf++ = d0 + '0';
  	d1 = q + 9*d3 + 5*d2 + d1;
  		q = (d1 * 0xcd) >> 11;
  		d1 = d1 - 10*q;
  		*buf++ = d1 + '0';
  
  		d2 = q + 2*d2;
  			q = (d2 * 0xd) >> 7;
  			d2 = d2 - 10*q;
  			*buf++ = d2 + '0';
  
  			d3 = q + 4*d3;
  				q = (d3 * 0xcd) >> 11; /* - shorter code */
  				/* q = (d3 * 0x67) >> 10; - would also work */
  				d3 = d3 - 10*q;
  				*buf++ = d3 + '0';
  					*buf++ = q + '0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
359

4277eedd7   Denis Vlasenko   vsprintf.c: optim...
360
361
362
  	return buf;
  }
  /* No inlining helps gcc to use registers better */
cf3b429b0   Joe Perches   vsprintf.c: use n...
363
364
  static noinline_for_stack
  char *put_dec(char *buf, unsigned long long num)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
365
366
367
368
369
370
371
372
373
  {
  	while (1) {
  		unsigned rem;
  		if (num < 100000)
  			return put_dec_trunc(buf, num);
  		rem = do_div(num, 100000);
  		buf = put_dec_full(buf, rem);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
  #define ZEROPAD	1		/* pad with zero */
  #define SIGN	2		/* unsigned/signed long */
  #define PLUS	4		/* show plus */
  #define SPACE	8		/* space if plus */
  #define LEFT	16		/* left justified */
b89dc5d6b   Bjorn Helgaas   vsprintf: clarify...
379
380
  #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
381

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
382
383
  enum format_type {
  	FORMAT_TYPE_NONE, /* Just a string part */
ed681a91a   Vegard Nossum   vsprintf: unify t...
384
  	FORMAT_TYPE_WIDTH,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
385
386
387
388
389
390
391
392
393
  	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...
394
395
  	FORMAT_TYPE_UBYTE,
  	FORMAT_TYPE_BYTE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
396
397
398
399
400
401
402
403
404
405
  	FORMAT_TYPE_USHORT,
  	FORMAT_TYPE_SHORT,
  	FORMAT_TYPE_UINT,
  	FORMAT_TYPE_INT,
  	FORMAT_TYPE_NRCHARS,
  	FORMAT_TYPE_SIZE_T,
  	FORMAT_TYPE_PTRDIFF
  };
  
  struct printf_spec {
4e310fda9   Joe Perches   vsprintf: Change ...
406
  	u8	type;		/* format_type enum */
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
407
  	u8	flags;		/* flags to number() */
4e310fda9   Joe Perches   vsprintf: Change ...
408
409
410
411
  	u8	base;		/* number base, 8, 10 or 16 only */
  	u8	qualifier;	/* number qualifier, one of 'hHlLtzZ' */
  	s16	field_width;	/* width of output field */
  	s16	precision;	/* # of digits/chars */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
412
  };
cf3b429b0   Joe Perches   vsprintf.c: use n...
413
414
415
  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
416
  {
9b706aee7   Denys Vlasenko   x86: trivial prin...
417
418
419
420
421
422
  	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
  	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
  
  	char tmp[66];
  	char sign;
  	char locase;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
423
  	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  	int i;
9b706aee7   Denys Vlasenko   x86: trivial prin...
425
426
  	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
  	 * produces same digits or (maybe lowercased) letters */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
427
428
429
  	locase = (spec.flags & SMALL);
  	if (spec.flags & LEFT)
  		spec.flags &= ~ZEROPAD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  	sign = 0;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
431
  	if (spec.flags & SIGN) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
432
  		if ((signed long long)num < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  			sign = '-';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
434
  			num = -(signed long long)num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
435
436
  			spec.field_width--;
  		} else if (spec.flags & PLUS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  			sign = '+';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
438
439
  			spec.field_width--;
  		} else if (spec.flags & SPACE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  			sign = ' ';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
441
  			spec.field_width--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
444
  	if (need_pfx) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
445
446
447
  		spec.field_width--;
  		if (spec.base == 16)
  			spec.field_width--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
449
450
  
  	/* generate full string in tmp[], in reverse order */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
  	i = 0;
  	if (num == 0)
b39a73409   Denis Vlasenko   vsprintf.c: optim...
453
  		tmp[i++] = '0';
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
454
455
  	/* Generic code, for any base:
  	else do {
9b706aee7   Denys Vlasenko   x86: trivial prin...
456
  		tmp[i++] = (digits[do_div(num,base)] | locase);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
457
458
  	} while (num != 0);
  	*/
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
459
460
  	else if (spec.base != 10) { /* 8 or 16 */
  		int mask = spec.base - 1;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
461
  		int shift = 3;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
462
463
464
  
  		if (spec.base == 16)
  			shift = 4;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
465
  		do {
9b706aee7   Denys Vlasenko   x86: trivial prin...
466
  			tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
b39a73409   Denis Vlasenko   vsprintf.c: optim...
467
468
  			num >>= shift;
  		} while (num);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
469
470
471
  	} else { /* base 10 */
  		i = put_dec(tmp, num) - tmp;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
472
473
  
  	/* printing 100 using %2d gives "100", not "00" */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
474
475
  	if (i > spec.precision)
  		spec.precision = i;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
476
  	/* leading space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
477
478
  	spec.field_width -= spec.precision;
  	if (!(spec.flags & (ZEROPAD+LEFT))) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
479
  		while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
480
  			if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
  				*buf = ' ';
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
485
  	/* sign */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  	if (sign) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
487
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
  			*buf = sign;
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
491
492
493
494
495
  	/* "0x" / "0" prefix */
  	if (need_pfx) {
  		if (buf < end)
  			*buf = '0';
  		++buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
496
  		if (spec.base == 16) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
497
  			if (buf < end)
9b706aee7   Denys Vlasenko   x86: trivial prin...
498
  				*buf = ('X' | locase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
502
  	/* zero or space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
503
504
505
  	if (!(spec.flags & LEFT)) {
  		char c = (spec.flags & ZEROPAD) ? '0' : ' ';
  		while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
506
  			if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
  				*buf = c;
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
511
  	/* hmm even more zero padding? */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
512
  	while (i <= --spec.precision) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
513
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
  			*buf = '0';
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
517
518
  	/* actual digits of result */
  	while (--i >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
519
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
522
  			*buf = tmp[i];
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
523
  	/* trailing space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
524
  	while (--spec.field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
525
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
  			*buf = ' ';
  		++buf;
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
529

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
  	return buf;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
532
533
  static noinline_for_stack
  char *string(char *buf, char *end, const char *s, struct printf_spec spec)
0f9bfa569   Linus Torvalds   vsprintf: split o...
534
535
536
537
  {
  	int len, i;
  
  	if ((unsigned long)s < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
538
  		s = "(null)";
0f9bfa569   Linus Torvalds   vsprintf: split o...
539

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
542
543
  	if (!(spec.flags & LEFT)) {
  		while (len < spec.field_width--) {
0f9bfa569   Linus Torvalds   vsprintf: split o...
544
545
546
547
548
549
550
551
552
553
  			if (buf < end)
  				*buf = ' ';
  			++buf;
  		}
  	}
  	for (i = 0; i < len; ++i) {
  		if (buf < end)
  			*buf = *s;
  		++buf; ++s;
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
554
  	while (len < spec.field_width--) {
0f9bfa569   Linus Torvalds   vsprintf: split o...
555
556
557
558
  		if (buf < end)
  			*buf = ' ';
  		++buf;
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
559

0f9bfa569   Linus Torvalds   vsprintf: split o...
560
561
  	return buf;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
562
563
564
  static noinline_for_stack
  char *symbol_string(char *buf, char *end, void *ptr,
  		    struct printf_spec spec, char ext)
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
565
566
567
568
  {
  	unsigned long value = (unsigned long) ptr;
  #ifdef CONFIG_KALLSYMS
  	char sym[KSYM_SYMBOL_LEN];
91adcd2c4   Steven Rostedt   vsprintf: add %ps...
569
  	if (ext != 'f' && ext != 's')
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
570
571
572
  		sprint_symbol(sym, value);
  	else
  		kallsyms_lookup(value, NULL, NULL, NULL, sym);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
573

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
574
  	return string(buf, end, sym, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
575
  #else
7b9186f5e   André Goddard Rosa   vsprintf: give it...
576
  	spec.field_width = 2 * sizeof(void *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
577
578
  	spec.flags |= SPECIAL | SMALL | ZEROPAD;
  	spec.base = 16;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
579

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
580
  	return number(buf, end, value, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
581
582
  #endif
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
583
584
585
  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 ...
586
587
  {
  #ifndef IO_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
588
  #define IO_RSRC_PRINTK_SIZE	6
332d2e783   Linus Torvalds   Implement %pR to ...
589
590
591
  #endif
  
  #ifndef MEM_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
592
  #define MEM_RSRC_PRINTK_SIZE	10
332d2e783   Linus Torvalds   Implement %pR to ...
593
  #endif
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
594
  	static const struct printf_spec io_spec = {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
595
  		.base = 16,
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
596
  		.field_width = IO_RSRC_PRINTK_SIZE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
597
598
599
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
600
601
602
603
604
605
  	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...
606
607
608
609
610
611
  	static const struct printf_spec bus_spec = {
  		.base = 16,
  		.field_width = 2,
  		.precision = -1,
  		.flags = SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
612
  	static const struct printf_spec dec_spec = {
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
613
614
615
616
  		.base = 10,
  		.precision = -1,
  		.flags = 0,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
617
  	static const struct printf_spec str_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
618
619
620
621
  		.field_width = -1,
  		.precision = 10,
  		.flags = LEFT,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
622
  	static const struct printf_spec flag_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
623
624
625
626
  		.base = 16,
  		.precision = -1,
  		.flags = SPECIAL | SMALL,
  	};
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
627
628
629
630
631
  
  	/* 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...
632
  #define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref window disabled]")
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
633
634
635
  #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 ...
636
  	char *p = sym, *pend = sym + sizeof(sym);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
637
  	int decode = (fmt[0] == 'R') ? 1 : 0;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
638
  	const struct printf_spec *specp;
332d2e783   Linus Torvalds   Implement %pR to ...
639
640
  
  	*p++ = '[';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
641
  	if (res->flags & IORESOURCE_IO) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
642
  		p = string(p, pend, "io  ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
643
644
  		specp = &io_spec;
  	} else if (res->flags & IORESOURCE_MEM) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
645
  		p = string(p, pend, "mem ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
646
647
  		specp = &mem_spec;
  	} else if (res->flags & IORESOURCE_IRQ) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
648
  		p = string(p, pend, "irq ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
649
650
  		specp = &dec_spec;
  	} else if (res->flags & IORESOURCE_DMA) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
651
  		p = string(p, pend, "dma ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
652
  		specp = &dec_spec;
0f4050c7d   Bjorn Helgaas   resource: add bus...
653
654
655
  	} else if (res->flags & IORESOURCE_BUS) {
  		p = string(p, pend, "bus ", str_spec);
  		specp = &bus_spec;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
656
  	} else {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
657
  		p = string(p, pend, "??? ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
658
  		specp = &mem_spec;
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
659
  		decode = 0;
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
660
  	}
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
661
  	p = number(p, pend, res->start, *specp);
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
662
663
  	if (res->start != res->end) {
  		*p++ = '-';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
664
  		p = number(p, pend, res->end, *specp);
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
665
  	}
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
666
  	if (decode) {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
667
668
669
670
  		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...
671
672
  		if (res->flags & IORESOURCE_WINDOW)
  			p = string(p, pend, " window", str_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
673
674
  		if (res->flags & IORESOURCE_DISABLED)
  			p = string(p, pend, " disabled", str_spec);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
675
676
677
  	} else {
  		p = string(p, pend, " flags ", str_spec);
  		p = number(p, pend, res->flags, flag_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
678
  	}
332d2e783   Linus Torvalds   Implement %pR to ...
679
  	*p++ = ']';
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
680
  	*p = '\0';
332d2e783   Linus Torvalds   Implement %pR to ...
681

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
682
  	return string(buf, end, sym, spec);
332d2e783   Linus Torvalds   Implement %pR to ...
683
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
684
685
686
  static noinline_for_stack
  char *mac_address_string(char *buf, char *end, u8 *addr,
  			 struct printf_spec spec, const char *fmt)
dd45c9cf6   Harvey Harrison   printk: add %pM f...
687
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
688
  	char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
dd45c9cf6   Harvey Harrison   printk: add %pM f...
689
690
  	char *p = mac_addr;
  	int i;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
691
692
693
  	char separator;
  
  	if (fmt[1] == 'F') {		/* FDDI canonical format */
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
694
695
  		separator = '-';
  	} else {
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
696
697
  		separator = ':';
  	}
dd45c9cf6   Harvey Harrison   printk: add %pM f...
698
699
  
  	for (i = 0; i < 6; i++) {
c8e000604   Joe Perches   lib: Kill bit-rev...
700
  		p = pack_hex_byte(p, addr[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
701
  		if (fmt[0] == 'M' && i != 5)
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
702
  			*p++ = separator;
dd45c9cf6   Harvey Harrison   printk: add %pM f...
703
704
  	}
  	*p = '\0';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
705
  	return string(buf, end, mac_addr, spec);
dd45c9cf6   Harvey Harrison   printk: add %pM f...
706
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
707
708
  static noinline_for_stack
  char *ip4_string(char *p, const u8 *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
709
710
  {
  	int i;
0159f24ee   Joe Perches   lib/vsprintf.c: A...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
  	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...
736
737
  	for (i = 0; i < 4; i++) {
  		char temp[3];	/* hold each IP quad in reverse order */
0159f24ee   Joe Perches   lib/vsprintf.c: A...
738
  		int digits = put_dec_trunc(temp, addr[index]) - temp;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
739
740
741
742
743
744
745
746
747
748
749
  		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...
750
  		index += step;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
751
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
752
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
753

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
754
755
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
756
757
  static noinline_for_stack
  char *ip6_compressed_string(char *p, const char *addr)
689afa7da   Harvey Harrison   printk: add %p6 f...
758
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
759
  	int i, j, range;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
760
761
762
763
  	unsigned char zerolength[8];
  	int longest = 1;
  	int colonpos = -1;
  	u16 word;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
764
  	u8 hi, lo;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
765
  	bool needcolon = false;
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
766
767
768
769
770
771
  	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...
772
773
774
775
776
777
778
779
780
781
782
  
  	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...
783
  			if (in6.s6_addr16[j] != 0)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
784
785
786
787
788
789
790
791
792
793
  				break;
  			zerolength[i]++;
  		}
  	}
  	for (i = 0; i < range; i++) {
  		if (zerolength[i] > longest) {
  			longest = zerolength[i];
  			colonpos = i;
  		}
  	}
689afa7da   Harvey Harrison   printk: add %p6 f...
794

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  	/* 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...
810
  		word = ntohs(in6.s6_addr16[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
811
812
813
814
815
816
817
  		hi = word >> 8;
  		lo = word & 0xff;
  		if (hi) {
  			if (hi > 0x0f)
  				p = pack_hex_byte(p, hi);
  			else
  				*p++ = hex_asc_lo(hi);
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
818
  			p = pack_hex_byte(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
819
  		}
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
820
  		else if (lo > 0x0f)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
821
822
823
824
825
826
827
828
829
  			p = pack_hex_byte(p, lo);
  		else
  			*p++ = hex_asc_lo(lo);
  		needcolon = true;
  	}
  
  	if (useIPv4) {
  		if (needcolon)
  			*p++ = ':';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
830
  		p = ip4_string(p, &in6.s6_addr[12], "I4");
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
831
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
832
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
833

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
834
835
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
836
837
  static noinline_for_stack
  char *ip6_string(char *p, const char *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
838
839
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
840

689afa7da   Harvey Harrison   printk: add %p6 f...
841
  	for (i = 0; i < 8; i++) {
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
842
843
  		p = pack_hex_byte(p, *addr++);
  		p = pack_hex_byte(p, *addr++);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
844
  		if (fmt[0] == 'I' && i != 7)
689afa7da   Harvey Harrison   printk: add %p6 f...
845
846
847
  			*p++ = ':';
  	}
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
848

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
849
850
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
851
852
853
  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...
854
855
856
857
  {
  	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...
858
  		ip6_compressed_string(ip6_addr, addr);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
859
  	else
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
860
  		ip6_string(ip6_addr, addr, fmt);
689afa7da   Harvey Harrison   printk: add %p6 f...
861

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
862
  	return string(buf, end, ip6_addr, spec);
689afa7da   Harvey Harrison   printk: add %p6 f...
863
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
864
865
866
  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, ...
867
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
868
  	char ip4_addr[sizeof("255.255.255.255")];
4aa996066   Harvey Harrison   printk: add %I4, ...
869

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
872
  	return string(buf, end, ip4_addr, spec);
4aa996066   Harvey Harrison   printk: add %I4, ...
873
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
874
875
876
  static noinline_for_stack
  char *uuid_string(char *buf, char *end, const u8 *addr,
  		  struct printf_spec spec, const char *fmt)
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
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
916
917
918
919
  {
  	char uuid[sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")];
  	char *p = uuid;
  	int i;
  	static const u8 be[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
  	static const u8 le[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15};
  	const u8 *index = be;
  	bool uc = false;
  
  	switch (*(++fmt)) {
  	case 'L':
  		uc = true;		/* fall-through */
  	case 'l':
  		index = le;
  		break;
  	case 'B':
  		uc = true;
  		break;
  	}
  
  	for (i = 0; i < 16; i++) {
  		p = pack_hex_byte(p, addr[index[i]]);
  		switch (i) {
  		case 3:
  		case 5:
  		case 7:
  		case 9:
  			*p++ = '-';
  			break;
  		}
  	}
  
  	*p = 0;
  
  	if (uc) {
  		p = uuid;
  		do {
  			*p = toupper(*p);
  		} while (*(++p));
  	}
  
  	return string(buf, end, uuid, spec);
  }
4d8a743cd   Linus Torvalds   vsprintf: add inf...
920
921
922
923
924
  /*
   * Show a '%p' thing.  A kernel extension is that the '%p' is followed
   * by an extra set of alphanumeric characters that are extended format
   * specifiers.
   *
332d2e783   Linus Torvalds   Implement %pR to ...
925
926
   * Right now we handle:
   *
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
927
928
   * - 'F' For symbolic function descriptor pointers with offset
   * - 'f' For simple symbolic function names without offset
0efb4d207   Steven Rostedt   vsnprintf: remove...
929
930
   * - 'S' For symbolic direct pointers with offset
   * - 's' For symbolic direct pointers without offset
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
931
932
   * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
   * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
dd45c9cf6   Harvey Harrison   printk: add %pM f...
933
934
   * - '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...
935
   * - 'm' For a 6-byte MAC address, it prints the hex address without colons
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
936
   * - 'MF' For a 6-byte MAC FDDI address, it prints the address
c8e000604   Joe Perches   lib: Kill bit-rev...
937
   *       with a dash-separated hex notation
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
938
939
940
941
942
943
   * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
   *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
   *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
   * - 'i' [46] for 'raw' IPv4/IPv6 addresses
   *       IPv6 omits the colons (01020304...0f)
   *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
0159f24ee   Joe Perches   lib/vsprintf.c: A...
944
   * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
945
   * - 'I6c' for IPv6 addresses printed as specified by
3f4724027   Uwe Kleine-König   vsnprintf: fix re...
946
   *       http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
947
948
949
950
951
952
953
954
955
956
957
   * - '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...
958
959
960
961
962
   * - '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.
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
963
   *
332d2e783   Linus Torvalds   Implement %pR to ...
964
965
966
   * 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...
967
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
968
969
970
  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...
971
  {
d97106ab5   Linus Torvalds   Make %p print '(n...
972
  	if (!ptr)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
973
  		return string(buf, end, "(null)", spec);
d97106ab5   Linus Torvalds   Make %p print '(n...
974

0fe1ef24f   Linus Torvalds   vsprintf: add sup...
975
976
  	switch (*fmt) {
  	case 'F':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
977
  	case 'f':
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
978
979
980
  		ptr = dereference_function_descriptor(ptr);
  		/* Fallthrough */
  	case 'S':
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
981
  	case 's':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
982
  		return symbol_string(buf, end, ptr, spec, *fmt);
332d2e783   Linus Torvalds   Implement %pR to ...
983
  	case 'R':
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
984
  	case 'r':
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
985
  		return resource_string(buf, end, ptr, spec, fmt);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
986
987
  	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
  	case 'm':			/* Contiguous: 000102030405 */
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
988
  					/* [mM]F (FDDI, bit reversed) */
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  		return mac_address_string(buf, end, ptr, spec, fmt);
  	case 'I':			/* Formatted IP supported
  					 * 4:	1.2.3.4
  					 * 6:	0001:0203:...:0708
  					 * 6c:	1::708 or 1::1.2.3.4
  					 */
  	case 'i':			/* Contiguous:
  					 * 4:	001.002.003.004
  					 * 6:   000102...0f
  					 */
  		switch (fmt[1]) {
  		case '6':
  			return ip6_addr_string(buf, end, ptr, spec, fmt);
  		case '4':
  			return ip4_addr_string(buf, end, ptr, spec, fmt);
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1005
  		break;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1006
1007
  	case 'U':
  		return uuid_string(buf, end, ptr, spec, fmt);
7db6f5fb6   Joe Perches   vsprintf: Recursi...
1008
1009
1010
1011
  	case 'V':
  		return buf + vsnprintf(buf, end - buf,
  				       ((struct va_format *)ptr)->fmt,
  				       *(((struct va_format *)ptr)->va));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
  	}
  	spec.flags |= SMALL;
  	if (spec.field_width == -1) {
  		spec.field_width = 2*sizeof(void *);
  		spec.flags |= ZEROPAD;
  	}
  	spec.base = 16;
  
  	return number(buf, end, (unsigned long) ptr, spec);
  }
  
  /*
   * Helper function to decode printf style format.
   * Each call decode a token from the format and return the
   * number of characters read (or likely the delta where it wants
   * to go on the next call).
   * The decoded token is returned through the parameters
   *
   * 'h', 'l', or 'L' for integer fields
   * 'z' support added 23/7/1999 S.H.
   * 'z' changed to 'Z' --davidm 1/25/99
   * 't' added for ptrdiff_t
   *
   * @fmt: the format string
   * @type of the token returned
   * @flags: various flags such as +, -, # tokens..
   * @field_width: overwritten width
   * @base: base of the number (octal, hex, ...)
   * @precision: precision of a number
   * @qualifier: qualifier of a number (long, size_t, ...)
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
1043
1044
  static noinline_for_stack
  int format_decode(const char *fmt, struct printf_spec *spec)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1045
1046
  {
  	const char *start = fmt;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1047
1048
  
  	/* we finished early by reading the field width */
ed681a91a   Vegard Nossum   vsprintf: unify t...
1049
  	if (spec->type == FORMAT_TYPE_WIDTH) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
  		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...
1107
  		spec->type = FORMAT_TYPE_WIDTH;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
  		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...
1122
  			spec->type = FORMAT_TYPE_PRECISION;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1123
1124
1125
1126
1127
1128
1129
  			return ++fmt - start;
  		}
  	}
  
  qualifier:
  	/* get the conversion qualifier */
  	spec->qualifier = -1;
08562cb27   André Goddard Rosa   vsprintf: use TOL...
1130
1131
  	if (*fmt == 'h' || TOLOWER(*fmt) == 'l' ||
  	    TOLOWER(*fmt) == 'z' || *fmt == 't') {
a4e94ef0d   Zhaolei   printk: add suppo...
1132
1133
1134
1135
1136
1137
1138
1139
1140
  		spec->qualifier = *fmt++;
  		if (unlikely(spec->qualifier == *fmt)) {
  			if (spec->qualifier == 'l') {
  				spec->qualifier = 'L';
  				++fmt;
  			} else if (spec->qualifier == 'h') {
  				spec->qualifier = 'H';
  				++fmt;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
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
  		}
  	}
  
  	/* default base */
  	spec->base = 10;
  	switch (*fmt) {
  	case 'c':
  		spec->type = FORMAT_TYPE_CHAR;
  		return ++fmt - start;
  
  	case 's':
  		spec->type = FORMAT_TYPE_STR;
  		return ++fmt - start;
  
  	case 'p':
  		spec->type = FORMAT_TYPE_PTR;
  		return fmt - start;
  		/* skip alnum */
  
  	case 'n':
  		spec->type = FORMAT_TYPE_NRCHARS;
  		return ++fmt - start;
  
  	case '%':
  		spec->type = FORMAT_TYPE_PERCENT_CHAR;
  		return ++fmt - start;
  
  	/* integer number formats - set up the flags and "break" */
  	case 'o':
  		spec->base = 8;
  		break;
  
  	case 'x':
  		spec->flags |= SMALL;
  
  	case 'X':
  		spec->base = 16;
  		break;
  
  	case 'd':
  	case 'i':
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1182
  		spec->flags |= SIGN;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1183
  	case 'u':
4aa996066   Harvey Harrison   printk: add %I4, ...
1184
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1185
1186
1187
1188
  
  	default:
  		spec->type = FORMAT_TYPE_INVALID;
  		return fmt - start;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1189
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1190
1191
1192
1193
  
  	if (spec->qualifier == 'L')
  		spec->type = FORMAT_TYPE_LONG_LONG;
  	else if (spec->qualifier == 'l') {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1194
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1195
1196
1197
  			spec->type = FORMAT_TYPE_LONG;
  		else
  			spec->type = FORMAT_TYPE_ULONG;
08562cb27   André Goddard Rosa   vsprintf: use TOL...
1198
  	} else if (TOLOWER(spec->qualifier) == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1199
1200
1201
  		spec->type = FORMAT_TYPE_SIZE_T;
  	} else if (spec->qualifier == 't') {
  		spec->type = FORMAT_TYPE_PTRDIFF;
a4e94ef0d   Zhaolei   printk: add suppo...
1202
1203
1204
1205
1206
  	} else if (spec->qualifier == 'H') {
  		if (spec->flags & SIGN)
  			spec->type = FORMAT_TYPE_BYTE;
  		else
  			spec->type = FORMAT_TYPE_UBYTE;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1207
  	} else if (spec->qualifier == 'h') {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1208
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1209
1210
1211
1212
  			spec->type = FORMAT_TYPE_SHORT;
  		else
  			spec->type = FORMAT_TYPE_USHORT;
  	} else {
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1213
  		if (spec->flags & SIGN)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1214
1215
1216
  			spec->type = FORMAT_TYPE_INT;
  		else
  			spec->type = FORMAT_TYPE_UINT;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1217
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1218
1219
  
  	return ++fmt - start;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1220
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
1222
1223
1224
1225
1226
1227
  /**
   * vsnprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
20036fdca   Andi Kleen   Add kerneldoc doc...
1228
   * This function follows C99 vsnprintf, but has some extensions:
91adcd2c4   Steven Rostedt   vsprintf: add %ps...
1229
1230
   * %pS output the name of a text symbol with offset
   * %ps output the name of a text symbol without offset
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1231
1232
   * %pF output the name of a function pointer with its offset
   * %pf output the name of a function pointer without its offset
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1233
1234
1235
1236
1237
1238
1239
1240
1241
   * %pR output the address range in a struct resource with decoded flags
   * %pr output the address range in a struct resource with raw flags
   * %pM output a 6-byte MAC address with colons
   * %pm output a 6-byte MAC address without colons
   * %pI4 print an IPv4 address without leading zeros
   * %pi4 print an IPv4 address with leading zeros
   * %pI6 print an IPv6 address with colons
   * %pi6 print an IPv6 address without colons
   * %pI6c print an IPv6 address as specified by
3f4724027   Uwe Kleine-König   vsnprintf: fix re...
1242
   *   http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00
8a79503aa   Uwe Kleine-König   lib/vsprintf.c: d...
1243
1244
   * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
   *   case.
0efb4d207   Steven Rostedt   vsnprintf: remove...
1245
   * %n is ignored
20036fdca   Andi Kleen   Add kerneldoc doc...
1246
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
1248
1249
1250
   * 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 ...
1251
   * (not including the trailing '\0'), use vscnprintf(). If the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1252
1253
1254
1255
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   *
   * Call this function if you are already dealing with a va_list.
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
1256
   * You probably want snprintf() instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1257
1258
1259
   */
  int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260
  	unsigned long long num;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1261
  	char *str, *end;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1262
  	struct printf_spec spec = {0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1264
1265
  	/* Reject out-of-range values early.  Large positive sizes are
  	   used for unknown buffer sizes. */
2f30b1f9e   Marcin Slusarz   vsprintf: use WAR...
1266
  	if (WARN_ON_ONCE((int) size < 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
1269
  
  	str = buf;
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1270
  	end = buf + size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1272
1273
1274
1275
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1277
1278
  	while (*fmt) {
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1279
  		int read = format_decode(fmt, &spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1283
1284
1285
1286
1287
1288
1289
  		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
1290
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1291
1292
  			str += read;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
1294
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1295
1296
  			spec.field_width = va_arg(args, int);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1298
1299
1300
  		case FORMAT_TYPE_PRECISION:
  			spec.precision = va_arg(args, int);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301

d4be151b2   André Goddard Rosa   vsprintf: move lo...
1302
1303
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1304
1305
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1306
  					if (str < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
1308
  						*str = ' ';
  					++str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1310
1311
1312
1313
1314
1315
1316
  				}
  			}
  			c = (unsigned char) va_arg(args, int);
  			if (str < end)
  				*str = c;
  			++str;
  			while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1317
  				if (str < end)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1318
  					*str = ' ';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
  				++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1320
1321
  			}
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1322
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1328
1329
1330
1331
1332
1333
  		case FORMAT_TYPE_PTR:
  			str = pointer(fmt+1, str, end, va_arg(args, void *),
  				      spec);
  			while (isalnum(*fmt))
  				fmt++;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1335
1336
1337
1338
1339
  		case FORMAT_TYPE_PERCENT_CHAR:
  			if (str < end)
  				*str = '%';
  			++str;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1341
1342
1343
1344
  		case FORMAT_TYPE_INVALID:
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1345
1346
1347
  			break;
  
  		case FORMAT_TYPE_NRCHARS: {
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1348
  			u8 qualifier = spec.qualifier;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1349
1350
1351
1352
  
  			if (qualifier == 'l') {
  				long *ip = va_arg(args, long *);
  				*ip = (str - buf);
08562cb27   André Goddard Rosa   vsprintf: use TOL...
1353
  			} else if (TOLOWER(qualifier) == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1354
1355
1356
1357
1358
1359
1360
  				size_t *ip = va_arg(args, size_t *);
  				*ip = (str - buf);
  			} else {
  				int *ip = va_arg(args, int *);
  				*ip = (str - buf);
  			}
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
  
  		default:
  			switch (spec.type) {
  			case FORMAT_TYPE_LONG_LONG:
  				num = va_arg(args, long long);
  				break;
  			case FORMAT_TYPE_ULONG:
  				num = va_arg(args, unsigned long);
  				break;
  			case FORMAT_TYPE_LONG:
  				num = va_arg(args, long);
  				break;
  			case FORMAT_TYPE_SIZE_T:
  				num = va_arg(args, size_t);
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = va_arg(args, ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1380
1381
1382
1383
1384
1385
  			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...
1386
1387
1388
1389
1390
1391
  			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...
1392
1393
  			case FORMAT_TYPE_INT:
  				num = (int) va_arg(args, int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1394
1395
1396
1397
1398
1399
  				break;
  			default:
  				num = va_arg(args, unsigned int);
  			}
  
  			str = number(str, end, num, spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1402

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1403
1404
1405
1406
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
0a6047eef   Linus Torvalds   Fix vsnprintf off...
1407
  			end[-1] = '\0';
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1408
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1409

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
  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
   * the @buf not including the trailing '\0'. If @size is <= 0 the function
   * returns 0.
   *
   * Call this function if you are already dealing with a va_list.
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
1428
   * You probably want scnprintf() instead.
20036fdca   Andi Kleen   Add kerneldoc doc...
1429
1430
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
1433
1434
   */
  int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1435
  	i = vsnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
1437
  	return (i >= size) ? (size - 1) : i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
  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...
1451
1452
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1454
  int snprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
1456
1457
1458
1459
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1460
  	i = vsnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1462

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
  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
ea6f3281a   Martin Peschke   [PATCH] scnprintf...
1475
   * the trailing '\0'. If @size is <= 0 the function returns 0.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1477
  int scnprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
1479
1480
1481
1482
1483
1484
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
  	i = vsnprintf(buf, size, fmt, args);
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1485

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
  	return (i >= size) ? (size - 1) : i;
  }
  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 ...
1497
   * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1498
1499
1500
   * buffer overflows.
   *
   * Call this function if you are already dealing with a va_list.
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
1501
   * You probably want sprintf() instead.
20036fdca   Andi Kleen   Add kerneldoc doc...
1502
1503
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
1505
1506
1507
1508
   */
  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
1509
1510
1511
1512
1513
1514
1515
1516
1517
  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 ...
1518
   * into @buf. Use snprintf() or scnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
   * buffer overflows.
20036fdca   Andi Kleen   Add kerneldoc doc...
1520
1521
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1523
  int sprintf(char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1524
1525
1526
1527
1528
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1529
  	i = vsnprintf(buf, INT_MAX, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1531

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1532
1533
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534
  EXPORT_SYMBOL(sprintf);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
  #ifdef CONFIG_BINARY_PRINTF
  /*
   * bprintf service:
   * vbin_printf() - VA arguments to binary data
   * bstr_printf() - Binary data to text string
   */
  
  /**
   * vbin_printf - Parse a format string and place args' binary value in a buffer
   * @bin_buf: The buffer to place args' binary value
   * @size: The size of the buffer(by words(32bits), not characters)
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
   * The format follows C99 vsnprintf, except %n is ignored, and its argument
   * is skiped.
   *
   * The return value is the number of words(32bits) which would be generated for
   * the given input.
   *
   * NOTE:
   * If the return value is greater than @size, the resulting bin_buf is NOT
   * valid for bstr_printf().
   */
  int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
  {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1561
  	struct printf_spec spec = {0};
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1562
  	char *str, *end;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
  
  	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...
1586
  	while (*fmt) {
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1587
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1588

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1591
1592
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE:
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1593
1594
  		case FORMAT_TYPE_INVALID:
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1595
  			break;
ed681a91a   Vegard Nossum   vsprintf: unify t...
1596
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1597
1598
1599
1600
1601
  		case FORMAT_TYPE_PRECISION:
  			save_arg(int);
  			break;
  
  		case FORMAT_TYPE_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1602
  			save_arg(char);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1603
1604
1605
  			break;
  
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1606
1607
  			const char *save_str = va_arg(args, char *);
  			size_t len;
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
1608

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1609
1610
  			if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
  					|| (unsigned long)save_str < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
1611
  				save_str = "(null)";
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
1612
1613
1614
1615
  			len = strlen(save_str) + 1;
  			if (str + len < end)
  				memcpy(str, save_str, len);
  			str += len;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1616
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1617
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1618
1619
  
  		case FORMAT_TYPE_PTR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1620
1621
  			save_arg(void *);
  			/* skip all alphanumeric pointer suffixes */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1622
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1623
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1624
  			break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1625
  		case FORMAT_TYPE_NRCHARS: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1626
  			/* skip %n 's argument */
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1627
  			u8 qualifier = spec.qualifier;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1628
1629
1630
  			void *skip_arg;
  			if (qualifier == 'l')
  				skip_arg = va_arg(args, long *);
08562cb27   André Goddard Rosa   vsprintf: use TOL...
1631
  			else if (TOLOWER(qualifier) == 'z')
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1632
1633
1634
  				skip_arg = va_arg(args, size_t *);
  			else
  				skip_arg = va_arg(args, int *);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1635
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1636
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1637
1638
1639
1640
1641
  
  		default:
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1642
  				save_arg(long long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1643
1644
1645
  				break;
  			case FORMAT_TYPE_ULONG:
  			case FORMAT_TYPE_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1646
  				save_arg(unsigned long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1647
1648
  				break;
  			case FORMAT_TYPE_SIZE_T:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1649
  				save_arg(size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1650
1651
  				break;
  			case FORMAT_TYPE_PTRDIFF:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1652
  				save_arg(ptrdiff_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1653
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
1654
1655
1656
1657
  			case FORMAT_TYPE_UBYTE:
  			case FORMAT_TYPE_BYTE:
  				save_arg(char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1658
1659
  			case FORMAT_TYPE_USHORT:
  			case FORMAT_TYPE_SHORT:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1660
  				save_arg(short);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1661
1662
  				break;
  			default:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1663
  				save_arg(int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1664
  			}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1665
1666
  		}
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1667

7b9186f5e   André Goddard Rosa   vsprintf: give it...
1668
  	return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1669
  #undef save_arg
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
  }
  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...
1685
   *  see vsnprintf comment for details.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
   *
   * 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...
1697
  	struct printf_spec spec = {0};
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1698
1699
  	char *str, *end;
  	const char *args = (const char *)bin_buf;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1700

2f30b1f9e   Marcin Slusarz   vsprintf: use WAR...
1701
  	if (WARN_ON_ONCE((int) size < 0))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1702
  		return 0;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
  
  	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...
1727
  	while (*fmt) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1728
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1729
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1730

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1733
1734
1735
1736
1737
1738
1739
  		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...
1740
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1741
1742
  			str += read;
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1743
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
1744
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1745
1746
  			spec.field_width = get_arg(int);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1747

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1748
1749
1750
  		case FORMAT_TYPE_PRECISION:
  			spec.precision = get_arg(int);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1751

d4be151b2   André Goddard Rosa   vsprintf: move lo...
1752
1753
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1754
1755
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1756
1757
1758
1759
1760
1761
1762
1763
1764
  					if (str < end)
  						*str = ' ';
  					++str;
  				}
  			}
  			c = (unsigned char) get_arg(char);
  			if (str < end)
  				*str = c;
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1765
  			while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1766
1767
1768
1769
  				if (str < end)
  					*str = ' ';
  				++str;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1770
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1771
  		}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1772

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1773
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1774
  			const char *str_arg = args;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1775
  			args += strlen(str_arg) + 1;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1776
1777
  			str = string(str, end, (char *)str_arg, spec);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1778
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1779
1780
1781
  		case FORMAT_TYPE_PTR:
  			str = pointer(fmt+1, str, end, get_arg(void *), spec);
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1782
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1783
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1784

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1785
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1786
  		case FORMAT_TYPE_INVALID:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1787
1788
1789
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1790
1791
1792
1793
1794
  			break;
  
  		case FORMAT_TYPE_NRCHARS:
  			/* skip */
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1795
1796
  		default: {
  			unsigned long long num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1797
1798
1799
1800
1801
1802
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
  				num = get_arg(long long);
  				break;
  			case FORMAT_TYPE_ULONG:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1803
1804
1805
1806
1807
1808
1809
1810
1811
  			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...
1812
1813
1814
1815
1816
1817
  			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...
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
  			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...
1832
1833
1834
  		} /* default: */
  		} /* switch(spec.type) */
  	} /* while(*fmt) */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1835

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1836
1837
1838
1839
1840
1841
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
  			end[-1] = '\0';
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1842

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
  #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...
1868

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
1869
1870
1871
1872
1873
  	return ret;
  }
  EXPORT_SYMBOL_GPL(bprintf);
  
  #endif /* CONFIG_BINARY_PRINTF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1874
1875
1876
1877
1878
1879
  /**
   * 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...
1880
  int vsscanf(const char *buf, const char *fmt, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1881
1882
1883
1884
1885
  {
  	const char *str = buf;
  	char *next;
  	char digit;
  	int num = 0;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
1886
1887
1888
  	u8 qualifier;
  	u8 base;
  	s16 field_width;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1889
  	bool is_sign;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1890

7b9186f5e   André Goddard Rosa   vsprintf: give it...
1891
  	while (*fmt && *str) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1892
1893
1894
1895
1896
  		/* 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...
1897
1898
  			fmt = skip_spaces(++fmt);
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
  		}
  
  		/* 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...
1911

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1912
1913
1914
1915
  		/* skip this conversion.
  		 * advance both strings to next white space
  		 */
  		if (*fmt == '*') {
8fccae2c9   Andy Spencer   sscanf(): fix %*s%n
1916
  			while (!isspace(*fmt) && *fmt != '%' && *fmt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
  				fmt++;
  			while (!isspace(*str) && *str)
  				str++;
  			continue;
  		}
  
  		/* get field width */
  		field_width = -1;
  		if (isdigit(*fmt))
  			field_width = skip_atoi(&fmt);
  
  		/* get conversion qualifier */
  		qualifier = -1;
08562cb27   André Goddard Rosa   vsprintf: use TOL...
1930
1931
  		if (*fmt == 'h' || TOLOWER(*fmt) == 'l' ||
  		    TOLOWER(*fmt) == 'z') {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
  			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
1943
1944
1945
  
  		if (!*fmt || !*str)
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1946
1947
  		base = 10;
  		is_sign = 0;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1948
  		switch (*fmt++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1949
1950
  		case 'c':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1951
  			char *s = (char *)va_arg(args, char*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
  			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...
1962
1963
  			char *s = (char *)va_arg(args, char *);
  			if (field_width == -1)
4be929be3   Alexey Dobriyan   kernel-wide: repl...
1964
  				field_width = SHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1965
  			/* first, skip leading white space in buffer */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
1966
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1967
1968
  
  			/* now copy until next white space */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1969
  			while (*str && !isspace(*str) && field_width--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1970
  				*s++ = *str++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1971
1972
1973
1974
1975
1976
1977
  			*s = '\0';
  			num++;
  		}
  		continue;
  		case 'n':
  			/* return number of characters read so far */
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1978
  			int *i = (int *)va_arg(args, int*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
  			*i = str - buf;
  		}
  		continue;
  		case 'o':
  			base = 8;
  			break;
  		case 'x':
  		case 'X':
  			base = 16;
  			break;
  		case 'i':
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1990
  			base = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1991
1992
1993
1994
1995
1996
  		case 'd':
  			is_sign = 1;
  		case 'u':
  			break;
  		case '%':
  			/* looking for '%' in str */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1997
  			if (*str++ != '%')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
  				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...
2008
  		str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2009
2010
2011
2012
2013
2014
  
  		digit = *str;
  		if (is_sign && digit == '-')
  			digit = *(str + 1);
  
  		if (!digit
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2015
2016
2017
2018
2019
  		    || (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
2020

7b9186f5e   André Goddard Rosa   vsprintf: give it...
2021
  		switch (qualifier) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2022
2023
  		case 'H':	/* that's 'hh' in format */
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2024
2025
  				signed char *s = (signed char *)va_arg(args, signed char *);
  				*s = (signed char)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2026
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2027
2028
  				unsigned char *s = (unsigned char *)va_arg(args, unsigned char *);
  				*s = (unsigned char)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029
2030
2031
2032
  			}
  			break;
  		case 'h':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2033
2034
  				short *s = (short *)va_arg(args, short *);
  				*s = (short)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2035
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2036
2037
  				unsigned short *s = (unsigned short *)va_arg(args, unsigned short *);
  				*s = (unsigned short)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2038
2039
2040
2041
  			}
  			break;
  		case 'l':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2042
2043
  				long *l = (long *)va_arg(args, long *);
  				*l = simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2045
2046
  				unsigned long *l = (unsigned long *)va_arg(args, unsigned long *);
  				*l = simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2047
2048
2049
2050
  			}
  			break;
  		case 'L':
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2051
2052
  				long long *l = (long long *)va_arg(args, long long *);
  				*l = simple_strtoll(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2053
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2054
2055
  				unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *);
  				*l = simple_strtoull(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2056
2057
2058
2059
2060
  			}
  			break;
  		case 'Z':
  		case 'z':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2061
2062
  			size_t *s = (size_t *)va_arg(args, size_t *);
  			*s = (size_t)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2063
2064
2065
2066
  		}
  		break;
  		default:
  			if (is_sign) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2067
2068
  				int *i = (int *)va_arg(args, int *);
  				*i = (int)simple_strtol(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
  			} else {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2070
2071
  				unsigned int *i = (unsigned int *)va_arg(args, unsigned int*);
  				*i = (unsigned int)simple_strtoul(str, &next, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2072
2073
2074
2075
2076
2077
2078
2079
2080
  			}
  			break;
  		}
  		num++;
  
  		if (!next)
  			break;
  		str = next;
  	}
c6b40d16d   Johannes Berg   fix sscanf %n mat...
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
  
  	/*
  	 * Now we've come all the way through so either the input string or the
  	 * format ended. In the former case, there can be a %n at the current
  	 * position in the format that needs to be filled.
  	 */
  	if (*fmt == '%' && *(fmt + 1) == 'n') {
  		int *p = (int *)va_arg(args, int *);
  		*p = str - buf;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
  	return num;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2093
2094
2095
2096
2097
2098
2099
2100
  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...
2101
  int sscanf(const char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102
2103
2104
  {
  	va_list args;
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2105
2106
  	va_start(args, fmt);
  	i = vsscanf(buf, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2107
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2108

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109
2110
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
  EXPORT_SYMBOL(sscanf);