11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/lib/vsprintf.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 81da177e4SLinus Torvalds /* 91da177e4SLinus Torvalds * Wirzenius wrote this portably, Torvalds fucked it up :-) 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds /* 131da177e4SLinus Torvalds * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> 141da177e4SLinus Torvalds * - changed to provide snprintf and vsnprintf functions 151da177e4SLinus Torvalds * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de> 161da177e4SLinus Torvalds * - scnprintf and vscnprintf 171da177e4SLinus Torvalds */ 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include <stdarg.h> 201da177e4SLinus Torvalds #include <linux/module.h> 211da177e4SLinus Torvalds #include <linux/types.h> 221da177e4SLinus Torvalds #include <linux/string.h> 231da177e4SLinus Torvalds #include <linux/ctype.h> 241da177e4SLinus Torvalds #include <linux/kernel.h> 251da177e4SLinus Torvalds 264e57b681STim Schmielau #include <asm/page.h> /* for PAGE_SIZE */ 271da177e4SLinus Torvalds #include <asm/div64.h> 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds /** 301da177e4SLinus Torvalds * simple_strtoul - convert a string to an unsigned long 311da177e4SLinus Torvalds * @cp: The start of the string 321da177e4SLinus Torvalds * @endp: A pointer to the end of the parsed string will be placed here 331da177e4SLinus Torvalds * @base: The number base to use 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds unsigned long result = 0,value; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds if (!base) { 401da177e4SLinus Torvalds base = 10; 411da177e4SLinus Torvalds if (*cp == '0') { 421da177e4SLinus Torvalds base = 8; 431da177e4SLinus Torvalds cp++; 441da177e4SLinus Torvalds if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { 451da177e4SLinus Torvalds cp++; 461da177e4SLinus Torvalds base = 16; 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds } else if (base == 16) { 501da177e4SLinus Torvalds if (cp[0] == '0' && toupper(cp[1]) == 'X') 511da177e4SLinus Torvalds cp += 2; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds while (isxdigit(*cp) && 541da177e4SLinus Torvalds (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { 551da177e4SLinus Torvalds result = result*base + value; 561da177e4SLinus Torvalds cp++; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds if (endp) 591da177e4SLinus Torvalds *endp = (char *)cp; 601da177e4SLinus Torvalds return result; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds EXPORT_SYMBOL(simple_strtoul); 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds /** 661da177e4SLinus Torvalds * simple_strtol - convert a string to a signed long 671da177e4SLinus Torvalds * @cp: The start of the string 681da177e4SLinus Torvalds * @endp: A pointer to the end of the parsed string will be placed here 691da177e4SLinus Torvalds * @base: The number base to use 701da177e4SLinus Torvalds */ 711da177e4SLinus Torvalds long simple_strtol(const char *cp,char **endp,unsigned int base) 721da177e4SLinus Torvalds { 731da177e4SLinus Torvalds if(*cp=='-') 741da177e4SLinus Torvalds return -simple_strtoul(cp+1,endp,base); 751da177e4SLinus Torvalds return simple_strtoul(cp,endp,base); 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds EXPORT_SYMBOL(simple_strtol); 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds /** 811da177e4SLinus Torvalds * simple_strtoull - convert a string to an unsigned long long 821da177e4SLinus Torvalds * @cp: The start of the string 831da177e4SLinus Torvalds * @endp: A pointer to the end of the parsed string will be placed here 841da177e4SLinus Torvalds * @base: The number base to use 851da177e4SLinus Torvalds */ 861da177e4SLinus Torvalds unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds unsigned long long result = 0,value; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds if (!base) { 911da177e4SLinus Torvalds base = 10; 921da177e4SLinus Torvalds if (*cp == '0') { 931da177e4SLinus Torvalds base = 8; 941da177e4SLinus Torvalds cp++; 951da177e4SLinus Torvalds if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { 961da177e4SLinus Torvalds cp++; 971da177e4SLinus Torvalds base = 16; 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds } else if (base == 16) { 1011da177e4SLinus Torvalds if (cp[0] == '0' && toupper(cp[1]) == 'X') 1021da177e4SLinus Torvalds cp += 2; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) 1051da177e4SLinus Torvalds ? toupper(*cp) : *cp)-'A'+10) < base) { 1061da177e4SLinus Torvalds result = result*base + value; 1071da177e4SLinus Torvalds cp++; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds if (endp) 1101da177e4SLinus Torvalds *endp = (char *)cp; 1111da177e4SLinus Torvalds return result; 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds EXPORT_SYMBOL(simple_strtoull); 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /** 1171da177e4SLinus Torvalds * simple_strtoll - convert a string to a signed long long 1181da177e4SLinus Torvalds * @cp: The start of the string 1191da177e4SLinus Torvalds * @endp: A pointer to the end of the parsed string will be placed here 1201da177e4SLinus Torvalds * @base: The number base to use 1211da177e4SLinus Torvalds */ 1221da177e4SLinus Torvalds long long simple_strtoll(const char *cp,char **endp,unsigned int base) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds if(*cp=='-') 1251da177e4SLinus Torvalds return -simple_strtoull(cp+1,endp,base); 1261da177e4SLinus Torvalds return simple_strtoull(cp,endp,base); 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds static int skip_atoi(const char **s) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds int i=0; 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds while (isdigit(**s)) 1341da177e4SLinus Torvalds i = i*10 + *((*s)++) - '0'; 1351da177e4SLinus Torvalds return i; 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds #define ZEROPAD 1 /* pad with zero */ 1391da177e4SLinus Torvalds #define SIGN 2 /* unsigned/signed long */ 1401da177e4SLinus Torvalds #define PLUS 4 /* show plus */ 1411da177e4SLinus Torvalds #define SPACE 8 /* space if plus */ 1421da177e4SLinus Torvalds #define LEFT 16 /* left justified */ 1431da177e4SLinus Torvalds #define SPECIAL 32 /* 0x */ 1441da177e4SLinus Torvalds #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) 1471da177e4SLinus Torvalds { 148*b39a7340SDenis Vlasenko char sign,tmp[66]; 1491da177e4SLinus Torvalds const char *digits; 150*b39a7340SDenis Vlasenko /* we are called with base 8, 10 or 16, only, thus don't need "g..." */ 151*b39a7340SDenis Vlasenko static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */ 152*b39a7340SDenis Vlasenko static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 153*b39a7340SDenis Vlasenko int need_pfx = ((type & SPECIAL) && base != 10); 1541da177e4SLinus Torvalds int i; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds digits = (type & LARGE) ? large_digits : small_digits; 1571da177e4SLinus Torvalds if (type & LEFT) 1581da177e4SLinus Torvalds type &= ~ZEROPAD; 1591da177e4SLinus Torvalds if (base < 2 || base > 36) 1601da177e4SLinus Torvalds return NULL; 1611da177e4SLinus Torvalds sign = 0; 1621da177e4SLinus Torvalds if (type & SIGN) { 1631da177e4SLinus Torvalds if ((signed long long) num < 0) { 1641da177e4SLinus Torvalds sign = '-'; 1651da177e4SLinus Torvalds num = - (signed long long) num; 1661da177e4SLinus Torvalds size--; 1671da177e4SLinus Torvalds } else if (type & PLUS) { 1681da177e4SLinus Torvalds sign = '+'; 1691da177e4SLinus Torvalds size--; 1701da177e4SLinus Torvalds } else if (type & SPACE) { 1711da177e4SLinus Torvalds sign = ' '; 1721da177e4SLinus Torvalds size--; 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds } 175*b39a7340SDenis Vlasenko if (need_pfx) { 176*b39a7340SDenis Vlasenko size--; 1771da177e4SLinus Torvalds if (base == 16) 1781da177e4SLinus Torvalds size--; 1791da177e4SLinus Torvalds } 180*b39a7340SDenis Vlasenko 181*b39a7340SDenis Vlasenko /* generate full string in tmp[], in reverse order */ 1821da177e4SLinus Torvalds i = 0; 1831da177e4SLinus Torvalds if (num == 0) 1841da177e4SLinus Torvalds tmp[i++] = '0'; 185*b39a7340SDenis Vlasenko else if (base != 10) { /* 8 or 16 */ 186*b39a7340SDenis Vlasenko int mask = base - 1; 187*b39a7340SDenis Vlasenko int shift = 3; 188*b39a7340SDenis Vlasenko if (base == 16) shift = 4; 189*b39a7340SDenis Vlasenko do { 190*b39a7340SDenis Vlasenko tmp[i++] = digits[((unsigned char)num) & mask]; 191*b39a7340SDenis Vlasenko num >>= shift; 192*b39a7340SDenis Vlasenko } while (num); 193*b39a7340SDenis Vlasenko } else do { /* generic code, works for any base */ 194*b39a7340SDenis Vlasenko tmp[i++] = digits[do_div(num,10 /*base*/)]; 195*b39a7340SDenis Vlasenko } while (num); 196*b39a7340SDenis Vlasenko 197*b39a7340SDenis Vlasenko /* printing 100 using %2d gives "100", not "00" */ 1981da177e4SLinus Torvalds if (i > precision) 1991da177e4SLinus Torvalds precision = i; 200*b39a7340SDenis Vlasenko /* leading space padding */ 2011da177e4SLinus Torvalds size -= precision; 2021da177e4SLinus Torvalds if (!(type & (ZEROPAD+LEFT))) { 203*b39a7340SDenis Vlasenko while(--size >= 0) { 204f796937aSJeremy Fitzhardinge if (buf < end) 2051da177e4SLinus Torvalds *buf = ' '; 2061da177e4SLinus Torvalds ++buf; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds } 209*b39a7340SDenis Vlasenko /* sign */ 2101da177e4SLinus Torvalds if (sign) { 211f796937aSJeremy Fitzhardinge if (buf < end) 2121da177e4SLinus Torvalds *buf = sign; 2131da177e4SLinus Torvalds ++buf; 2141da177e4SLinus Torvalds } 215*b39a7340SDenis Vlasenko /* "0x" / "0" prefix */ 216*b39a7340SDenis Vlasenko if (need_pfx) { 217f796937aSJeremy Fitzhardinge if (buf < end) 2181da177e4SLinus Torvalds *buf = '0'; 2191da177e4SLinus Torvalds ++buf; 220*b39a7340SDenis Vlasenko if (base == 16) { 221f796937aSJeremy Fitzhardinge if (buf < end) 222*b39a7340SDenis Vlasenko *buf = digits[16]; /* for arbitrary base: digits[33]; */ 2231da177e4SLinus Torvalds ++buf; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds } 226*b39a7340SDenis Vlasenko /* zero or space padding */ 2271da177e4SLinus Torvalds if (!(type & LEFT)) { 228*b39a7340SDenis Vlasenko char c = (type & ZEROPAD) ? '0' : ' '; 229*b39a7340SDenis Vlasenko while (--size >= 0) { 230f796937aSJeremy Fitzhardinge if (buf < end) 2311da177e4SLinus Torvalds *buf = c; 2321da177e4SLinus Torvalds ++buf; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds } 235*b39a7340SDenis Vlasenko /* hmm even more zero padding? */ 236*b39a7340SDenis Vlasenko while (i <= --precision) { 237f796937aSJeremy Fitzhardinge if (buf < end) 2381da177e4SLinus Torvalds *buf = '0'; 2391da177e4SLinus Torvalds ++buf; 2401da177e4SLinus Torvalds } 241*b39a7340SDenis Vlasenko /* actual digits of result */ 242*b39a7340SDenis Vlasenko while (--i >= 0) { 243f796937aSJeremy Fitzhardinge if (buf < end) 2441da177e4SLinus Torvalds *buf = tmp[i]; 2451da177e4SLinus Torvalds ++buf; 2461da177e4SLinus Torvalds } 247*b39a7340SDenis Vlasenko /* trailing space padding */ 248*b39a7340SDenis Vlasenko while (--size >= 0) { 249f796937aSJeremy Fitzhardinge if (buf < end) 2501da177e4SLinus Torvalds *buf = ' '; 2511da177e4SLinus Torvalds ++buf; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds return buf; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds /** 2571da177e4SLinus Torvalds * vsnprintf - Format a string and place it in a buffer 2581da177e4SLinus Torvalds * @buf: The buffer to place the result into 2591da177e4SLinus Torvalds * @size: The size of the buffer, including the trailing null space 2601da177e4SLinus Torvalds * @fmt: The format string to use 2611da177e4SLinus Torvalds * @args: Arguments for the format string 2621da177e4SLinus Torvalds * 2631da177e4SLinus Torvalds * The return value is the number of characters which would 2641da177e4SLinus Torvalds * be generated for the given input, excluding the trailing 2651da177e4SLinus Torvalds * '\0', as per ISO C99. If you want to have the exact 2661da177e4SLinus Torvalds * number of characters written into @buf as return value 26772fd4a35SRobert P. J. Day * (not including the trailing '\0'), use vscnprintf(). If the 2681da177e4SLinus Torvalds * return is greater than or equal to @size, the resulting 2691da177e4SLinus Torvalds * string is truncated. 2701da177e4SLinus Torvalds * 2711da177e4SLinus Torvalds * Call this function if you are already dealing with a va_list. 27272fd4a35SRobert P. J. Day * You probably want snprintf() instead. 2731da177e4SLinus Torvalds */ 2741da177e4SLinus Torvalds int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) 2751da177e4SLinus Torvalds { 2761da177e4SLinus Torvalds int len; 2771da177e4SLinus Torvalds unsigned long long num; 2781da177e4SLinus Torvalds int i, base; 2791da177e4SLinus Torvalds char *str, *end, c; 2801da177e4SLinus Torvalds const char *s; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds int flags; /* flags to number() */ 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds int field_width; /* width of output field */ 2851da177e4SLinus Torvalds int precision; /* min. # of digits for integers; max 2861da177e4SLinus Torvalds number of chars for from string */ 2871da177e4SLinus Torvalds int qualifier; /* 'h', 'l', or 'L' for integer fields */ 2881da177e4SLinus Torvalds /* 'z' support added 23/7/1999 S.H. */ 2891da177e4SLinus Torvalds /* 'z' changed to 'Z' --davidm 1/25/99 */ 29080322306SAl Viro /* 't' added for ptrdiff_t */ 2911da177e4SLinus Torvalds 292f796937aSJeremy Fitzhardinge /* Reject out-of-range values early. Large positive sizes are 293f796937aSJeremy Fitzhardinge used for unknown buffer sizes. */ 2941da177e4SLinus Torvalds if (unlikely((int) size < 0)) { 2951da177e4SLinus Torvalds /* There can be only one.. */ 296*b39a7340SDenis Vlasenko static char warn = 1; 2971da177e4SLinus Torvalds WARN_ON(warn); 2981da177e4SLinus Torvalds warn = 0; 2991da177e4SLinus Torvalds return 0; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds str = buf; 303f796937aSJeremy Fitzhardinge end = buf + size; 3041da177e4SLinus Torvalds 305f796937aSJeremy Fitzhardinge /* Make sure end is always >= buf */ 306f796937aSJeremy Fitzhardinge if (end < buf) { 3071da177e4SLinus Torvalds end = ((void *)-1); 308f796937aSJeremy Fitzhardinge size = end - buf; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds for (; *fmt ; ++fmt) { 3121da177e4SLinus Torvalds if (*fmt != '%') { 313f796937aSJeremy Fitzhardinge if (str < end) 3141da177e4SLinus Torvalds *str = *fmt; 3151da177e4SLinus Torvalds ++str; 3161da177e4SLinus Torvalds continue; 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds /* process flags */ 3201da177e4SLinus Torvalds flags = 0; 3211da177e4SLinus Torvalds repeat: 3221da177e4SLinus Torvalds ++fmt; /* this also skips first '%' */ 3231da177e4SLinus Torvalds switch (*fmt) { 3241da177e4SLinus Torvalds case '-': flags |= LEFT; goto repeat; 3251da177e4SLinus Torvalds case '+': flags |= PLUS; goto repeat; 3261da177e4SLinus Torvalds case ' ': flags |= SPACE; goto repeat; 3271da177e4SLinus Torvalds case '#': flags |= SPECIAL; goto repeat; 3281da177e4SLinus Torvalds case '0': flags |= ZEROPAD; goto repeat; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds /* get field width */ 3321da177e4SLinus Torvalds field_width = -1; 3331da177e4SLinus Torvalds if (isdigit(*fmt)) 3341da177e4SLinus Torvalds field_width = skip_atoi(&fmt); 3351da177e4SLinus Torvalds else if (*fmt == '*') { 3361da177e4SLinus Torvalds ++fmt; 3371da177e4SLinus Torvalds /* it's the next argument */ 3381da177e4SLinus Torvalds field_width = va_arg(args, int); 3391da177e4SLinus Torvalds if (field_width < 0) { 3401da177e4SLinus Torvalds field_width = -field_width; 3411da177e4SLinus Torvalds flags |= LEFT; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* get the precision */ 3461da177e4SLinus Torvalds precision = -1; 3471da177e4SLinus Torvalds if (*fmt == '.') { 3481da177e4SLinus Torvalds ++fmt; 3491da177e4SLinus Torvalds if (isdigit(*fmt)) 3501da177e4SLinus Torvalds precision = skip_atoi(&fmt); 3511da177e4SLinus Torvalds else if (*fmt == '*') { 3521da177e4SLinus Torvalds ++fmt; 3531da177e4SLinus Torvalds /* it's the next argument */ 3541da177e4SLinus Torvalds precision = va_arg(args, int); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds if (precision < 0) 3571da177e4SLinus Torvalds precision = 0; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /* get the conversion qualifier */ 3611da177e4SLinus Torvalds qualifier = -1; 3621da177e4SLinus Torvalds if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 36380322306SAl Viro *fmt =='Z' || *fmt == 'z' || *fmt == 't') { 3641da177e4SLinus Torvalds qualifier = *fmt; 3651da177e4SLinus Torvalds ++fmt; 3661da177e4SLinus Torvalds if (qualifier == 'l' && *fmt == 'l') { 3671da177e4SLinus Torvalds qualifier = 'L'; 3681da177e4SLinus Torvalds ++fmt; 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds /* default base */ 3731da177e4SLinus Torvalds base = 10; 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds switch (*fmt) { 3761da177e4SLinus Torvalds case 'c': 3771da177e4SLinus Torvalds if (!(flags & LEFT)) { 3781da177e4SLinus Torvalds while (--field_width > 0) { 379f796937aSJeremy Fitzhardinge if (str < end) 3801da177e4SLinus Torvalds *str = ' '; 3811da177e4SLinus Torvalds ++str; 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds c = (unsigned char) va_arg(args, int); 385f796937aSJeremy Fitzhardinge if (str < end) 3861da177e4SLinus Torvalds *str = c; 3871da177e4SLinus Torvalds ++str; 3881da177e4SLinus Torvalds while (--field_width > 0) { 389f796937aSJeremy Fitzhardinge if (str < end) 3901da177e4SLinus Torvalds *str = ' '; 3911da177e4SLinus Torvalds ++str; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds continue; 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds case 's': 3961da177e4SLinus Torvalds s = va_arg(args, char *); 3971da177e4SLinus Torvalds if ((unsigned long)s < PAGE_SIZE) 3981da177e4SLinus Torvalds s = "<NULL>"; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds len = strnlen(s, precision); 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds if (!(flags & LEFT)) { 4031da177e4SLinus Torvalds while (len < field_width--) { 404f796937aSJeremy Fitzhardinge if (str < end) 4051da177e4SLinus Torvalds *str = ' '; 4061da177e4SLinus Torvalds ++str; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds for (i = 0; i < len; ++i) { 410f796937aSJeremy Fitzhardinge if (str < end) 4111da177e4SLinus Torvalds *str = *s; 4121da177e4SLinus Torvalds ++str; ++s; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds while (len < field_width--) { 415f796937aSJeremy Fitzhardinge if (str < end) 4161da177e4SLinus Torvalds *str = ' '; 4171da177e4SLinus Torvalds ++str; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds continue; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds case 'p': 4221da177e4SLinus Torvalds if (field_width == -1) { 4231da177e4SLinus Torvalds field_width = 2*sizeof(void *); 4241da177e4SLinus Torvalds flags |= ZEROPAD; 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds str = number(str, end, 4271da177e4SLinus Torvalds (unsigned long) va_arg(args, void *), 4281da177e4SLinus Torvalds 16, field_width, precision, flags); 4291da177e4SLinus Torvalds continue; 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds case 'n': 4331da177e4SLinus Torvalds /* FIXME: 4341da177e4SLinus Torvalds * What does C99 say about the overflow case here? */ 4351da177e4SLinus Torvalds if (qualifier == 'l') { 4361da177e4SLinus Torvalds long * ip = va_arg(args, long *); 4371da177e4SLinus Torvalds *ip = (str - buf); 4381da177e4SLinus Torvalds } else if (qualifier == 'Z' || qualifier == 'z') { 4391da177e4SLinus Torvalds size_t * ip = va_arg(args, size_t *); 4401da177e4SLinus Torvalds *ip = (str - buf); 4411da177e4SLinus Torvalds } else { 4421da177e4SLinus Torvalds int * ip = va_arg(args, int *); 4431da177e4SLinus Torvalds *ip = (str - buf); 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds continue; 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds case '%': 448f796937aSJeremy Fitzhardinge if (str < end) 4491da177e4SLinus Torvalds *str = '%'; 4501da177e4SLinus Torvalds ++str; 4511da177e4SLinus Torvalds continue; 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds /* integer number formats - set up the flags and "break" */ 4541da177e4SLinus Torvalds case 'o': 4551da177e4SLinus Torvalds base = 8; 4561da177e4SLinus Torvalds break; 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds case 'X': 4591da177e4SLinus Torvalds flags |= LARGE; 4601da177e4SLinus Torvalds case 'x': 4611da177e4SLinus Torvalds base = 16; 4621da177e4SLinus Torvalds break; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds case 'd': 4651da177e4SLinus Torvalds case 'i': 4661da177e4SLinus Torvalds flags |= SIGN; 4671da177e4SLinus Torvalds case 'u': 4681da177e4SLinus Torvalds break; 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds default: 471f796937aSJeremy Fitzhardinge if (str < end) 4721da177e4SLinus Torvalds *str = '%'; 4731da177e4SLinus Torvalds ++str; 4741da177e4SLinus Torvalds if (*fmt) { 475f796937aSJeremy Fitzhardinge if (str < end) 4761da177e4SLinus Torvalds *str = *fmt; 4771da177e4SLinus Torvalds ++str; 4781da177e4SLinus Torvalds } else { 4791da177e4SLinus Torvalds --fmt; 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds continue; 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds if (qualifier == 'L') 4841da177e4SLinus Torvalds num = va_arg(args, long long); 4851da177e4SLinus Torvalds else if (qualifier == 'l') { 4861da177e4SLinus Torvalds num = va_arg(args, unsigned long); 4871da177e4SLinus Torvalds if (flags & SIGN) 4881da177e4SLinus Torvalds num = (signed long) num; 4891da177e4SLinus Torvalds } else if (qualifier == 'Z' || qualifier == 'z') { 4901da177e4SLinus Torvalds num = va_arg(args, size_t); 49180322306SAl Viro } else if (qualifier == 't') { 49280322306SAl Viro num = va_arg(args, ptrdiff_t); 4931da177e4SLinus Torvalds } else if (qualifier == 'h') { 4941da177e4SLinus Torvalds num = (unsigned short) va_arg(args, int); 4951da177e4SLinus Torvalds if (flags & SIGN) 4961da177e4SLinus Torvalds num = (signed short) num; 4971da177e4SLinus Torvalds } else { 4981da177e4SLinus Torvalds num = va_arg(args, unsigned int); 4991da177e4SLinus Torvalds if (flags & SIGN) 5001da177e4SLinus Torvalds num = (signed int) num; 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds str = number(str, end, num, base, 5031da177e4SLinus Torvalds field_width, precision, flags); 5041da177e4SLinus Torvalds } 505f796937aSJeremy Fitzhardinge if (size > 0) { 506f796937aSJeremy Fitzhardinge if (str < end) 5071da177e4SLinus Torvalds *str = '\0'; 508f796937aSJeremy Fitzhardinge else 5090a6047eeSLinus Torvalds end[-1] = '\0'; 510f796937aSJeremy Fitzhardinge } 511f796937aSJeremy Fitzhardinge /* the trailing null byte doesn't count towards the total */ 5121da177e4SLinus Torvalds return str-buf; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds EXPORT_SYMBOL(vsnprintf); 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds /** 5181da177e4SLinus Torvalds * vscnprintf - Format a string and place it in a buffer 5191da177e4SLinus Torvalds * @buf: The buffer to place the result into 5201da177e4SLinus Torvalds * @size: The size of the buffer, including the trailing null space 5211da177e4SLinus Torvalds * @fmt: The format string to use 5221da177e4SLinus Torvalds * @args: Arguments for the format string 5231da177e4SLinus Torvalds * 5241da177e4SLinus Torvalds * The return value is the number of characters which have been written into 5251da177e4SLinus Torvalds * the @buf not including the trailing '\0'. If @size is <= 0 the function 5261da177e4SLinus Torvalds * returns 0. 5271da177e4SLinus Torvalds * 5281da177e4SLinus Torvalds * Call this function if you are already dealing with a va_list. 52972fd4a35SRobert P. J. Day * You probably want scnprintf() instead. 5301da177e4SLinus Torvalds */ 5311da177e4SLinus Torvalds int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds int i; 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds i=vsnprintf(buf,size,fmt,args); 5361da177e4SLinus Torvalds return (i >= size) ? (size - 1) : i; 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds EXPORT_SYMBOL(vscnprintf); 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds /** 5421da177e4SLinus Torvalds * snprintf - Format a string and place it in a buffer 5431da177e4SLinus Torvalds * @buf: The buffer to place the result into 5441da177e4SLinus Torvalds * @size: The size of the buffer, including the trailing null space 5451da177e4SLinus Torvalds * @fmt: The format string to use 5461da177e4SLinus Torvalds * @...: Arguments for the format string 5471da177e4SLinus Torvalds * 5481da177e4SLinus Torvalds * The return value is the number of characters which would be 5491da177e4SLinus Torvalds * generated for the given input, excluding the trailing null, 5501da177e4SLinus Torvalds * as per ISO C99. If the return is greater than or equal to 5511da177e4SLinus Torvalds * @size, the resulting string is truncated. 5521da177e4SLinus Torvalds */ 5531da177e4SLinus Torvalds int snprintf(char * buf, size_t size, const char *fmt, ...) 5541da177e4SLinus Torvalds { 5551da177e4SLinus Torvalds va_list args; 5561da177e4SLinus Torvalds int i; 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds va_start(args, fmt); 5591da177e4SLinus Torvalds i=vsnprintf(buf,size,fmt,args); 5601da177e4SLinus Torvalds va_end(args); 5611da177e4SLinus Torvalds return i; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds EXPORT_SYMBOL(snprintf); 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds /** 5671da177e4SLinus Torvalds * scnprintf - Format a string and place it in a buffer 5681da177e4SLinus Torvalds * @buf: The buffer to place the result into 5691da177e4SLinus Torvalds * @size: The size of the buffer, including the trailing null space 5701da177e4SLinus Torvalds * @fmt: The format string to use 5711da177e4SLinus Torvalds * @...: Arguments for the format string 5721da177e4SLinus Torvalds * 5731da177e4SLinus Torvalds * The return value is the number of characters written into @buf not including 574ea6f3281SMartin Peschke * the trailing '\0'. If @size is <= 0 the function returns 0. 5751da177e4SLinus Torvalds */ 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds int scnprintf(char * buf, size_t size, const char *fmt, ...) 5781da177e4SLinus Torvalds { 5791da177e4SLinus Torvalds va_list args; 5801da177e4SLinus Torvalds int i; 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds va_start(args, fmt); 5831da177e4SLinus Torvalds i = vsnprintf(buf, size, fmt, args); 5841da177e4SLinus Torvalds va_end(args); 5851da177e4SLinus Torvalds return (i >= size) ? (size - 1) : i; 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds EXPORT_SYMBOL(scnprintf); 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds /** 5901da177e4SLinus Torvalds * vsprintf - Format a string and place it in a buffer 5911da177e4SLinus Torvalds * @buf: The buffer to place the result into 5921da177e4SLinus Torvalds * @fmt: The format string to use 5931da177e4SLinus Torvalds * @args: Arguments for the format string 5941da177e4SLinus Torvalds * 5951da177e4SLinus Torvalds * The function returns the number of characters written 59672fd4a35SRobert P. J. Day * into @buf. Use vsnprintf() or vscnprintf() in order to avoid 5971da177e4SLinus Torvalds * buffer overflows. 5981da177e4SLinus Torvalds * 5991da177e4SLinus Torvalds * Call this function if you are already dealing with a va_list. 60072fd4a35SRobert P. J. Day * You probably want sprintf() instead. 6011da177e4SLinus Torvalds */ 6021da177e4SLinus Torvalds int vsprintf(char *buf, const char *fmt, va_list args) 6031da177e4SLinus Torvalds { 6041da177e4SLinus Torvalds return vsnprintf(buf, INT_MAX, fmt, args); 6051da177e4SLinus Torvalds } 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds EXPORT_SYMBOL(vsprintf); 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds /** 6101da177e4SLinus Torvalds * sprintf - Format a string and place it in a buffer 6111da177e4SLinus Torvalds * @buf: The buffer to place the result into 6121da177e4SLinus Torvalds * @fmt: The format string to use 6131da177e4SLinus Torvalds * @...: Arguments for the format string 6141da177e4SLinus Torvalds * 6151da177e4SLinus Torvalds * The function returns the number of characters written 61672fd4a35SRobert P. J. Day * into @buf. Use snprintf() or scnprintf() in order to avoid 6171da177e4SLinus Torvalds * buffer overflows. 6181da177e4SLinus Torvalds */ 6191da177e4SLinus Torvalds int sprintf(char * buf, const char *fmt, ...) 6201da177e4SLinus Torvalds { 6211da177e4SLinus Torvalds va_list args; 6221da177e4SLinus Torvalds int i; 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds va_start(args, fmt); 6251da177e4SLinus Torvalds i=vsnprintf(buf, INT_MAX, fmt, args); 6261da177e4SLinus Torvalds va_end(args); 6271da177e4SLinus Torvalds return i; 6281da177e4SLinus Torvalds } 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds EXPORT_SYMBOL(sprintf); 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds /** 6331da177e4SLinus Torvalds * vsscanf - Unformat a buffer into a list of arguments 6341da177e4SLinus Torvalds * @buf: input buffer 6351da177e4SLinus Torvalds * @fmt: format of buffer 6361da177e4SLinus Torvalds * @args: arguments 6371da177e4SLinus Torvalds */ 6381da177e4SLinus Torvalds int vsscanf(const char * buf, const char * fmt, va_list args) 6391da177e4SLinus Torvalds { 6401da177e4SLinus Torvalds const char *str = buf; 6411da177e4SLinus Torvalds char *next; 6421da177e4SLinus Torvalds char digit; 6431da177e4SLinus Torvalds int num = 0; 6441da177e4SLinus Torvalds int qualifier; 6451da177e4SLinus Torvalds int base; 6461da177e4SLinus Torvalds int field_width; 6471da177e4SLinus Torvalds int is_sign = 0; 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds while(*fmt && *str) { 6501da177e4SLinus Torvalds /* skip any white space in format */ 6511da177e4SLinus Torvalds /* white space in format matchs any amount of 6521da177e4SLinus Torvalds * white space, including none, in the input. 6531da177e4SLinus Torvalds */ 6541da177e4SLinus Torvalds if (isspace(*fmt)) { 6551da177e4SLinus Torvalds while (isspace(*fmt)) 6561da177e4SLinus Torvalds ++fmt; 6571da177e4SLinus Torvalds while (isspace(*str)) 6581da177e4SLinus Torvalds ++str; 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds /* anything that is not a conversion must match exactly */ 6621da177e4SLinus Torvalds if (*fmt != '%' && *fmt) { 6631da177e4SLinus Torvalds if (*fmt++ != *str++) 6641da177e4SLinus Torvalds break; 6651da177e4SLinus Torvalds continue; 6661da177e4SLinus Torvalds } 6671da177e4SLinus Torvalds 6681da177e4SLinus Torvalds if (!*fmt) 6691da177e4SLinus Torvalds break; 6701da177e4SLinus Torvalds ++fmt; 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds /* skip this conversion. 6731da177e4SLinus Torvalds * advance both strings to next white space 6741da177e4SLinus Torvalds */ 6751da177e4SLinus Torvalds if (*fmt == '*') { 6761da177e4SLinus Torvalds while (!isspace(*fmt) && *fmt) 6771da177e4SLinus Torvalds fmt++; 6781da177e4SLinus Torvalds while (!isspace(*str) && *str) 6791da177e4SLinus Torvalds str++; 6801da177e4SLinus Torvalds continue; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds /* get field width */ 6841da177e4SLinus Torvalds field_width = -1; 6851da177e4SLinus Torvalds if (isdigit(*fmt)) 6861da177e4SLinus Torvalds field_width = skip_atoi(&fmt); 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds /* get conversion qualifier */ 6891da177e4SLinus Torvalds qualifier = -1; 6901da177e4SLinus Torvalds if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 6911da177e4SLinus Torvalds *fmt == 'Z' || *fmt == 'z') { 6921da177e4SLinus Torvalds qualifier = *fmt++; 6931da177e4SLinus Torvalds if (unlikely(qualifier == *fmt)) { 6941da177e4SLinus Torvalds if (qualifier == 'h') { 6951da177e4SLinus Torvalds qualifier = 'H'; 6961da177e4SLinus Torvalds fmt++; 6971da177e4SLinus Torvalds } else if (qualifier == 'l') { 6981da177e4SLinus Torvalds qualifier = 'L'; 6991da177e4SLinus Torvalds fmt++; 7001da177e4SLinus Torvalds } 7011da177e4SLinus Torvalds } 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds base = 10; 7041da177e4SLinus Torvalds is_sign = 0; 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds if (!*fmt || !*str) 7071da177e4SLinus Torvalds break; 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds switch(*fmt++) { 7101da177e4SLinus Torvalds case 'c': 7111da177e4SLinus Torvalds { 7121da177e4SLinus Torvalds char *s = (char *) va_arg(args,char*); 7131da177e4SLinus Torvalds if (field_width == -1) 7141da177e4SLinus Torvalds field_width = 1; 7151da177e4SLinus Torvalds do { 7161da177e4SLinus Torvalds *s++ = *str++; 7171da177e4SLinus Torvalds } while (--field_width > 0 && *str); 7181da177e4SLinus Torvalds num++; 7191da177e4SLinus Torvalds } 7201da177e4SLinus Torvalds continue; 7211da177e4SLinus Torvalds case 's': 7221da177e4SLinus Torvalds { 7231da177e4SLinus Torvalds char *s = (char *) va_arg(args, char *); 7241da177e4SLinus Torvalds if(field_width == -1) 7251da177e4SLinus Torvalds field_width = INT_MAX; 7261da177e4SLinus Torvalds /* first, skip leading white space in buffer */ 7271da177e4SLinus Torvalds while (isspace(*str)) 7281da177e4SLinus Torvalds str++; 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds /* now copy until next white space */ 7311da177e4SLinus Torvalds while (*str && !isspace(*str) && field_width--) { 7321da177e4SLinus Torvalds *s++ = *str++; 7331da177e4SLinus Torvalds } 7341da177e4SLinus Torvalds *s = '\0'; 7351da177e4SLinus Torvalds num++; 7361da177e4SLinus Torvalds } 7371da177e4SLinus Torvalds continue; 7381da177e4SLinus Torvalds case 'n': 7391da177e4SLinus Torvalds /* return number of characters read so far */ 7401da177e4SLinus Torvalds { 7411da177e4SLinus Torvalds int *i = (int *)va_arg(args,int*); 7421da177e4SLinus Torvalds *i = str - buf; 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds continue; 7451da177e4SLinus Torvalds case 'o': 7461da177e4SLinus Torvalds base = 8; 7471da177e4SLinus Torvalds break; 7481da177e4SLinus Torvalds case 'x': 7491da177e4SLinus Torvalds case 'X': 7501da177e4SLinus Torvalds base = 16; 7511da177e4SLinus Torvalds break; 7521da177e4SLinus Torvalds case 'i': 7531da177e4SLinus Torvalds base = 0; 7541da177e4SLinus Torvalds case 'd': 7551da177e4SLinus Torvalds is_sign = 1; 7561da177e4SLinus Torvalds case 'u': 7571da177e4SLinus Torvalds break; 7581da177e4SLinus Torvalds case '%': 7591da177e4SLinus Torvalds /* looking for '%' in str */ 7601da177e4SLinus Torvalds if (*str++ != '%') 7611da177e4SLinus Torvalds return num; 7621da177e4SLinus Torvalds continue; 7631da177e4SLinus Torvalds default: 7641da177e4SLinus Torvalds /* invalid format; stop here */ 7651da177e4SLinus Torvalds return num; 7661da177e4SLinus Torvalds } 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds /* have some sort of integer conversion. 7691da177e4SLinus Torvalds * first, skip white space in buffer. 7701da177e4SLinus Torvalds */ 7711da177e4SLinus Torvalds while (isspace(*str)) 7721da177e4SLinus Torvalds str++; 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds digit = *str; 7751da177e4SLinus Torvalds if (is_sign && digit == '-') 7761da177e4SLinus Torvalds digit = *(str + 1); 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds if (!digit 7791da177e4SLinus Torvalds || (base == 16 && !isxdigit(digit)) 7801da177e4SLinus Torvalds || (base == 10 && !isdigit(digit)) 7811da177e4SLinus Torvalds || (base == 8 && (!isdigit(digit) || digit > '7')) 7821da177e4SLinus Torvalds || (base == 0 && !isdigit(digit))) 7831da177e4SLinus Torvalds break; 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds switch(qualifier) { 7861da177e4SLinus Torvalds case 'H': /* that's 'hh' in format */ 7871da177e4SLinus Torvalds if (is_sign) { 7881da177e4SLinus Torvalds signed char *s = (signed char *) va_arg(args,signed char *); 7891da177e4SLinus Torvalds *s = (signed char) simple_strtol(str,&next,base); 7901da177e4SLinus Torvalds } else { 7911da177e4SLinus Torvalds unsigned char *s = (unsigned char *) va_arg(args, unsigned char *); 7921da177e4SLinus Torvalds *s = (unsigned char) simple_strtoul(str, &next, base); 7931da177e4SLinus Torvalds } 7941da177e4SLinus Torvalds break; 7951da177e4SLinus Torvalds case 'h': 7961da177e4SLinus Torvalds if (is_sign) { 7971da177e4SLinus Torvalds short *s = (short *) va_arg(args,short *); 7981da177e4SLinus Torvalds *s = (short) simple_strtol(str,&next,base); 7991da177e4SLinus Torvalds } else { 8001da177e4SLinus Torvalds unsigned short *s = (unsigned short *) va_arg(args, unsigned short *); 8011da177e4SLinus Torvalds *s = (unsigned short) simple_strtoul(str, &next, base); 8021da177e4SLinus Torvalds } 8031da177e4SLinus Torvalds break; 8041da177e4SLinus Torvalds case 'l': 8051da177e4SLinus Torvalds if (is_sign) { 8061da177e4SLinus Torvalds long *l = (long *) va_arg(args,long *); 8071da177e4SLinus Torvalds *l = simple_strtol(str,&next,base); 8081da177e4SLinus Torvalds } else { 8091da177e4SLinus Torvalds unsigned long *l = (unsigned long*) va_arg(args,unsigned long*); 8101da177e4SLinus Torvalds *l = simple_strtoul(str,&next,base); 8111da177e4SLinus Torvalds } 8121da177e4SLinus Torvalds break; 8131da177e4SLinus Torvalds case 'L': 8141da177e4SLinus Torvalds if (is_sign) { 8151da177e4SLinus Torvalds long long *l = (long long*) va_arg(args,long long *); 8161da177e4SLinus Torvalds *l = simple_strtoll(str,&next,base); 8171da177e4SLinus Torvalds } else { 8181da177e4SLinus Torvalds unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*); 8191da177e4SLinus Torvalds *l = simple_strtoull(str,&next,base); 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds break; 8221da177e4SLinus Torvalds case 'Z': 8231da177e4SLinus Torvalds case 'z': 8241da177e4SLinus Torvalds { 8251da177e4SLinus Torvalds size_t *s = (size_t*) va_arg(args,size_t*); 8261da177e4SLinus Torvalds *s = (size_t) simple_strtoul(str,&next,base); 8271da177e4SLinus Torvalds } 8281da177e4SLinus Torvalds break; 8291da177e4SLinus Torvalds default: 8301da177e4SLinus Torvalds if (is_sign) { 8311da177e4SLinus Torvalds int *i = (int *) va_arg(args, int*); 8321da177e4SLinus Torvalds *i = (int) simple_strtol(str,&next,base); 8331da177e4SLinus Torvalds } else { 8341da177e4SLinus Torvalds unsigned int *i = (unsigned int*) va_arg(args, unsigned int*); 8351da177e4SLinus Torvalds *i = (unsigned int) simple_strtoul(str,&next,base); 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds break; 8381da177e4SLinus Torvalds } 8391da177e4SLinus Torvalds num++; 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds if (!next) 8421da177e4SLinus Torvalds break; 8431da177e4SLinus Torvalds str = next; 8441da177e4SLinus Torvalds } 845c6b40d16SJohannes Berg 846c6b40d16SJohannes Berg /* 847c6b40d16SJohannes Berg * Now we've come all the way through so either the input string or the 848c6b40d16SJohannes Berg * format ended. In the former case, there can be a %n at the current 849c6b40d16SJohannes Berg * position in the format that needs to be filled. 850c6b40d16SJohannes Berg */ 851c6b40d16SJohannes Berg if (*fmt == '%' && *(fmt + 1) == 'n') { 852c6b40d16SJohannes Berg int *p = (int *)va_arg(args, int *); 853c6b40d16SJohannes Berg *p = str - buf; 854c6b40d16SJohannes Berg } 855c6b40d16SJohannes Berg 8561da177e4SLinus Torvalds return num; 8571da177e4SLinus Torvalds } 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds EXPORT_SYMBOL(vsscanf); 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds /** 8621da177e4SLinus Torvalds * sscanf - Unformat a buffer into a list of arguments 8631da177e4SLinus Torvalds * @buf: input buffer 8641da177e4SLinus Torvalds * @fmt: formatting of buffer 8651da177e4SLinus Torvalds * @...: resulting arguments 8661da177e4SLinus Torvalds */ 8671da177e4SLinus Torvalds int sscanf(const char * buf, const char * fmt, ...) 8681da177e4SLinus Torvalds { 8691da177e4SLinus Torvalds va_list args; 8701da177e4SLinus Torvalds int i; 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds va_start(args,fmt); 8731da177e4SLinus Torvalds i = vsscanf(buf,fmt,args); 8741da177e4SLinus Torvalds va_end(args); 8751da177e4SLinus Torvalds return i; 8761da177e4SLinus Torvalds } 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds EXPORT_SYMBOL(sscanf); 879e905914fSJeremy Fitzhardinge 880e905914fSJeremy Fitzhardinge 881e905914fSJeremy Fitzhardinge /* Simplified asprintf. */ 88211443ec7SJeremy Fitzhardinge char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap) 883e905914fSJeremy Fitzhardinge { 884e905914fSJeremy Fitzhardinge unsigned int len; 885e905914fSJeremy Fitzhardinge char *p; 88611443ec7SJeremy Fitzhardinge va_list aq; 887e905914fSJeremy Fitzhardinge 88811443ec7SJeremy Fitzhardinge va_copy(aq, ap); 88911443ec7SJeremy Fitzhardinge len = vsnprintf(NULL, 0, fmt, aq); 89011443ec7SJeremy Fitzhardinge va_end(aq); 891e905914fSJeremy Fitzhardinge 892e905914fSJeremy Fitzhardinge p = kmalloc(len+1, gfp); 893e905914fSJeremy Fitzhardinge if (!p) 894e905914fSJeremy Fitzhardinge return NULL; 89511443ec7SJeremy Fitzhardinge 896e905914fSJeremy Fitzhardinge vsnprintf(p, len+1, fmt, ap); 89711443ec7SJeremy Fitzhardinge 898e905914fSJeremy Fitzhardinge return p; 899e905914fSJeremy Fitzhardinge } 90011443ec7SJeremy Fitzhardinge EXPORT_SYMBOL(kvasprintf); 901e905914fSJeremy Fitzhardinge 90211443ec7SJeremy Fitzhardinge char *kasprintf(gfp_t gfp, const char *fmt, ...) 90311443ec7SJeremy Fitzhardinge { 90411443ec7SJeremy Fitzhardinge va_list ap; 90511443ec7SJeremy Fitzhardinge char *p; 90611443ec7SJeremy Fitzhardinge 90711443ec7SJeremy Fitzhardinge va_start(ap, fmt); 90811443ec7SJeremy Fitzhardinge p = kvasprintf(gfp, fmt, ap); 90911443ec7SJeremy Fitzhardinge va_end(ap); 91011443ec7SJeremy Fitzhardinge 91111443ec7SJeremy Fitzhardinge return p; 91211443ec7SJeremy Fitzhardinge } 913e905914fSJeremy Fitzhardinge EXPORT_SYMBOL(kasprintf); 914