blob: e94b4bd25bc5fae8fbe2c39afc0155f50d834077 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/lib/vsprintf.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8/*
9 * Wirzenius wrote this portably, Torvalds fucked it up :-)
10 */
11
12/*
13 * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
14 * - changed to provide snprintf and vsnprintf functions
15 * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
16 * - scnprintf and vscnprintf
17 */
18
19#include <stdarg.h>
20#include <linux/module.h>
21#include <linux/types.h>
22#include <linux/string.h>
23#include <linux/ctype.h>
24#include <linux/kernel.h>
25
Tim Schmielau4e57b682005-10-30 15:03:48 -080026#include <asm/page.h> /* for PAGE_SIZE */
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <asm/div64.h>
28
29/**
30 * simple_strtoul - convert a string to an unsigned long
31 * @cp: The start of the string
32 * @endp: A pointer to the end of the parsed string will be placed here
33 * @base: The number base to use
34 */
35unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
36{
37 unsigned long result = 0,value;
38
39 if (!base) {
40 base = 10;
41 if (*cp == '0') {
42 base = 8;
43 cp++;
44 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
45 cp++;
46 base = 16;
47 }
48 }
49 } else if (base == 16) {
50 if (cp[0] == '0' && toupper(cp[1]) == 'X')
51 cp += 2;
52 }
53 while (isxdigit(*cp) &&
54 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
55 result = result*base + value;
56 cp++;
57 }
58 if (endp)
59 *endp = (char *)cp;
60 return result;
61}
62
63EXPORT_SYMBOL(simple_strtoul);
64
65/**
66 * simple_strtol - convert a string to a signed long
67 * @cp: The start of the string
68 * @endp: A pointer to the end of the parsed string will be placed here
69 * @base: The number base to use
70 */
71long simple_strtol(const char *cp,char **endp,unsigned int base)
72{
73 if(*cp=='-')
74 return -simple_strtoul(cp+1,endp,base);
75 return simple_strtoul(cp,endp,base);
76}
77
78EXPORT_SYMBOL(simple_strtol);
79
80/**
81 * simple_strtoull - convert a string to an unsigned long long
82 * @cp: The start of the string
83 * @endp: A pointer to the end of the parsed string will be placed here
84 * @base: The number base to use
85 */
86unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
87{
88 unsigned long long result = 0,value;
89
90 if (!base) {
91 base = 10;
92 if (*cp == '0') {
93 base = 8;
94 cp++;
95 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
96 cp++;
97 base = 16;
98 }
99 }
100 } else if (base == 16) {
101 if (cp[0] == '0' && toupper(cp[1]) == 'X')
102 cp += 2;
103 }
104 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
105 ? toupper(*cp) : *cp)-'A'+10) < base) {
106 result = result*base + value;
107 cp++;
108 }
109 if (endp)
110 *endp = (char *)cp;
111 return result;
112}
113
114EXPORT_SYMBOL(simple_strtoull);
115
116/**
117 * simple_strtoll - convert a string to a signed long long
118 * @cp: The start of the string
119 * @endp: A pointer to the end of the parsed string will be placed here
120 * @base: The number base to use
121 */
122long long simple_strtoll(const char *cp,char **endp,unsigned int base)
123{
124 if(*cp=='-')
125 return -simple_strtoull(cp+1,endp,base);
126 return simple_strtoull(cp,endp,base);
127}
128
129static int skip_atoi(const char **s)
130{
131 int i=0;
132
133 while (isdigit(**s))
134 i = i*10 + *((*s)++) - '0';
135 return i;
136}
137
138#define ZEROPAD 1 /* pad with zero */
139#define SIGN 2 /* unsigned/signed long */
140#define PLUS 4 /* show plus */
141#define SPACE 8 /* space if plus */
142#define LEFT 16 /* left justified */
143#define SPECIAL 32 /* 0x */
144#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
145
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700146static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700148 char sign,tmp[66];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 const char *digits;
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700150 /* we are called with base 8, 10 or 16, only, thus don't need "g..." */
151 static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */
152 static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
153 int need_pfx = ((type & SPECIAL) && base != 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 int i;
155
156 digits = (type & LARGE) ? large_digits : small_digits;
157 if (type & LEFT)
158 type &= ~ZEROPAD;
159 if (base < 2 || base > 36)
160 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 sign = 0;
162 if (type & SIGN) {
163 if ((signed long long) num < 0) {
164 sign = '-';
165 num = - (signed long long) num;
166 size--;
167 } else if (type & PLUS) {
168 sign = '+';
169 size--;
170 } else if (type & SPACE) {
171 sign = ' ';
172 size--;
173 }
174 }
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700175 if (need_pfx) {
176 size--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 if (base == 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 size--;
179 }
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700180
181 /* generate full string in tmp[], in reverse order */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 i = 0;
183 if (num == 0)
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700184 tmp[i++] = '0';
185 else if (base != 10) { /* 8 or 16 */
186 int mask = base - 1;
187 int shift = 3;
188 if (base == 16) shift = 4;
189 do {
190 tmp[i++] = digits[((unsigned char)num) & mask];
191 num >>= shift;
192 } while (num);
193 } else do { /* generic code, works for any base */
194 tmp[i++] = digits[do_div(num,10 /*base*/)];
195 } while (num);
196
197 /* printing 100 using %2d gives "100", not "00" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 if (i > precision)
199 precision = i;
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700200 /* leading space padding */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 size -= precision;
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700202 if (!(type & (ZEROPAD+LEFT))) {
203 while(--size >= 0) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700204 if (buf < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 *buf = ' ';
206 ++buf;
207 }
208 }
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700209 /* sign */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 if (sign) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700211 if (buf < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 *buf = sign;
213 ++buf;
214 }
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700215 /* "0x" / "0" prefix */
216 if (need_pfx) {
217 if (buf < end)
218 *buf = '0';
219 ++buf;
220 if (base == 16) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700221 if (buf < end)
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700222 *buf = digits[16]; /* for arbitrary base: digits[33]; */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 ++buf;
224 }
225 }
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700226 /* zero or space padding */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 if (!(type & LEFT)) {
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700228 char c = (type & ZEROPAD) ? '0' : ' ';
229 while (--size >= 0) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700230 if (buf < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 *buf = c;
232 ++buf;
233 }
234 }
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700235 /* hmm even more zero padding? */
236 while (i <= --precision) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700237 if (buf < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 *buf = '0';
239 ++buf;
240 }
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700241 /* actual digits of result */
242 while (--i >= 0) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700243 if (buf < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 *buf = tmp[i];
245 ++buf;
246 }
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700247 /* trailing space padding */
248 while (--size >= 0) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700249 if (buf < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 *buf = ' ';
251 ++buf;
252 }
253 return buf;
254}
255
256/**
257 * vsnprintf - Format a string and place it in a buffer
258 * @buf: The buffer to place the result into
259 * @size: The size of the buffer, including the trailing null space
260 * @fmt: The format string to use
261 * @args: Arguments for the format string
262 *
263 * The return value is the number of characters which would
264 * be generated for the given input, excluding the trailing
265 * '\0', as per ISO C99. If you want to have the exact
266 * number of characters written into @buf as return value
Robert P. J. Day72fd4a32007-02-10 01:45:59 -0800267 * (not including the trailing '\0'), use vscnprintf(). If the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 * return is greater than or equal to @size, the resulting
269 * string is truncated.
270 *
271 * Call this function if you are already dealing with a va_list.
Robert P. J. Day72fd4a32007-02-10 01:45:59 -0800272 * You probably want snprintf() instead.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 */
274int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
275{
276 int len;
277 unsigned long long num;
278 int i, base;
279 char *str, *end, c;
280 const char *s;
281
282 int flags; /* flags to number() */
283
284 int field_width; /* width of output field */
285 int precision; /* min. # of digits for integers; max
286 number of chars for from string */
287 int qualifier; /* 'h', 'l', or 'L' for integer fields */
288 /* 'z' support added 23/7/1999 S.H. */
289 /* 'z' changed to 'Z' --davidm 1/25/99 */
Al Viro80322302005-08-23 22:48:17 +0100290 /* 't' added for ptrdiff_t */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700292 /* Reject out-of-range values early. Large positive sizes are
293 used for unknown buffer sizes. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (unlikely((int) size < 0)) {
295 /* There can be only one.. */
Denis Vlasenkob39a7342007-07-15 23:41:54 -0700296 static char warn = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 WARN_ON(warn);
298 warn = 0;
299 return 0;
300 }
301
302 str = buf;
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700303 end = buf + size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700305 /* Make sure end is always >= buf */
306 if (end < buf) {
307 end = ((void *)-1);
308 size = end - buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 }
310
311 for (; *fmt ; ++fmt) {
312 if (*fmt != '%') {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700313 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 *str = *fmt;
315 ++str;
316 continue;
317 }
318
319 /* process flags */
320 flags = 0;
321 repeat:
322 ++fmt; /* this also skips first '%' */
323 switch (*fmt) {
324 case '-': flags |= LEFT; goto repeat;
325 case '+': flags |= PLUS; goto repeat;
326 case ' ': flags |= SPACE; goto repeat;
327 case '#': flags |= SPECIAL; goto repeat;
328 case '0': flags |= ZEROPAD; goto repeat;
329 }
330
331 /* get field width */
332 field_width = -1;
333 if (isdigit(*fmt))
334 field_width = skip_atoi(&fmt);
335 else if (*fmt == '*') {
336 ++fmt;
337 /* it's the next argument */
338 field_width = va_arg(args, int);
339 if (field_width < 0) {
340 field_width = -field_width;
341 flags |= LEFT;
342 }
343 }
344
345 /* get the precision */
346 precision = -1;
347 if (*fmt == '.') {
348 ++fmt;
349 if (isdigit(*fmt))
350 precision = skip_atoi(&fmt);
351 else if (*fmt == '*') {
352 ++fmt;
353 /* it's the next argument */
354 precision = va_arg(args, int);
355 }
356 if (precision < 0)
357 precision = 0;
358 }
359
360 /* get the conversion qualifier */
361 qualifier = -1;
362 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
Al Viro80322302005-08-23 22:48:17 +0100363 *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 qualifier = *fmt;
365 ++fmt;
366 if (qualifier == 'l' && *fmt == 'l') {
367 qualifier = 'L';
368 ++fmt;
369 }
370 }
371
372 /* default base */
373 base = 10;
374
375 switch (*fmt) {
376 case 'c':
377 if (!(flags & LEFT)) {
378 while (--field_width > 0) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700379 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 *str = ' ';
381 ++str;
382 }
383 }
384 c = (unsigned char) va_arg(args, int);
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700385 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 *str = c;
387 ++str;
388 while (--field_width > 0) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700389 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 *str = ' ';
391 ++str;
392 }
393 continue;
394
395 case 's':
396 s = va_arg(args, char *);
397 if ((unsigned long)s < PAGE_SIZE)
398 s = "<NULL>";
399
400 len = strnlen(s, precision);
401
402 if (!(flags & LEFT)) {
403 while (len < field_width--) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700404 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 *str = ' ';
406 ++str;
407 }
408 }
409 for (i = 0; i < len; ++i) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700410 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 *str = *s;
412 ++str; ++s;
413 }
414 while (len < field_width--) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700415 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 *str = ' ';
417 ++str;
418 }
419 continue;
420
421 case 'p':
422 if (field_width == -1) {
423 field_width = 2*sizeof(void *);
424 flags |= ZEROPAD;
425 }
426 str = number(str, end,
427 (unsigned long) va_arg(args, void *),
428 16, field_width, precision, flags);
429 continue;
430
431
432 case 'n':
433 /* FIXME:
434 * What does C99 say about the overflow case here? */
435 if (qualifier == 'l') {
436 long * ip = va_arg(args, long *);
437 *ip = (str - buf);
438 } else if (qualifier == 'Z' || qualifier == 'z') {
439 size_t * ip = va_arg(args, size_t *);
440 *ip = (str - buf);
441 } else {
442 int * ip = va_arg(args, int *);
443 *ip = (str - buf);
444 }
445 continue;
446
447 case '%':
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700448 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 *str = '%';
450 ++str;
451 continue;
452
453 /* integer number formats - set up the flags and "break" */
454 case 'o':
455 base = 8;
456 break;
457
458 case 'X':
459 flags |= LARGE;
460 case 'x':
461 base = 16;
462 break;
463
464 case 'd':
465 case 'i':
466 flags |= SIGN;
467 case 'u':
468 break;
469
470 default:
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700471 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 *str = '%';
473 ++str;
474 if (*fmt) {
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700475 if (str < end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 *str = *fmt;
477 ++str;
478 } else {
479 --fmt;
480 }
481 continue;
482 }
483 if (qualifier == 'L')
484 num = va_arg(args, long long);
485 else if (qualifier == 'l') {
486 num = va_arg(args, unsigned long);
487 if (flags & SIGN)
488 num = (signed long) num;
489 } else if (qualifier == 'Z' || qualifier == 'z') {
490 num = va_arg(args, size_t);
Al Viro80322302005-08-23 22:48:17 +0100491 } else if (qualifier == 't') {
492 num = va_arg(args, ptrdiff_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 } else if (qualifier == 'h') {
494 num = (unsigned short) va_arg(args, int);
495 if (flags & SIGN)
496 num = (signed short) num;
497 } else {
498 num = va_arg(args, unsigned int);
499 if (flags & SIGN)
500 num = (signed int) num;
501 }
502 str = number(str, end, num, base,
503 field_width, precision, flags);
504 }
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700505 if (size > 0) {
506 if (str < end)
507 *str = '\0';
508 else
Linus Torvalds0a6047e2006-06-28 17:09:34 -0700509 end[-1] = '\0';
Jeremy Fitzhardingef7969372006-06-25 05:49:17 -0700510 }
511 /* the trailing null byte doesn't count towards the total */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return str-buf;
513}
514
515EXPORT_SYMBOL(vsnprintf);
516
517/**
518 * vscnprintf - Format a string and place it in a buffer
519 * @buf: The buffer to place the result into
520 * @size: The size of the buffer, including the trailing null space
521 * @fmt: The format string to use
522 * @args: Arguments for the format string
523 *
524 * The return value is the number of characters which have been written into
525 * the @buf not including the trailing '\0'. If @size is <= 0 the function
526 * returns 0.
527 *
528 * Call this function if you are already dealing with a va_list.
Robert P. J. Day72fd4a32007-02-10 01:45:59 -0800529 * You probably want scnprintf() instead.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 */
531int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
532{
533 int i;
534
535 i=vsnprintf(buf,size,fmt,args);
536 return (i >= size) ? (size - 1) : i;
537}
538
539EXPORT_SYMBOL(vscnprintf);
540
541/**
542 * snprintf - Format a string and place it in a buffer
543 * @buf: The buffer to place the result into
544 * @size: The size of the buffer, including the trailing null space
545 * @fmt: The format string to use
546 * @...: Arguments for the format string
547 *
548 * The return value is the number of characters which would be
549 * generated for the given input, excluding the trailing null,
550 * as per ISO C99. If the return is greater than or equal to
551 * @size, the resulting string is truncated.
552 */
553int snprintf(char * buf, size_t size, const char *fmt, ...)
554{
555 va_list args;
556 int i;
557
558 va_start(args, fmt);
559 i=vsnprintf(buf,size,fmt,args);
560 va_end(args);
561 return i;
562}
563
564EXPORT_SYMBOL(snprintf);
565
566/**
567 * scnprintf - Format a string and place it in a buffer
568 * @buf: The buffer to place the result into
569 * @size: The size of the buffer, including the trailing null space
570 * @fmt: The format string to use
571 * @...: Arguments for the format string
572 *
573 * The return value is the number of characters written into @buf not including
Martin Peschkeea6f3282007-02-12 00:51:56 -0800574 * the trailing '\0'. If @size is <= 0 the function returns 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 */
576
577int scnprintf(char * buf, size_t size, const char *fmt, ...)
578{
579 va_list args;
580 int i;
581
582 va_start(args, fmt);
583 i = vsnprintf(buf, size, fmt, args);
584 va_end(args);
585 return (i >= size) ? (size - 1) : i;
586}
587EXPORT_SYMBOL(scnprintf);
588
589/**
590 * vsprintf - Format a string and place it in a buffer
591 * @buf: The buffer to place the result into
592 * @fmt: The format string to use
593 * @args: Arguments for the format string
594 *
595 * The function returns the number of characters written
Robert P. J. Day72fd4a32007-02-10 01:45:59 -0800596 * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 * buffer overflows.
598 *
599 * Call this function if you are already dealing with a va_list.
Robert P. J. Day72fd4a32007-02-10 01:45:59 -0800600 * You probably want sprintf() instead.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 */
602int vsprintf(char *buf, const char *fmt, va_list args)
603{
604 return vsnprintf(buf, INT_MAX, fmt, args);
605}
606
607EXPORT_SYMBOL(vsprintf);
608
609/**
610 * sprintf - Format a string and place it in a buffer
611 * @buf: The buffer to place the result into
612 * @fmt: The format string to use
613 * @...: Arguments for the format string
614 *
615 * The function returns the number of characters written
Robert P. J. Day72fd4a32007-02-10 01:45:59 -0800616 * into @buf. Use snprintf() or scnprintf() in order to avoid
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 * buffer overflows.
618 */
619int sprintf(char * buf, const char *fmt, ...)
620{
621 va_list args;
622 int i;
623
624 va_start(args, fmt);
625 i=vsnprintf(buf, INT_MAX, fmt, args);
626 va_end(args);
627 return i;
628}
629
630EXPORT_SYMBOL(sprintf);
631
632/**
633 * vsscanf - Unformat a buffer into a list of arguments
634 * @buf: input buffer
635 * @fmt: format of buffer
636 * @args: arguments
637 */
638int vsscanf(const char * buf, const char * fmt, va_list args)
639{
640 const char *str = buf;
641 char *next;
642 char digit;
643 int num = 0;
644 int qualifier;
645 int base;
646 int field_width;
647 int is_sign = 0;
648
649 while(*fmt && *str) {
650 /* skip any white space in format */
651 /* white space in format matchs any amount of
652 * white space, including none, in the input.
653 */
654 if (isspace(*fmt)) {
655 while (isspace(*fmt))
656 ++fmt;
657 while (isspace(*str))
658 ++str;
659 }
660
661 /* anything that is not a conversion must match exactly */
662 if (*fmt != '%' && *fmt) {
663 if (*fmt++ != *str++)
664 break;
665 continue;
666 }
667
668 if (!*fmt)
669 break;
670 ++fmt;
671
672 /* skip this conversion.
673 * advance both strings to next white space
674 */
675 if (*fmt == '*') {
676 while (!isspace(*fmt) && *fmt)
677 fmt++;
678 while (!isspace(*str) && *str)
679 str++;
680 continue;
681 }
682
683 /* get field width */
684 field_width = -1;
685 if (isdigit(*fmt))
686 field_width = skip_atoi(&fmt);
687
688 /* get conversion qualifier */
689 qualifier = -1;
690 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
691 *fmt == 'Z' || *fmt == 'z') {
692 qualifier = *fmt++;
693 if (unlikely(qualifier == *fmt)) {
694 if (qualifier == 'h') {
695 qualifier = 'H';
696 fmt++;
697 } else if (qualifier == 'l') {
698 qualifier = 'L';
699 fmt++;
700 }
701 }
702 }
703 base = 10;
704 is_sign = 0;
705
706 if (!*fmt || !*str)
707 break;
708
709 switch(*fmt++) {
710 case 'c':
711 {
712 char *s = (char *) va_arg(args,char*);
713 if (field_width == -1)
714 field_width = 1;
715 do {
716 *s++ = *str++;
717 } while (--field_width > 0 && *str);
718 num++;
719 }
720 continue;
721 case 's':
722 {
723 char *s = (char *) va_arg(args, char *);
724 if(field_width == -1)
725 field_width = INT_MAX;
726 /* first, skip leading white space in buffer */
727 while (isspace(*str))
728 str++;
729
730 /* now copy until next white space */
731 while (*str && !isspace(*str) && field_width--) {
732 *s++ = *str++;
733 }
734 *s = '\0';
735 num++;
736 }
737 continue;
738 case 'n':
739 /* return number of characters read so far */
740 {
741 int *i = (int *)va_arg(args,int*);
742 *i = str - buf;
743 }
744 continue;
745 case 'o':
746 base = 8;
747 break;
748 case 'x':
749 case 'X':
750 base = 16;
751 break;
752 case 'i':
753 base = 0;
754 case 'd':
755 is_sign = 1;
756 case 'u':
757 break;
758 case '%':
759 /* looking for '%' in str */
760 if (*str++ != '%')
761 return num;
762 continue;
763 default:
764 /* invalid format; stop here */
765 return num;
766 }
767
768 /* have some sort of integer conversion.
769 * first, skip white space in buffer.
770 */
771 while (isspace(*str))
772 str++;
773
774 digit = *str;
775 if (is_sign && digit == '-')
776 digit = *(str + 1);
777
778 if (!digit
779 || (base == 16 && !isxdigit(digit))
780 || (base == 10 && !isdigit(digit))
781 || (base == 8 && (!isdigit(digit) || digit > '7'))
782 || (base == 0 && !isdigit(digit)))
783 break;
784
785 switch(qualifier) {
786 case 'H': /* that's 'hh' in format */
787 if (is_sign) {
788 signed char *s = (signed char *) va_arg(args,signed char *);
789 *s = (signed char) simple_strtol(str,&next,base);
790 } else {
791 unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
792 *s = (unsigned char) simple_strtoul(str, &next, base);
793 }
794 break;
795 case 'h':
796 if (is_sign) {
797 short *s = (short *) va_arg(args,short *);
798 *s = (short) simple_strtol(str,&next,base);
799 } else {
800 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
801 *s = (unsigned short) simple_strtoul(str, &next, base);
802 }
803 break;
804 case 'l':
805 if (is_sign) {
806 long *l = (long *) va_arg(args,long *);
807 *l = simple_strtol(str,&next,base);
808 } else {
809 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
810 *l = simple_strtoul(str,&next,base);
811 }
812 break;
813 case 'L':
814 if (is_sign) {
815 long long *l = (long long*) va_arg(args,long long *);
816 *l = simple_strtoll(str,&next,base);
817 } else {
818 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
819 *l = simple_strtoull(str,&next,base);
820 }
821 break;
822 case 'Z':
823 case 'z':
824 {
825 size_t *s = (size_t*) va_arg(args,size_t*);
826 *s = (size_t) simple_strtoul(str,&next,base);
827 }
828 break;
829 default:
830 if (is_sign) {
831 int *i = (int *) va_arg(args, int*);
832 *i = (int) simple_strtol(str,&next,base);
833 } else {
834 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
835 *i = (unsigned int) simple_strtoul(str,&next,base);
836 }
837 break;
838 }
839 num++;
840
841 if (!next)
842 break;
843 str = next;
844 }
Johannes Bergc6b40d12007-05-08 00:27:20 -0700845
846 /*
847 * Now we've come all the way through so either the input string or the
848 * format ended. In the former case, there can be a %n at the current
849 * position in the format that needs to be filled.
850 */
851 if (*fmt == '%' && *(fmt + 1) == 'n') {
852 int *p = (int *)va_arg(args, int *);
853 *p = str - buf;
854 }
855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return num;
857}
858
859EXPORT_SYMBOL(vsscanf);
860
861/**
862 * sscanf - Unformat a buffer into a list of arguments
863 * @buf: input buffer
864 * @fmt: formatting of buffer
865 * @...: resulting arguments
866 */
867int sscanf(const char * buf, const char * fmt, ...)
868{
869 va_list args;
870 int i;
871
872 va_start(args,fmt);
873 i = vsscanf(buf,fmt,args);
874 va_end(args);
875 return i;
876}
877
878EXPORT_SYMBOL(sscanf);
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700879
880
881/* Simplified asprintf. */
Jeremy Fitzhardinge11443ec2007-04-30 15:09:56 -0700882char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700883{
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700884 unsigned int len;
885 char *p;
Jeremy Fitzhardinge11443ec2007-04-30 15:09:56 -0700886 va_list aq;
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700887
Jeremy Fitzhardinge11443ec2007-04-30 15:09:56 -0700888 va_copy(aq, ap);
889 len = vsnprintf(NULL, 0, fmt, aq);
890 va_end(aq);
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700891
892 p = kmalloc(len+1, gfp);
893 if (!p)
894 return NULL;
Jeremy Fitzhardinge11443ec2007-04-30 15:09:56 -0700895
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700896 vsnprintf(p, len+1, fmt, ap);
Jeremy Fitzhardinge11443ec2007-04-30 15:09:56 -0700897
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700898 return p;
899}
Jeremy Fitzhardinge11443ec2007-04-30 15:09:56 -0700900EXPORT_SYMBOL(kvasprintf);
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700901
Jeremy Fitzhardinge11443ec2007-04-30 15:09:56 -0700902char *kasprintf(gfp_t gfp, const char *fmt, ...)
903{
904 va_list ap;
905 char *p;
906
907 va_start(ap, fmt);
908 p = kvasprintf(gfp, fmt, ap);
909 va_end(ap);
910
911 return p;
912}
Jeremy Fitzhardingee9059142006-06-25 05:49:17 -0700913EXPORT_SYMBOL(kasprintf);