#include <linux/ctype.h>
#include <linux/kernel.h>
+#include <asm/page.h> /* for PAGE_SIZE */
#include <asm/div64.h>
/**
if (*cp == '0') {
base = 8;
cp++;
- if ((*cp == 'x') && isxdigit(cp[1])) {
+ if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
cp++;
base = 16;
}
}
+ } else if (base == 16) {
+ if (cp[0] == '0' && toupper(cp[1]) == 'X')
+ cp += 2;
}
while (isxdigit(*cp) &&
(value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
if (*cp == '0') {
base = 8;
cp++;
- if ((*cp == 'x') && isxdigit(cp[1])) {
+ if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
cp++;
base = 16;
}
}
+ } else if (base == 16) {
+ if (cp[0] == '0' && toupper(cp[1]) == 'X')
+ cp += 2;
}
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
? toupper(*cp) : *cp)-'A'+10) < base) {
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
- return 0;
+ return NULL;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
size -= precision;
if (!(type&(ZEROPAD+LEFT))) {
while(size-->0) {
- if (buf <= end)
+ if (buf < end)
*buf = ' ';
++buf;
}
}
if (sign) {
- if (buf <= end)
+ if (buf < end)
*buf = sign;
++buf;
}
if (type & SPECIAL) {
if (base==8) {
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++buf;
} else if (base==16) {
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++buf;
- if (buf <= end)
+ if (buf < end)
*buf = digits[33];
++buf;
}
}
if (!(type & LEFT)) {
while (size-- > 0) {
- if (buf <= end)
+ if (buf < end)
*buf = c;
++buf;
}
}
while (i < precision--) {
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++buf;
}
while (i-- > 0) {
- if (buf <= end)
+ if (buf < end)
*buf = tmp[i];
++buf;
}
while (size-- > 0) {
- if (buf <= end)
+ if (buf < end)
*buf = ' ';
++buf;
}
int qualifier; /* 'h', 'l', or 'L' for integer fields */
/* 'z' support added 23/7/1999 S.H. */
/* 'z' changed to 'Z' --davidm 1/25/99 */
+ /* 't' added for ptrdiff_t */
- /* Reject out-of-range values early */
+ /* Reject out-of-range values early. Large positive sizes are
+ used for unknown buffer sizes. */
if (unlikely((int) size < 0)) {
/* There can be only one.. */
static int warn = 1;
}
str = buf;
- end = buf + size - 1;
+ end = buf + size;
- if (end < buf - 1) {
- end = ((void *) -1);
- size = end - buf + 1;
+ /* Make sure end is always >= buf */
+ if (end < buf) {
+ end = ((void *)-1);
+ size = end - buf;
}
for (; *fmt ; ++fmt) {
if (*fmt != '%') {
- if (str <= end)
+ if (str < end)
*str = *fmt;
++str;
continue;
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
- *fmt =='Z' || *fmt == 'z') {
+ *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
qualifier = *fmt;
++fmt;
if (qualifier == 'l' && *fmt == 'l') {
case 'c':
if (!(flags & LEFT)) {
while (--field_width > 0) {
- if (str <= end)
+ if (str < end)
*str = ' ';
++str;
}
}
c = (unsigned char) va_arg(args, int);
- if (str <= end)
+ if (str < end)
*str = c;
++str;
while (--field_width > 0) {
- if (str <= end)
+ if (str < end)
*str = ' ';
++str;
}
if (!(flags & LEFT)) {
while (len < field_width--) {
- if (str <= end)
+ if (str < end)
*str = ' ';
++str;
}
}
for (i = 0; i < len; ++i) {
- if (str <= end)
+ if (str < end)
*str = *s;
++str; ++s;
}
while (len < field_width--) {
- if (str <= end)
+ if (str < end)
*str = ' ';
++str;
}
continue;
case '%':
- if (str <= end)
+ if (str < end)
*str = '%';
++str;
continue;
break;
default:
- if (str <= end)
+ if (str < end)
*str = '%';
++str;
if (*fmt) {
- if (str <= end)
+ if (str < end)
*str = *fmt;
++str;
} else {
num = (signed long) num;
} else if (qualifier == 'Z' || qualifier == 'z') {
num = va_arg(args, size_t);
+ } else if (qualifier == 't') {
+ num = va_arg(args, ptrdiff_t);
} else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & SIGN)
str = number(str, end, num, base,
field_width, precision, flags);
}
- if (str <= end)
- *str = '\0';
- else if (size > 0)
- /* don't write out a null byte if the buf size is zero */
- *end = '\0';
- /* the trailing null byte doesn't count towards the total
- * ++str;
- */
+ if (size > 0) {
+ if (str < end)
+ *str = '\0';
+ else
+ end[-1] = '\0';
+ }
+ /* the trailing null byte doesn't count towards the total */
return str-buf;
}
*/
int vsprintf(char *buf, const char *fmt, va_list args)
{
- return vsnprintf(buf, (~0U)>>1, fmt, args);
+ return vsnprintf(buf, INT_MAX, fmt, args);
}
EXPORT_SYMBOL(vsprintf);
int i;
va_start(args, fmt);
- i=vsprintf(buf,fmt,args);
+ i=vsnprintf(buf, INT_MAX, fmt, args);
va_end(args);
return i;
}
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
*fmt == 'Z' || *fmt == 'z') {
- qualifier = *fmt;
- fmt++;
+ qualifier = *fmt++;
+ if (unlikely(qualifier == *fmt)) {
+ if (qualifier == 'h') {
+ qualifier = 'H';
+ fmt++;
+ } else if (qualifier == 'l') {
+ qualifier = 'L';
+ fmt++;
+ }
+ }
}
base = 10;
is_sign = 0;
break;
switch(qualifier) {
+ case 'H': /* that's 'hh' in format */
+ if (is_sign) {
+ signed char *s = (signed char *) va_arg(args,signed char *);
+ *s = (signed char) simple_strtol(str,&next,base);
+ } else {
+ unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
+ *s = (unsigned char) simple_strtoul(str, &next, base);
+ }
+ break;
case 'h':
if (is_sign) {
short *s = (short *) va_arg(args,short *);
}
EXPORT_SYMBOL(sscanf);
+
+
+/* Simplified asprintf. */
+char *kasprintf(gfp_t gfp, const char *fmt, ...)
+{
+ va_list ap;
+ unsigned int len;
+ char *p;
+
+ va_start(ap, fmt);
+ len = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ p = kmalloc(len+1, gfp);
+ if (!p)
+ return NULL;
+ va_start(ap, fmt);
+ vsnprintf(p, len+1, fmt, ap);
+ va_end(ap);
+ return p;
+}
+
+EXPORT_SYMBOL(kasprintf);