diff options
Diffstat (limited to 'qemu/roms/openbios/libc')
-rw-r--r-- | qemu/roms/openbios/libc/build.xml | 12 | ||||
-rw-r--r-- | qemu/roms/openbios/libc/ctype.c | 34 | ||||
-rw-r--r-- | qemu/roms/openbios/libc/diskio.c | 248 | ||||
-rw-r--r-- | qemu/roms/openbios/libc/extra.c | 49 | ||||
-rw-r--r-- | qemu/roms/openbios/libc/misc.c | 144 | ||||
-rw-r--r-- | qemu/roms/openbios/libc/string.c | 387 | ||||
-rw-r--r-- | qemu/roms/openbios/libc/vsprintf.c | 448 |
7 files changed, 1322 insertions, 0 deletions
diff --git a/qemu/roms/openbios/libc/build.xml b/qemu/roms/openbios/libc/build.xml new file mode 100644 index 000000000..cb2b560db --- /dev/null +++ b/qemu/roms/openbios/libc/build.xml @@ -0,0 +1,12 @@ +<build> + + <library name="libc" type="static" target="target"> + <object source="ctype.c"/> + <object source="diskio.c"/> + <object source="extra.c"/> + <object source="misc.c"/> + <object source="string.c"/> + <object source="vsprintf.c"/> + </library> + +</build> diff --git a/qemu/roms/openbios/libc/ctype.c b/qemu/roms/openbios/libc/ctype.c new file mode 100644 index 000000000..c433f6c62 --- /dev/null +++ b/qemu/roms/openbios/libc/ctype.c @@ -0,0 +1,34 @@ +/* + * linux/lib/ctype.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include "config.h" +#include "libc/string.h" + +const unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ diff --git a/qemu/roms/openbios/libc/diskio.c b/qemu/roms/openbios/libc/diskio.c new file mode 100644 index 000000000..23f38ebb2 --- /dev/null +++ b/qemu/roms/openbios/libc/diskio.c @@ -0,0 +1,248 @@ +/* + * Creation Date: <2003/12/07 19:36:00 samuel> + * Time-stamp: <2004/01/07 19:28:43 samuel> + * + * <diskio.c> + * + * I/O wrappers + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "config.h" +#include "libopenbios/bindings.h" +#include "libc/diskio.h" + +//#define CONFIG_DEBUG_DISKIO +#ifdef CONFIG_DEBUG_DISKIO +#define DPRINTF(fmt, args...) \ + do { printk(fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +typedef struct { + ihandle_t ih; + int do_close; + xt_t read_xt; + xt_t seek_xt; + + xt_t reopen_xt; + xt_t tell_xt; + xt_t get_path_xt; + xt_t get_fstype_xt; + xt_t open_nwrom_xt; + xt_t volume_name_xt; +} priv_fd_t; + +#define MAX_FD 32 +static priv_fd_t *file_descriptors[MAX_FD]; + +static int +lookup_xt( ihandle_t ih, const char *method, xt_t *xt ) +{ + if( *xt ) + return 0; + *xt = find_ih_method( method, ih ); + return (*xt) ? 0:1; +} + +int +open_ih( ihandle_t ih ) +{ + xt_t read_xt=0, seek_xt=0; + priv_fd_t *fdp; + int fd; + + if( !ih || lookup_xt(ih, "read", &read_xt) ) + return -1; + if( lookup_xt(ih, "seek", &seek_xt) ) + return -1; + + for (fd=0; fd<MAX_FD; fd++) + if(file_descriptors[fd]==NULL) + break; + if(fd==MAX_FD) + return -1; + + fdp = malloc( sizeof(*fdp) ); + /* Better clear the fd, as it + * contains valuable information + */ + memset(fdp, 0, sizeof(*fdp)); + fdp->ih = ih; + fdp->read_xt = read_xt; + fdp->seek_xt = seek_xt; + fdp->do_close = 0; + + file_descriptors[fd]=fdp; + DPRINTF("%s(0x%lx) = %d\n", __func__, (unsigned long)ih, fd); + return fd; +} + +int +open_io( const char *spec ) +{ + int fd; + ihandle_t ih = open_dev( spec ); + priv_fd_t *fdp; + + DPRINTF("%s(%s)\n", __func__, spec); + if( !ih ) + return -1; + + if( (fd=open_ih(ih)) == -1 ) { + close_dev( ih ); + return -1; + } + + fdp = file_descriptors[fd]; + fdp->do_close = 1; + + return fd; +} + +int +reopen( int fd, const char *filename ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + int ret; + + if( lookup_xt(fdp->ih, "reopen", &fdp->reopen_xt) ) + return -1; + + push_str( filename ); + call_package( fdp->reopen_xt, fdp->ih ); + ret = (POP() == (ucell)-1)? 0 : -1; + + DPRINTF("%s(%d, %s) = %d\n", __func__, fd, filename, ret); + return ret; +} + +int +reopen_nwrom( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + + DPRINTF("%s(%d)\n", __func__, fd); + if( lookup_xt(fdp->ih, "open-nwrom", &fdp->open_nwrom_xt) ) + return -1; + call_package( fdp->open_nwrom_xt, fdp->ih ); + return (POP() == (ucell)-1)? 0 : -1; +} + +ihandle_t +get_ih_from_fd( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + return fdp->ih; +} + +const char * +get_file_path( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + if( lookup_xt(fdp->ih, "get-path", &fdp->get_path_xt) ) + return NULL; + call_package( fdp->get_path_xt, fdp->ih ); + return (char*)cell2pointer(POP()); +} + +const char * +get_volume_name( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + if( lookup_xt(fdp->ih, "volume-name", &fdp->volume_name_xt) ) + return NULL; + call_package( fdp->volume_name_xt, fdp->ih ); + return (char*)cell2pointer(POP()); +} + +const char * +get_fstype( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + if( lookup_xt(fdp->ih, "get-fstype", &fdp->get_fstype_xt) ) + return NULL; + call_package( fdp->get_fstype_xt, fdp->ih ); + return (char*)cell2pointer(POP()); +} + +int +read_io( int fd, void *buf, size_t cnt ) +{ + priv_fd_t *fdp; + ucell ret; + + DPRINTF("%s(%d, %p, %u)\n", __func__, fd, buf, cnt); + if (fd != -1) { + fdp = file_descriptors[fd]; + + PUSH( pointer2cell(buf) ); + PUSH( cnt ); + call_package( fdp->read_xt, fdp->ih ); + ret = POP(); + + if( !ret && cnt ) + ret = -1; + } else { + ret = -1; + } + + return ret; +} + +int +seek_io( int fd, long long offs ) +{ + priv_fd_t *fdp; + + DPRINTF("%s(%d, %lld)\n", __func__, fd, offs); + if (fd != -1) { + fdp = file_descriptors[fd]; + + DPUSH( offs ); + call_package( fdp->seek_xt, fdp->ih ); + return ((((cell)POP()) >= 0)? 0 : -1); + } else { + return -1; + } +} + +long long +tell( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + long long offs; + + if( lookup_xt(fdp->ih, "tell", &fdp->tell_xt) ) + return -1; + call_package( fdp->tell_xt, fdp->ih ); + offs = DPOP(); + DPRINTF("%s(%d) = %lld\n", __func__, fd, offs); + return offs; +} + +int +close_io( int fd ) +{ + priv_fd_t *fdp; + + DPRINTF("%s(%d)\n", __func__, fd); + if (fd != -1) { + fdp = file_descriptors[fd]; + + if( fdp->do_close ) + close_dev( fdp->ih ); + free( fdp ); + + file_descriptors[fd]=NULL; + } + + return 0; +} diff --git a/qemu/roms/openbios/libc/extra.c b/qemu/roms/openbios/libc/extra.c new file mode 100644 index 000000000..85731ade9 --- /dev/null +++ b/qemu/roms/openbios/libc/extra.c @@ -0,0 +1,49 @@ +/* + * Creation Date: <2003/10/18 13:52:32 samuel> + * Time-stamp: <2003/10/18 13:54:24 samuel> + * + * <extra.c> + * + * Libc extras + * + * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "config.h" +#include "libc/string.h" +#include "libc/vsprintf.h" +#include "libopenbios/bindings.h" + +/* strncpy without 0-pad */ +char * +strncpy_nopad( char *dest, const char *src, size_t n ) +{ + int len = MIN( n, strlen(src)+1 ); + return memcpy( dest, src, len ); +} + +/* printf */ + +int forth_printf( const char *fmt, ... ) +{ + char buf[512]; + va_list args; + int i; + + va_start(args, fmt); + i = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + PUSH(pointer2cell(buf)); + PUSH(i); + fword("type"); + + return i; +} + + diff --git a/qemu/roms/openbios/libc/misc.c b/qemu/roms/openbios/libc/misc.c new file mode 100644 index 000000000..e7cf4f408 --- /dev/null +++ b/qemu/roms/openbios/libc/misc.c @@ -0,0 +1,144 @@ +/* + * Creation Date: <2002/10/19 21:05:07 samuel> + * Time-stamp: <2002/10/22 22:29:18 samuel> + * + * <misc.c> + * + * Miscellaneous + * + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "config.h" +#include "libc/string.h" + +int errno_int; + +void +qsort( void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void*) ) +{ + unsigned int worked, i, j; + + /* even more inefficient than the glibc variant :-) */ + do { + char *p = base; + worked = 0; + for( i=0; i<nmemb-1; i++, p+= size ) { + if( compar( p, p + size ) > 0 ) { + worked = 1; + for( j=0; j<size; j++ ) { + char ch = p[j]; + p[j] = p[j+size]; + p[j+size] = ch; + } + } + } + } while( worked ); +} + + +long int +strtol( const char *nptr, char **endptr, int base ) +{ + int sum, n, sign=1; + while( isspace(*nptr) ) + nptr++; + + if( *nptr == '-' || *nptr == '+' ) + sign = (*nptr++ == '-') ? -1 : 1; + + if( base == 16 || base == 0) { + if( !base ) + base = (nptr[0] == '0')? 8 : 10; + if( nptr[0] == '0' && nptr[1] == 'x' ) { + nptr += 2; + base = 16; + } + } + for( sum=0 ;; nptr++ ) { + char ch = *nptr; + if( !isalnum(ch) ) + break; + n = isdigit(ch) ? ch - '0' : toupper(ch) - 'A' + 10; + if( n >= base || n < 0 ) + break; + sum *= base; + sum += n; + } + if( endptr ) + *endptr = (char*)nptr; + + return sum * sign; +} + +long long int +strtoll( const char *nptr, char **endptr, int base ) +{ + long long int sum; + int n, sign=1; + while( isspace(*nptr) ) + nptr++; + + if( *nptr == '-' || *nptr == '+' ) + sign = (*nptr++ == '-') ? -1 : 1; + + if( base == 16 || base == 0) { + if( !base ) + base = (nptr[0] == '0')? 8 : 10; + if( nptr[0] == '0' && nptr[1] == 'x' ) { + nptr += 2; + base = 16; + } + } + for( sum=0 ;; nptr++ ) { + char ch = *nptr; + if( !isalnum(ch) ) + break; + n = isdigit(ch) ? ch - '0' : toupper(ch) - 'A' + 10; + if( n >= base || n < 0 ) + break; + sum *= base; + sum += n; + } + if( endptr ) + *endptr = (char*)nptr; + + return sum * sign; +} + +// Propolice support +long __guard[8] = { +#ifdef CONFIG_BIG_ENDIAN + (0 << 24) | (0 << 16) | ('\n' << 8) | 255, +#else + (255 << 24) | ('\n' << 16) | (0 << 8) | 0, +#endif + 0, 0, 0, 0, 0, 0, 0 +}; + +static void freeze(void) +{ + // Freeze + // XXX: Disable interrupts? + for(;;) + ; +} + +void __stack_smash_handler(const char *func, int damaged) +{ + printk("Propolice detected a stack smashing attack %x at function %s," + " freezing\n", damaged, func); + freeze(); +} + +void __stack_chk_fail(void) +{ + printk("Propolice detected a stack smashing attack, freezing\n"); + + freeze(); +} diff --git a/qemu/roms/openbios/libc/string.c b/qemu/roms/openbios/libc/string.c new file mode 100644 index 000000000..8f62bd7bb --- /dev/null +++ b/qemu/roms/openbios/libc/string.c @@ -0,0 +1,387 @@ +/* + * linux/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * stupid library routines.. The optimized versions should generally be found + * as inline code in <asm-xx/string.h> + * + * These are buggy as well.. + * + * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de> + * - Added strsep() which will replace strtok() soon (because strsep() is + * reentrant and should be faster). Use only strsep() in new code, please. + */ + +#include "config.h" +#include "libc/string.h" +#include "libc/stdlib.h" + +/** + * strnicmp - Case insensitive, length-limited string comparison + * @s1: One string + * @s2: The other string + * @len: the maximum number of characters to compare + */ +int strnicmp(const char *s1, const char *s2, size_t len) +{ + /* Yes, Virginia, it had better be unsigned */ + unsigned char c1, c2; + + c1 = 0; c2 = 0; + if (len) { + do { + c1 = *s1; c2 = *s2; + s1++; s2++; + if (!c1) + break; + if (!c2) + break; + if (c1 == c2) + continue; + c1 = tolower(c1); + c2 = tolower(c2); + if (c1 != c2) + break; + } while (--len); + } + return (int)c1 - (int)c2; +} + +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + */ +char * strcpy(char * dest,const char *src) +{ + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + /* nothing */; + return tmp; +} + +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @count: The maximum number of bytes to copy + * + * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. + * However, the result is not %NUL-terminated if the source exceeds + * @count bytes. + */ +char * strncpy(char * dest,const char *src,size_t count) +{ + char *tmp = dest; + + while (count-- && (*dest++ = *src++) != '\0') + /* nothing */; + + return tmp; +} + +/** + * strcat - Append one %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + */ +char * strcat(char * dest, const char * src) +{ + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return tmp; +} + +/** + * strncat - Append a length-limited, %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * @count: The maximum numbers of bytes to copy + * + * Note that in contrast to strncpy, strncat ensures the result is + * terminated. + */ +char * strncat(char *dest, const char *src, size_t count) +{ + char *tmp = dest; + + if (count) { + while (*dest) + dest++; + while ((*dest++ = *src++)) { + if (--count == 0) { + *dest = '\0'; + break; + } + } + } + + return tmp; +} + +/** + * strcmp - Compare two strings + * @cs: One string + * @ct: Another string + */ +int strcmp(const char * cs,const char * ct) +{ + register signed char __res; + + while (1) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + } + + return __res; +} + +/** + * strncmp - Compare two length-limited strings + * @cs: One string + * @ct: Another string + * @count: The maximum number of bytes to compare + */ +int strncmp(const char * cs,const char * ct,size_t count) +{ + register signed char __res = 0; + + while (count) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} + + +/** + * strchr - Find the first occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char * strchr(const char * s, int c) +{ + for(; *s != (char) c; ++s) + if (*s == '\0') + return NULL; + return (char *) s; +} + +/** + * strrchr - Find the last occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char * strrchr(const char * s, int c) +{ + const char *p = s + strlen(s); + do { + if (*p == (char)c) + return (char *)p; + } while (--p >= s); + return NULL; +} + +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t strlen(const char * s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +/** + * strpbrk - Find the first occurrence of a set of characters + * @cs: The string to be searched + * @ct: The characters to search for + */ +char * strpbrk(const char * cs,const char * ct) +{ + const char *sc1,*sc2; + + for( sc1 = cs; *sc1 != '\0'; ++sc1) { + for( sc2 = ct; *sc2 != '\0'; ++sc2) { + if (*sc1 == *sc2) + return (char *) sc1; + } + } + return NULL; +} + +/** + * strsep - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * strsep() updates @s to point after the token, ready for the next call. + * + * It returns empty tokens, too, behaving exactly like the libc function + * of that name. In fact, it was stolen from glibc2 and de-fancy-fied. + * Same semantics, slimmer shape. ;) + */ +char * strsep(char **s, const char *ct) +{ + char *sbegin = *s, *end; + + if (sbegin == NULL) + return NULL; + + end = strpbrk(sbegin, ct); + if (end) + *end++ = '\0'; + *s = end; + + return sbegin; +} + +/** + * memset - Fill a region of memory with the given value + * @s: Pointer to the start of the area. + * @c: The byte to fill the area with + * @count: The size of the area. + * + * Do not use memset() to access IO space, use memset_io() instead. + */ +void * memset(void * s,int c,size_t count) +{ + char *xs = (char *) s; + + while (count--) + *xs++ = c; + + return s; +} + +/** + * memcpy - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. + */ +void * memcpy(void * dest,const void *src,size_t count) +{ + char *tmp = (char *) dest, *s = (char *) src; + + while (count--) + *tmp++ = *s++; + + return dest; +} + +/** + * memmove - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +void * memmove(void * dest,const void *src,size_t count) +{ + char *tmp, *s; + + if (dest <= src) { + tmp = (char *) dest; + s = (char *) src; + while (count--) + *tmp++ = *s++; + } + else { + tmp = (char *) dest + count; + s = (char *) src + count; + while (count--) + *--tmp = *--s; + } + + return dest; +} + +/** + * memcmp - Compare two areas of memory + * @cs: One area of memory + * @ct: Another area of memory + * @count: The size of the area. + */ +int memcmp(const void * cs,const void * ct,size_t count) +{ + const unsigned char *su1, *su2; + int res = 0; + + for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} + +char * +strdup( const char *str ) +{ + char *p; + if( !str ) + return NULL; + p = malloc( strlen(str) + 1 ); + strcpy( p, str ); + return p; +} + +int +strcasecmp( const char *cs, const char *ct ) +{ + register signed char __res; + + while (1) { + char ch1 = toupper(*cs), ch2 = toupper(*ct); + ct++; + if ((__res = ch1 - ch2) != 0 || !*cs++) + break; + } + return __res; +} + +int +strncasecmp( const char *cs, const char *ct, size_t count ) +{ + register signed char __res = 0; + + while (count--) { + char ch1 = toupper(*cs), ch2 = toupper(*ct); + ct++; + if ((__res = ch1 - ch2) != 0 || !*cs++) + break; + } + return __res; +} + diff --git a/qemu/roms/openbios/libc/vsprintf.c b/qemu/roms/openbios/libc/vsprintf.c new file mode 100644 index 000000000..29ec7b96e --- /dev/null +++ b/qemu/roms/openbios/libc/vsprintf.c @@ -0,0 +1,448 @@ +/* + * String functions for logger. + */ + +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * 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 "config.h" +#include "libc/string.h" +#include "libc/vsprintf.h" + +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long long) n) % (unsigned) base; \ +n = ((unsigned long long) n) / (unsigned) base; \ +__res; }) + +static int mstrlen( const char *str ); + +#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; + static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + digits = (type & LARGE) ? large_digits : small_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return NULL; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + 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) { + 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) { + 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; +} + +/** +* 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 long num; + int i, base; + char *str, *end, c; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + 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 */ + + str = buf; + end = buf + size - 1; + + if (end < buf - 1) { + end = ((void *) -1); + size = end - buf + 1; + } + + for (; *fmt ; ++fmt) { + if (*fmt != '%') { + if (str <= end) + *str = *fmt; + ++str; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + 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) { + 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 ((unsigned long)s < PAGE_SIZE) + s = "<NULL>"; + +#if 0 + len = strnlen(s, precision); +#else + 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; + + 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 '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 '%': + if (str <= end) + *str = '%'; + ++str; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (str <= end) + *str = '%'; + ++str; + if (*fmt) { + if (str <= end) + *str = *fmt; + ++str; + } else { + --fmt; + } + continue; + } + if (qualifier == 'L') + num = va_arg(args, long long); + else if (qualifier == 'l') { + num = va_arg(args, unsigned long); + 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 = (signed short) num; + } else { + num = va_arg(args, unsigned int); + if (flags & SIGN) + num = (signed int) num; + } + 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; + */ + 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; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +static int mstrlen( const char *str ) +{ + int i=0; + if( str == NULL ) + return 0; + while( *str++ ) + i++; + return i; +} |