ia64/linux-2.6.18-xen.hg

annotate lib/vsprintf.c @ 782:9ab1c319531f

merge with linux-2.6.18-xen.hg
author Isaku Yamahata <yamahata@valinux.co.jp>
date Wed Jan 28 13:07:23 2009 +0900 (2009-01-28)
parents 831230e53067
children
rev   line source
ian@0 1 /*
ian@0 2 * linux/lib/vsprintf.c
ian@0 3 *
ian@0 4 * Copyright (C) 1991, 1992 Linus Torvalds
ian@0 5 */
ian@0 6
ian@0 7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
ian@0 8 /*
ian@0 9 * Wirzenius wrote this portably, Torvalds fucked it up :-)
ian@0 10 */
ian@0 11
ian@0 12 /*
ian@0 13 * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
ian@0 14 * - changed to provide snprintf and vsnprintf functions
ian@0 15 * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
ian@0 16 * - scnprintf and vscnprintf
ian@0 17 */
ian@0 18
ian@0 19 #include <stdarg.h>
ian@0 20 #include <linux/module.h>
ian@0 21 #include <linux/types.h>
ian@0 22 #include <linux/string.h>
ian@0 23 #include <linux/ctype.h>
ian@0 24 #include <linux/kernel.h>
ian@0 25
ian@0 26 #include <asm/page.h> /* for PAGE_SIZE */
ian@0 27 #include <asm/div64.h>
ian@0 28
ian@0 29 /**
ian@0 30 * simple_strtoul - convert a string to an unsigned long
ian@0 31 * @cp: The start of the string
ian@0 32 * @endp: A pointer to the end of the parsed string will be placed here
ian@0 33 * @base: The number base to use
ian@0 34 */
ian@0 35 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
ian@0 36 {
ian@0 37 unsigned long result = 0,value;
ian@0 38
ian@0 39 if (!base) {
ian@0 40 base = 10;
ian@0 41 if (*cp == '0') {
ian@0 42 base = 8;
ian@0 43 cp++;
ian@0 44 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
ian@0 45 cp++;
ian@0 46 base = 16;
ian@0 47 }
ian@0 48 }
ian@0 49 } else if (base == 16) {
ian@0 50 if (cp[0] == '0' && toupper(cp[1]) == 'X')
ian@0 51 cp += 2;
ian@0 52 }
ian@0 53 while (isxdigit(*cp) &&
ian@0 54 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
ian@0 55 result = result*base + value;
ian@0 56 cp++;
ian@0 57 }
ian@0 58 if (endp)
ian@0 59 *endp = (char *)cp;
ian@0 60 return result;
ian@0 61 }
ian@0 62
ian@0 63 EXPORT_SYMBOL(simple_strtoul);
ian@0 64
ian@0 65 /**
ian@0 66 * simple_strtol - convert a string to a signed long
ian@0 67 * @cp: The start of the string
ian@0 68 * @endp: A pointer to the end of the parsed string will be placed here
ian@0 69 * @base: The number base to use
ian@0 70 */
ian@0 71 long simple_strtol(const char *cp,char **endp,unsigned int base)
ian@0 72 {
ian@0 73 if(*cp=='-')
ian@0 74 return -simple_strtoul(cp+1,endp,base);
ian@0 75 return simple_strtoul(cp,endp,base);
ian@0 76 }
ian@0 77
ian@0 78 EXPORT_SYMBOL(simple_strtol);
ian@0 79
ian@0 80 /**
ian@0 81 * simple_strtoull - convert a string to an unsigned long long
ian@0 82 * @cp: The start of the string
ian@0 83 * @endp: A pointer to the end of the parsed string will be placed here
ian@0 84 * @base: The number base to use
ian@0 85 */
ian@0 86 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
ian@0 87 {
ian@0 88 unsigned long long result = 0,value;
ian@0 89
ian@0 90 if (!base) {
ian@0 91 base = 10;
ian@0 92 if (*cp == '0') {
ian@0 93 base = 8;
ian@0 94 cp++;
ian@0 95 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
ian@0 96 cp++;
ian@0 97 base = 16;
ian@0 98 }
ian@0 99 }
ian@0 100 } else if (base == 16) {
ian@0 101 if (cp[0] == '0' && toupper(cp[1]) == 'X')
ian@0 102 cp += 2;
ian@0 103 }
ian@0 104 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
ian@0 105 ? toupper(*cp) : *cp)-'A'+10) < base) {
ian@0 106 result = result*base + value;
ian@0 107 cp++;
ian@0 108 }
ian@0 109 if (endp)
ian@0 110 *endp = (char *)cp;
ian@0 111 return result;
ian@0 112 }
ian@0 113
ian@0 114 EXPORT_SYMBOL(simple_strtoull);
ian@0 115
ian@0 116 /**
ian@0 117 * simple_strtoll - convert a string to a signed long long
ian@0 118 * @cp: The start of the string
ian@0 119 * @endp: A pointer to the end of the parsed string will be placed here
ian@0 120 * @base: The number base to use
ian@0 121 */
ian@0 122 long long simple_strtoll(const char *cp,char **endp,unsigned int base)
ian@0 123 {
ian@0 124 if(*cp=='-')
ian@0 125 return -simple_strtoull(cp+1,endp,base);
ian@0 126 return simple_strtoull(cp,endp,base);
ian@0 127 }
ian@0 128
ian@0 129 static int skip_atoi(const char **s)
ian@0 130 {
ian@0 131 int i=0;
ian@0 132
ian@0 133 while (isdigit(**s))
ian@0 134 i = i*10 + *((*s)++) - '0';
ian@0 135 return i;
ian@0 136 }
ian@0 137
ian@0 138 #define ZEROPAD 1 /* pad with zero */
ian@0 139 #define SIGN 2 /* unsigned/signed long */
ian@0 140 #define PLUS 4 /* show plus */
ian@0 141 #define SPACE 8 /* space if plus */
ian@0 142 #define LEFT 16 /* left justified */
ian@0 143 #define SPECIAL 32 /* 0x */
ian@0 144 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
ian@0 145
ian@0 146 static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
ian@0 147 {
ian@0 148 char c,sign,tmp[66];
ian@0 149 const char *digits;
ian@0 150 static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
ian@0 151 static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
ian@0 152 int i;
ian@0 153
ian@0 154 digits = (type & LARGE) ? large_digits : small_digits;
ian@0 155 if (type & LEFT)
ian@0 156 type &= ~ZEROPAD;
ian@0 157 if (base < 2 || base > 36)
ian@0 158 return NULL;
ian@0 159 c = (type & ZEROPAD) ? '0' : ' ';
ian@0 160 sign = 0;
ian@0 161 if (type & SIGN) {
ian@0 162 if ((signed long long) num < 0) {
ian@0 163 sign = '-';
ian@0 164 num = - (signed long long) num;
ian@0 165 size--;
ian@0 166 } else if (type & PLUS) {
ian@0 167 sign = '+';
ian@0 168 size--;
ian@0 169 } else if (type & SPACE) {
ian@0 170 sign = ' ';
ian@0 171 size--;
ian@0 172 }
ian@0 173 }
ian@0 174 if (type & SPECIAL) {
ian@0 175 if (base == 16)
ian@0 176 size -= 2;
ian@0 177 else if (base == 8)
ian@0 178 size--;
ian@0 179 }
ian@0 180 i = 0;
ian@0 181 if (num == 0)
ian@0 182 tmp[i++]='0';
ian@0 183 else while (num != 0)
ian@0 184 tmp[i++] = digits[do_div(num,base)];
ian@0 185 if (i > precision)
ian@0 186 precision = i;
ian@0 187 size -= precision;
ian@0 188 if (!(type&(ZEROPAD+LEFT))) {
ian@0 189 while(size-->0) {
ian@0 190 if (buf < end)
ian@0 191 *buf = ' ';
ian@0 192 ++buf;
ian@0 193 }
ian@0 194 }
ian@0 195 if (sign) {
ian@0 196 if (buf < end)
ian@0 197 *buf = sign;
ian@0 198 ++buf;
ian@0 199 }
ian@0 200 if (type & SPECIAL) {
ian@0 201 if (base==8) {
ian@0 202 if (buf < end)
ian@0 203 *buf = '0';
ian@0 204 ++buf;
ian@0 205 } else if (base==16) {
ian@0 206 if (buf < end)
ian@0 207 *buf = '0';
ian@0 208 ++buf;
ian@0 209 if (buf < end)
ian@0 210 *buf = digits[33];
ian@0 211 ++buf;
ian@0 212 }
ian@0 213 }
ian@0 214 if (!(type & LEFT)) {
ian@0 215 while (size-- > 0) {
ian@0 216 if (buf < end)
ian@0 217 *buf = c;
ian@0 218 ++buf;
ian@0 219 }
ian@0 220 }
ian@0 221 while (i < precision--) {
ian@0 222 if (buf < end)
ian@0 223 *buf = '0';
ian@0 224 ++buf;
ian@0 225 }
ian@0 226 while (i-- > 0) {
ian@0 227 if (buf < end)
ian@0 228 *buf = tmp[i];
ian@0 229 ++buf;
ian@0 230 }
ian@0 231 while (size-- > 0) {
ian@0 232 if (buf < end)
ian@0 233 *buf = ' ';
ian@0 234 ++buf;
ian@0 235 }
ian@0 236 return buf;
ian@0 237 }
ian@0 238
ian@0 239 /**
ian@0 240 * vsnprintf - Format a string and place it in a buffer
ian@0 241 * @buf: The buffer to place the result into
ian@0 242 * @size: The size of the buffer, including the trailing null space
ian@0 243 * @fmt: The format string to use
ian@0 244 * @args: Arguments for the format string
ian@0 245 *
ian@0 246 * The return value is the number of characters which would
ian@0 247 * be generated for the given input, excluding the trailing
ian@0 248 * '\0', as per ISO C99. If you want to have the exact
ian@0 249 * number of characters written into @buf as return value
ian@0 250 * (not including the trailing '\0'), use vscnprintf. If the
ian@0 251 * return is greater than or equal to @size, the resulting
ian@0 252 * string is truncated.
ian@0 253 *
ian@0 254 * Call this function if you are already dealing with a va_list.
ian@0 255 * You probably want snprintf instead.
ian@0 256 */
ian@0 257 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
ian@0 258 {
ian@0 259 int len;
ian@0 260 unsigned long long num;
ian@0 261 int i, base;
ian@0 262 char *str, *end, c;
ian@0 263 const char *s;
ian@0 264
ian@0 265 int flags; /* flags to number() */
ian@0 266
ian@0 267 int field_width; /* width of output field */
ian@0 268 int precision; /* min. # of digits for integers; max
ian@0 269 number of chars for from string */
ian@0 270 int qualifier; /* 'h', 'l', or 'L' for integer fields */
ian@0 271 /* 'z' support added 23/7/1999 S.H. */
ian@0 272 /* 'z' changed to 'Z' --davidm 1/25/99 */
ian@0 273 /* 't' added for ptrdiff_t */
ian@0 274
ian@0 275 /* Reject out-of-range values early. Large positive sizes are
ian@0 276 used for unknown buffer sizes. */
ian@0 277 if (unlikely((int) size < 0)) {
ian@0 278 /* There can be only one.. */
ian@0 279 static int warn = 1;
ian@0 280 WARN_ON(warn);
ian@0 281 warn = 0;
ian@0 282 return 0;
ian@0 283 }
ian@0 284
ian@0 285 str = buf;
ian@0 286 end = buf + size;
ian@0 287
ian@0 288 /* Make sure end is always >= buf */
ian@0 289 if (end < buf) {
ian@0 290 end = ((void *)-1);
ian@0 291 size = end - buf;
ian@0 292 }
ian@0 293
ian@0 294 for (; *fmt ; ++fmt) {
ian@0 295 if (*fmt != '%') {
ian@0 296 if (str < end)
ian@0 297 *str = *fmt;
ian@0 298 ++str;
ian@0 299 continue;
ian@0 300 }
ian@0 301
ian@0 302 /* process flags */
ian@0 303 flags = 0;
ian@0 304 repeat:
ian@0 305 ++fmt; /* this also skips first '%' */
ian@0 306 switch (*fmt) {
ian@0 307 case '-': flags |= LEFT; goto repeat;
ian@0 308 case '+': flags |= PLUS; goto repeat;
ian@0 309 case ' ': flags |= SPACE; goto repeat;
ian@0 310 case '#': flags |= SPECIAL; goto repeat;
ian@0 311 case '0': flags |= ZEROPAD; goto repeat;
ian@0 312 }
ian@0 313
ian@0 314 /* get field width */
ian@0 315 field_width = -1;
ian@0 316 if (isdigit(*fmt))
ian@0 317 field_width = skip_atoi(&fmt);
ian@0 318 else if (*fmt == '*') {
ian@0 319 ++fmt;
ian@0 320 /* it's the next argument */
ian@0 321 field_width = va_arg(args, int);
ian@0 322 if (field_width < 0) {
ian@0 323 field_width = -field_width;
ian@0 324 flags |= LEFT;
ian@0 325 }
ian@0 326 }
ian@0 327
ian@0 328 /* get the precision */
ian@0 329 precision = -1;
ian@0 330 if (*fmt == '.') {
ian@0 331 ++fmt;
ian@0 332 if (isdigit(*fmt))
ian@0 333 precision = skip_atoi(&fmt);
ian@0 334 else if (*fmt == '*') {
ian@0 335 ++fmt;
ian@0 336 /* it's the next argument */
ian@0 337 precision = va_arg(args, int);
ian@0 338 }
ian@0 339 if (precision < 0)
ian@0 340 precision = 0;
ian@0 341 }
ian@0 342
ian@0 343 /* get the conversion qualifier */
ian@0 344 qualifier = -1;
ian@0 345 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
ian@0 346 *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
ian@0 347 qualifier = *fmt;
ian@0 348 ++fmt;
ian@0 349 if (qualifier == 'l' && *fmt == 'l') {
ian@0 350 qualifier = 'L';
ian@0 351 ++fmt;
ian@0 352 }
ian@0 353 }
ian@0 354
ian@0 355 /* default base */
ian@0 356 base = 10;
ian@0 357
ian@0 358 switch (*fmt) {
ian@0 359 case 'c':
ian@0 360 if (!(flags & LEFT)) {
ian@0 361 while (--field_width > 0) {
ian@0 362 if (str < end)
ian@0 363 *str = ' ';
ian@0 364 ++str;
ian@0 365 }
ian@0 366 }
ian@0 367 c = (unsigned char) va_arg(args, int);
ian@0 368 if (str < end)
ian@0 369 *str = c;
ian@0 370 ++str;
ian@0 371 while (--field_width > 0) {
ian@0 372 if (str < end)
ian@0 373 *str = ' ';
ian@0 374 ++str;
ian@0 375 }
ian@0 376 continue;
ian@0 377
ian@0 378 case 's':
ian@0 379 s = va_arg(args, char *);
ian@0 380 if ((unsigned long)s < PAGE_SIZE)
ian@0 381 s = "<NULL>";
ian@0 382
ian@0 383 len = strnlen(s, precision);
ian@0 384
ian@0 385 if (!(flags & LEFT)) {
ian@0 386 while (len < field_width--) {
ian@0 387 if (str < end)
ian@0 388 *str = ' ';
ian@0 389 ++str;
ian@0 390 }
ian@0 391 }
ian@0 392 for (i = 0; i < len; ++i) {
ian@0 393 if (str < end)
ian@0 394 *str = *s;
ian@0 395 ++str; ++s;
ian@0 396 }
ian@0 397 while (len < field_width--) {
ian@0 398 if (str < end)
ian@0 399 *str = ' ';
ian@0 400 ++str;
ian@0 401 }
ian@0 402 continue;
ian@0 403
ian@0 404 case 'p':
ian@0 405 if (field_width == -1) {
ian@0 406 field_width = 2*sizeof(void *);
ian@0 407 flags |= ZEROPAD;
ian@0 408 }
ian@0 409 str = number(str, end,
ian@0 410 (unsigned long) va_arg(args, void *),
ian@0 411 16, field_width, precision, flags);
ian@0 412 continue;
ian@0 413
ian@0 414
ian@0 415 case 'n':
ian@0 416 /* FIXME:
ian@0 417 * What does C99 say about the overflow case here? */
ian@0 418 if (qualifier == 'l') {
ian@0 419 long * ip = va_arg(args, long *);
ian@0 420 *ip = (str - buf);
ian@0 421 } else if (qualifier == 'Z' || qualifier == 'z') {
ian@0 422 size_t * ip = va_arg(args, size_t *);
ian@0 423 *ip = (str - buf);
ian@0 424 } else {
ian@0 425 int * ip = va_arg(args, int *);
ian@0 426 *ip = (str - buf);
ian@0 427 }
ian@0 428 continue;
ian@0 429
ian@0 430 case '%':
ian@0 431 if (str < end)
ian@0 432 *str = '%';
ian@0 433 ++str;
ian@0 434 continue;
ian@0 435
ian@0 436 /* integer number formats - set up the flags and "break" */
ian@0 437 case 'o':
ian@0 438 base = 8;
ian@0 439 break;
ian@0 440
ian@0 441 case 'X':
ian@0 442 flags |= LARGE;
ian@0 443 case 'x':
ian@0 444 base = 16;
ian@0 445 break;
ian@0 446
ian@0 447 case 'd':
ian@0 448 case 'i':
ian@0 449 flags |= SIGN;
ian@0 450 case 'u':
ian@0 451 break;
ian@0 452
ian@0 453 default:
ian@0 454 if (str < end)
ian@0 455 *str = '%';
ian@0 456 ++str;
ian@0 457 if (*fmt) {
ian@0 458 if (str < end)
ian@0 459 *str = *fmt;
ian@0 460 ++str;
ian@0 461 } else {
ian@0 462 --fmt;
ian@0 463 }
ian@0 464 continue;
ian@0 465 }
ian@0 466 if (qualifier == 'L')
ian@0 467 num = va_arg(args, long long);
ian@0 468 else if (qualifier == 'l') {
ian@0 469 num = va_arg(args, unsigned long);
ian@0 470 if (flags & SIGN)
ian@0 471 num = (signed long) num;
ian@0 472 } else if (qualifier == 'Z' || qualifier == 'z') {
ian@0 473 num = va_arg(args, size_t);
ian@0 474 } else if (qualifier == 't') {
ian@0 475 num = va_arg(args, ptrdiff_t);
ian@0 476 } else if (qualifier == 'h') {
ian@0 477 num = (unsigned short) va_arg(args, int);
ian@0 478 if (flags & SIGN)
ian@0 479 num = (signed short) num;
ian@0 480 } else {
ian@0 481 num = va_arg(args, unsigned int);
ian@0 482 if (flags & SIGN)
ian@0 483 num = (signed int) num;
ian@0 484 }
ian@0 485 str = number(str, end, num, base,
ian@0 486 field_width, precision, flags);
ian@0 487 }
ian@0 488 if (size > 0) {
ian@0 489 if (str < end)
ian@0 490 *str = '\0';
ian@0 491 else
ian@0 492 end[-1] = '\0';
ian@0 493 }
ian@0 494 /* the trailing null byte doesn't count towards the total */
ian@0 495 return str-buf;
ian@0 496 }
ian@0 497
ian@0 498 EXPORT_SYMBOL(vsnprintf);
ian@0 499
ian@0 500 /**
ian@0 501 * vscnprintf - Format a string and place it in a buffer
ian@0 502 * @buf: The buffer to place the result into
ian@0 503 * @size: The size of the buffer, including the trailing null space
ian@0 504 * @fmt: The format string to use
ian@0 505 * @args: Arguments for the format string
ian@0 506 *
ian@0 507 * The return value is the number of characters which have been written into
ian@0 508 * the @buf not including the trailing '\0'. If @size is <= 0 the function
ian@0 509 * returns 0.
ian@0 510 *
ian@0 511 * Call this function if you are already dealing with a va_list.
ian@0 512 * You probably want scnprintf instead.
ian@0 513 */
ian@0 514 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
ian@0 515 {
ian@0 516 int i;
ian@0 517
ian@0 518 i=vsnprintf(buf,size,fmt,args);
ian@0 519 return (i >= size) ? (size - 1) : i;
ian@0 520 }
ian@0 521
ian@0 522 EXPORT_SYMBOL(vscnprintf);
ian@0 523
ian@0 524 /**
ian@0 525 * snprintf - Format a string and place it in a buffer
ian@0 526 * @buf: The buffer to place the result into
ian@0 527 * @size: The size of the buffer, including the trailing null space
ian@0 528 * @fmt: The format string to use
ian@0 529 * @...: Arguments for the format string
ian@0 530 *
ian@0 531 * The return value is the number of characters which would be
ian@0 532 * generated for the given input, excluding the trailing null,
ian@0 533 * as per ISO C99. If the return is greater than or equal to
ian@0 534 * @size, the resulting string is truncated.
ian@0 535 */
ian@0 536 int snprintf(char * buf, size_t size, const char *fmt, ...)
ian@0 537 {
ian@0 538 va_list args;
ian@0 539 int i;
ian@0 540
ian@0 541 va_start(args, fmt);
ian@0 542 i=vsnprintf(buf,size,fmt,args);
ian@0 543 va_end(args);
ian@0 544 return i;
ian@0 545 }
ian@0 546
ian@0 547 EXPORT_SYMBOL(snprintf);
ian@0 548
ian@0 549 /**
ian@0 550 * scnprintf - Format a string and place it in a buffer
ian@0 551 * @buf: The buffer to place the result into
ian@0 552 * @size: The size of the buffer, including the trailing null space
ian@0 553 * @fmt: The format string to use
ian@0 554 * @...: Arguments for the format string
ian@0 555 *
ian@0 556 * The return value is the number of characters written into @buf not including
ian@0 557 * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
ian@0 558 * greater than or equal to @size, the resulting string is truncated.
ian@0 559 */
ian@0 560
ian@0 561 int scnprintf(char * buf, size_t size, const char *fmt, ...)
ian@0 562 {
ian@0 563 va_list args;
ian@0 564 int i;
ian@0 565
ian@0 566 va_start(args, fmt);
ian@0 567 i = vsnprintf(buf, size, fmt, args);
ian@0 568 va_end(args);
ian@0 569 return (i >= size) ? (size - 1) : i;
ian@0 570 }
ian@0 571 EXPORT_SYMBOL(scnprintf);
ian@0 572
ian@0 573 /**
ian@0 574 * vsprintf - Format a string and place it in a buffer
ian@0 575 * @buf: The buffer to place the result into
ian@0 576 * @fmt: The format string to use
ian@0 577 * @args: Arguments for the format string
ian@0 578 *
ian@0 579 * The function returns the number of characters written
ian@0 580 * into @buf. Use vsnprintf or vscnprintf in order to avoid
ian@0 581 * buffer overflows.
ian@0 582 *
ian@0 583 * Call this function if you are already dealing with a va_list.
ian@0 584 * You probably want sprintf instead.
ian@0 585 */
ian@0 586 int vsprintf(char *buf, const char *fmt, va_list args)
ian@0 587 {
ian@0 588 return vsnprintf(buf, INT_MAX, fmt, args);
ian@0 589 }
ian@0 590
ian@0 591 EXPORT_SYMBOL(vsprintf);
ian@0 592
ian@0 593 /**
ian@0 594 * sprintf - Format a string and place it in a buffer
ian@0 595 * @buf: The buffer to place the result into
ian@0 596 * @fmt: The format string to use
ian@0 597 * @...: Arguments for the format string
ian@0 598 *
ian@0 599 * The function returns the number of characters written
ian@0 600 * into @buf. Use snprintf or scnprintf in order to avoid
ian@0 601 * buffer overflows.
ian@0 602 */
ian@0 603 int sprintf(char * buf, const char *fmt, ...)
ian@0 604 {
ian@0 605 va_list args;
ian@0 606 int i;
ian@0 607
ian@0 608 va_start(args, fmt);
ian@0 609 i=vsnprintf(buf, INT_MAX, fmt, args);
ian@0 610 va_end(args);
ian@0 611 return i;
ian@0 612 }
ian@0 613
ian@0 614 EXPORT_SYMBOL(sprintf);
ian@0 615
ian@0 616 /**
ian@0 617 * vsscanf - Unformat a buffer into a list of arguments
ian@0 618 * @buf: input buffer
ian@0 619 * @fmt: format of buffer
ian@0 620 * @args: arguments
ian@0 621 */
ian@0 622 int vsscanf(const char * buf, const char * fmt, va_list args)
ian@0 623 {
ian@0 624 const char *str = buf;
ian@0 625 char *next;
ian@0 626 char digit;
ian@0 627 int num = 0;
ian@0 628 int qualifier;
ian@0 629 int base;
ian@0 630 int field_width;
ian@0 631 int is_sign = 0;
ian@0 632
ian@0 633 while(*fmt && *str) {
ian@0 634 /* skip any white space in format */
ian@0 635 /* white space in format matchs any amount of
ian@0 636 * white space, including none, in the input.
ian@0 637 */
ian@0 638 if (isspace(*fmt)) {
ian@0 639 while (isspace(*fmt))
ian@0 640 ++fmt;
ian@0 641 while (isspace(*str))
ian@0 642 ++str;
ian@0 643 }
ian@0 644
ian@0 645 /* anything that is not a conversion must match exactly */
ian@0 646 if (*fmt != '%' && *fmt) {
ian@0 647 if (*fmt++ != *str++)
ian@0 648 break;
ian@0 649 continue;
ian@0 650 }
ian@0 651
ian@0 652 if (!*fmt)
ian@0 653 break;
ian@0 654 ++fmt;
ian@0 655
ian@0 656 /* skip this conversion.
ian@0 657 * advance both strings to next white space
ian@0 658 */
ian@0 659 if (*fmt == '*') {
ian@0 660 while (!isspace(*fmt) && *fmt)
ian@0 661 fmt++;
ian@0 662 while (!isspace(*str) && *str)
ian@0 663 str++;
ian@0 664 continue;
ian@0 665 }
ian@0 666
ian@0 667 /* get field width */
ian@0 668 field_width = -1;
ian@0 669 if (isdigit(*fmt))
ian@0 670 field_width = skip_atoi(&fmt);
ian@0 671
ian@0 672 /* get conversion qualifier */
ian@0 673 qualifier = -1;
ian@0 674 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
ian@0 675 *fmt == 'Z' || *fmt == 'z') {
ian@0 676 qualifier = *fmt++;
ian@0 677 if (unlikely(qualifier == *fmt)) {
ian@0 678 if (qualifier == 'h') {
ian@0 679 qualifier = 'H';
ian@0 680 fmt++;
ian@0 681 } else if (qualifier == 'l') {
ian@0 682 qualifier = 'L';
ian@0 683 fmt++;
ian@0 684 }
ian@0 685 }
ian@0 686 }
ian@0 687 base = 10;
ian@0 688 is_sign = 0;
ian@0 689
ian@0 690 if (!*fmt || !*str)
ian@0 691 break;
ian@0 692
ian@0 693 switch(*fmt++) {
ian@0 694 case 'c':
ian@0 695 {
ian@0 696 char *s = (char *) va_arg(args,char*);
ian@0 697 if (field_width == -1)
ian@0 698 field_width = 1;
ian@0 699 do {
ian@0 700 *s++ = *str++;
ian@0 701 } while (--field_width > 0 && *str);
ian@0 702 num++;
ian@0 703 }
ian@0 704 continue;
ian@0 705 case 's':
ian@0 706 {
ian@0 707 char *s = (char *) va_arg(args, char *);
ian@0 708 if(field_width == -1)
ian@0 709 field_width = INT_MAX;
ian@0 710 /* first, skip leading white space in buffer */
ian@0 711 while (isspace(*str))
ian@0 712 str++;
ian@0 713
ian@0 714 /* now copy until next white space */
ian@0 715 while (*str && !isspace(*str) && field_width--) {
ian@0 716 *s++ = *str++;
ian@0 717 }
ian@0 718 *s = '\0';
ian@0 719 num++;
ian@0 720 }
ian@0 721 continue;
ian@0 722 case 'n':
ian@0 723 /* return number of characters read so far */
ian@0 724 {
ian@0 725 int *i = (int *)va_arg(args,int*);
ian@0 726 *i = str - buf;
ian@0 727 }
ian@0 728 continue;
ian@0 729 case 'o':
ian@0 730 base = 8;
ian@0 731 break;
ian@0 732 case 'x':
ian@0 733 case 'X':
ian@0 734 base = 16;
ian@0 735 break;
ian@0 736 case 'i':
ian@0 737 base = 0;
ian@0 738 case 'd':
ian@0 739 is_sign = 1;
ian@0 740 case 'u':
ian@0 741 break;
ian@0 742 case '%':
ian@0 743 /* looking for '%' in str */
ian@0 744 if (*str++ != '%')
ian@0 745 return num;
ian@0 746 continue;
ian@0 747 default:
ian@0 748 /* invalid format; stop here */
ian@0 749 return num;
ian@0 750 }
ian@0 751
ian@0 752 /* have some sort of integer conversion.
ian@0 753 * first, skip white space in buffer.
ian@0 754 */
ian@0 755 while (isspace(*str))
ian@0 756 str++;
ian@0 757
ian@0 758 digit = *str;
ian@0 759 if (is_sign && digit == '-')
ian@0 760 digit = *(str + 1);
ian@0 761
ian@0 762 if (!digit
ian@0 763 || (base == 16 && !isxdigit(digit))
ian@0 764 || (base == 10 && !isdigit(digit))
ian@0 765 || (base == 8 && (!isdigit(digit) || digit > '7'))
ian@0 766 || (base == 0 && !isdigit(digit)))
ian@0 767 break;
ian@0 768
ian@0 769 switch(qualifier) {
ian@0 770 case 'H': /* that's 'hh' in format */
ian@0 771 if (is_sign) {
ian@0 772 signed char *s = (signed char *) va_arg(args,signed char *);
ian@0 773 *s = (signed char) simple_strtol(str,&next,base);
ian@0 774 } else {
ian@0 775 unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
ian@0 776 *s = (unsigned char) simple_strtoul(str, &next, base);
ian@0 777 }
ian@0 778 break;
ian@0 779 case 'h':
ian@0 780 if (is_sign) {
ian@0 781 short *s = (short *) va_arg(args,short *);
ian@0 782 *s = (short) simple_strtol(str,&next,base);
ian@0 783 } else {
ian@0 784 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
ian@0 785 *s = (unsigned short) simple_strtoul(str, &next, base);
ian@0 786 }
ian@0 787 break;
ian@0 788 case 'l':
ian@0 789 if (is_sign) {
ian@0 790 long *l = (long *) va_arg(args,long *);
ian@0 791 *l = simple_strtol(str,&next,base);
ian@0 792 } else {
ian@0 793 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
ian@0 794 *l = simple_strtoul(str,&next,base);
ian@0 795 }
ian@0 796 break;
ian@0 797 case 'L':
ian@0 798 if (is_sign) {
ian@0 799 long long *l = (long long*) va_arg(args,long long *);
ian@0 800 *l = simple_strtoll(str,&next,base);
ian@0 801 } else {
ian@0 802 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
ian@0 803 *l = simple_strtoull(str,&next,base);
ian@0 804 }
ian@0 805 break;
ian@0 806 case 'Z':
ian@0 807 case 'z':
ian@0 808 {
ian@0 809 size_t *s = (size_t*) va_arg(args,size_t*);
ian@0 810 *s = (size_t) simple_strtoul(str,&next,base);
ian@0 811 }
ian@0 812 break;
ian@0 813 default:
ian@0 814 if (is_sign) {
ian@0 815 int *i = (int *) va_arg(args, int*);
ian@0 816 *i = (int) simple_strtol(str,&next,base);
ian@0 817 } else {
ian@0 818 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
ian@0 819 *i = (unsigned int) simple_strtoul(str,&next,base);
ian@0 820 }
ian@0 821 break;
ian@0 822 }
ian@0 823 num++;
ian@0 824
ian@0 825 if (!next)
ian@0 826 break;
ian@0 827 str = next;
ian@0 828 }
ian@0 829 return num;
ian@0 830 }
ian@0 831
ian@0 832 EXPORT_SYMBOL(vsscanf);
ian@0 833
ian@0 834 /**
ian@0 835 * sscanf - Unformat a buffer into a list of arguments
ian@0 836 * @buf: input buffer
ian@0 837 * @fmt: formatting of buffer
ian@0 838 * @...: resulting arguments
ian@0 839 */
ian@0 840 int sscanf(const char * buf, const char * fmt, ...)
ian@0 841 {
ian@0 842 va_list args;
ian@0 843 int i;
ian@0 844
ian@0 845 va_start(args,fmt);
ian@0 846 i = vsscanf(buf,fmt,args);
ian@0 847 va_end(args);
ian@0 848 return i;
ian@0 849 }
ian@0 850
ian@0 851 EXPORT_SYMBOL(sscanf);
ian@0 852
ian@0 853
ian@0 854 /* Simplified asprintf. */
ian@0 855 char *kasprintf(gfp_t gfp, const char *fmt, ...)
ian@0 856 {
ian@0 857 va_list ap;
ian@0 858 unsigned int len;
ian@0 859 char *p;
ian@0 860
ian@0 861 va_start(ap, fmt);
ian@0 862 len = vsnprintf(NULL, 0, fmt, ap);
ian@0 863 va_end(ap);
ian@0 864
ian@0 865 p = kmalloc(len+1, gfp);
ian@0 866 if (!p)
ian@0 867 return NULL;
ian@0 868 va_start(ap, fmt);
ian@0 869 vsnprintf(p, len+1, fmt, ap);
ian@0 870 va_end(ap);
ian@0 871 return p;
ian@0 872 }
ian@0 873
ian@0 874 EXPORT_SYMBOL(kasprintf);