debuggers.hg

annotate xen/common/vsprintf.c @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

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