Author: blueswirl Date: 2007-05-19 14:51:04 +0200 (Sat, 19 May 2007) New Revision: 148
Modified: openbios-devel/libc/vsprintf.c Log: Update vsprintf.c from Linux to get 64-bit output
Modified: openbios-devel/libc/vsprintf.c =================================================================== --- openbios-devel/libc/vsprintf.c 2007-05-17 19:16:06 UTC (rev 147) +++ openbios-devel/libc/vsprintf.c 2007-05-19 12:51:04 UTC (rev 148) @@ -5,7 +5,7 @@ /* * linux/lib/vsprintf.c * - * Copyright (C) 1991, 1992, Linus Torvalds + * Copyright (C) 1991, 1992 Linus Torvalds */
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ @@ -13,18 +13,20 @@ * Wirzenius wrote this portably, Torvalds fucked it up :-) */
+/* + * Fri Jul 13 2001 Crutcher Dunnavant crutcher+kernel@datastacks.com + * - changed to provide snprintf and vsnprintf functions + */ + #include "openbios/config.h" #include "libc/string.h" #include "libc/vsprintf.h"
-/* we use this so that we can do without the ctype library */ -#define is_digit(c) ((c) >= '0' && (c) <= '9') - static int skip_atoi(const char **s) { int i=0;
- while (is_digit(**s)) + while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; return i; } @@ -39,21 +41,25 @@
#define do_div(n,base) ({ \ int __res; \ -__res = ((unsigned long) n) % (unsigned) base; \ -n = ((unsigned long) n) / (unsigned) base; \ +__res = ((unsigned long long) n) % (unsigned) base; \ +n = ((unsigned long long) n) / (unsigned) base; \ __res; })
static int mstrlen( const char *str );
-static char * number(char * str, long num, int base, int size, int precision - ,int type) +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type) { char c,sign,tmp[66]; - const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + const char *digits; + static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int i;
- if (type & LARGE) - digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + digits = (type & LARGE) ? large_digits : small_digits; if (type & LEFT) type &= ~ZEROPAD; if (base < 2 || base > 36) @@ -82,52 +88,78 @@ i = 0; if (num == 0) tmp[i++]='0'; - else while (num != 0) { -#if 0 + else while (num != 0) tmp[i++] = digits[do_div(num,base)]; -#endif - int __res; - __res = ((unsigned long) num) % (unsigned) base; - num = ((unsigned long) num) / (unsigned) base; - tmp[i++] = digits[__res]; - } if (i > precision) precision = i; size -= precision; - if (!(type&(ZEROPAD+LEFT))) - while(size-->0) - *str++ = ' '; - if (sign) - *str++ = sign; + if (!(type&(ZEROPAD+LEFT))) { + while(size-->0) { + if (buf <= end) + *buf = ' '; + ++buf; + } + } + if (sign) { + if (buf <= end) + *buf = sign; + ++buf; + } if (type & SPECIAL) { - if (base==8) - *str++ = '0'; - else if (base==16) { - *str++ = '0'; - *str++ = digits[33]; + if (base==8) { + if (buf <= end) + *buf = '0'; + ++buf; + } else if (base==16) { + if (buf <= end) + *buf = '0'; + ++buf; + if (buf <= end) + *buf = digits[33]; + ++buf; } } - if (!(type & LEFT)) - while (size-- > 0) - *str++ = c; - while (i < precision--) - *str++ = '0'; - while (i-- > 0) - *str++ = tmp[i]; - while (size-- > 0) - *str++ = ' '; - return str; + if (!(type & LEFT)) { + while (size-- > 0) { + if (buf <= end) + *buf = c; + ++buf; + } + } + while (i < precision--) { + if (buf <= end) + *buf = '0'; + ++buf; + } + while (i-- > 0) { + if (buf <= end) + *buf = tmp[i]; + ++buf; + } + while (size-- > 0) { + if (buf <= end) + *buf = ' '; + ++buf; + } + return buf; }
-/* Forward decl. to keep compiler happy. */ -//static int vsprintf(char *buf, const char *fmt, va_list args); - -int vsprintf(char *buf, const char *fmt, va_list args) +/** +* vsnprintf - Format a string and place it in a buffer +* @buf: The buffer to place the result into +* @size: The size of the buffer, including the trailing null space +* @fmt: The format string to use +* @args: Arguments for the format string +* +* Call this function if you are already dealing with a va_list. +* You probably want snprintf instead. + */ +int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { int len; - unsigned long num; + unsigned long long num; int i, base; - char * str; + char *str, *end, c; const char *s;
int flags; /* flags to number() */ @@ -136,13 +168,25 @@ int precision; /* min. # of digits for integers; max number of chars for from string */ 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 */
- for (str=buf ; *fmt ; ++fmt) { + str = buf; + end = buf + size - 1; + + if (end < buf - 1) { + end = ((void *) -1); + size = end - buf + 1; + } + + for (; *fmt ; ++fmt) { if (*fmt != '%') { - *str++ = *fmt; + if (str <= end) + *str = *fmt; + ++str; continue; } - + /* process flags */ flags = 0; repeat: @@ -153,11 +197,11 @@ case ' ': flags |= SPACE; goto repeat; case '#': flags |= SPECIAL; goto repeat; case '0': flags |= ZEROPAD; goto repeat; - } - + } + /* get field width */ field_width = -1; - if (is_digit(*fmt)) + if (isdigit(*fmt)) field_width = skip_atoi(&fmt); else if (*fmt == '*') { ++fmt; @@ -173,7 +217,7 @@ precision = -1; if (*fmt == '.') { ++fmt; - if (is_digit(*fmt)) + if (isdigit(*fmt)) precision = skip_atoi(&fmt); else if (*fmt == '*') { ++fmt; @@ -186,109 +230,202 @@
/* get the conversion qualifier */ qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || + *fmt =='Z' || *fmt == 'z') { qualifier = *fmt; ++fmt; + if (qualifier == 'l' && *fmt == 'l') { + qualifier = 'L'; + ++fmt; + } }
/* default base */ base = 10;
switch (*fmt) { - case 'c': - if (!(flags & LEFT)) - while (--field_width > 0) - *str++ = ' '; - *str++ = (unsigned char) va_arg(args, int); - while (--field_width > 0) - *str++ = ' '; - continue; + case 'c': + if (!(flags & LEFT)) { + while (--field_width > 0) { + if (str <= end) + *str = ' '; + ++str; + } + } + c = (unsigned char) va_arg(args, int); + if (str <= end) + *str = c; + ++str; + while (--field_width > 0) { + if (str <= end) + *str = ' '; + ++str; + } + continue;
- case 's': - s = va_arg(args, char *); - if (!s) - s = "<NULL>"; + case 's': + s = va_arg(args, char *); + if ((unsigned long)s < PAGE_SIZE) + s = "<NULL>";
#if 0 - len = strnlen(s, precision); + len = strnlen(s, precision); #else - len = mstrlen(s); - if( precision > len ) - len = precision; + len = mstrlen(s); + if( precision > len ) + len = precision; #endif + if (!(flags & LEFT)) { + while (len < field_width--) { + if (str <= end) + *str = ' '; + ++str; + } + } + for (i = 0; i < len; ++i) { + if (str <= end) + *str = *s; + ++str; ++s; + } + while (len < field_width--) { + if (str <= end) + *str = ' '; + ++str; + } + continue;
- if (!(flags & LEFT)) - while (len < field_width--) - *str++ = ' '; - for (i = 0; i < len; ++i) - *str++ = *s++; - while (len < field_width--) - *str++ = ' '; - continue; + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, end, + (unsigned long) va_arg(args, void *), + 16, field_width, precision, flags); + continue;
- case 'p': - if (field_width == -1) { - field_width = 2*sizeof(void *); - flags |= ZEROPAD; - } - str = number(str, - (unsigned long) va_arg(args, void *), 16, - field_width, precision, flags); - continue;
+ case 'n': + /* FIXME: + * What does C99 say about the overflow case here? */ + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else if (qualifier == 'Z' || qualifier == 'z') { + size_t * ip = va_arg(args, size_t *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue;
- case 'n': - if (qualifier == 'l') { - long * ip = va_arg(args, long *); - *ip = (str - buf); - } else { - int * ip = va_arg(args, int *); - *ip = (str - buf); - } - continue; + case '%': + if (str <= end) + *str = '%'; + ++str; + continue;
- /* integer number formats - set up the flags and "break" */ - case 'o': - base = 8; - break; + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break;
- case 'X': - flags |= LARGE; - case 'x': - base = 16; - break; + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break;
- case 'd': - case 'i': - flags |= SIGN; - case 'u': - break; + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break;
- default: - if (*fmt != '%') - *str++ = '%'; - if (*fmt) - *str++ = *fmt; - else - --fmt; - continue; + default: + if (str <= end) + *str = '%'; + ++str; + if (*fmt) { + if (str <= end) + *str = *fmt; + ++str; + } else { + --fmt; + } + continue; } - if (qualifier == 'l') + if (qualifier == 'L') + num = va_arg(args, long long); + else if (qualifier == 'l') { num = va_arg(args, unsigned long); - else if (qualifier == 'h') { + if (flags & SIGN) + num = (signed long) num; + } else if (qualifier == 'Z' || qualifier == 'z') { + num = va_arg(args, size_t); + } else if (qualifier == 'h') { num = (unsigned short) va_arg(args, int); if (flags & SIGN) - num = (short) num; - } else if (flags & SIGN) - num = va_arg(args, int); - else + num = (signed short) num; + } else { num = va_arg(args, unsigned int); - str = number(str, num, base, field_width, precision, flags); + if (flags & SIGN) + num = (signed int) num; + } + str = number(str, end, num, base, + field_width, precision, flags); } - *str = '\0'; + 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; + */ return str-buf; }
+/** + * snprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @size: The size of the buffer, including the trailing null space + * @fmt: The format string to use + * @...: Arguments for the format string + */ +int snprintf(char * buf, size_t size, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsnprintf(buf,size,fmt,args); + va_end(args); + return i; +} + +/** + * vsprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + * + * Call this function if you are already dealing with a va_list. + * You probably want sprintf instead. + */ +int vsprintf(char *buf, const char *fmt, va_list args) +{ + return vsnprintf(buf, (~0U)>>1, fmt, args); +} + + +/** + * sprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @...: Arguments for the format string + */ int sprintf(char * buf, const char *fmt, ...) { va_list args;