diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2017-07-23 15:28:13 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2017-07-23 15:28:13 +0200 |
commit | ec9ed8deb79a9fd508a11b122453bb39d3b587a9 (patch) | |
tree | 6e35f78af8922083ff5b77dac04e4330e4ac0bb3 | |
parent | ab8803f7cfdc7c7b258fb3e59fb2d55bacf7522a (diff) | |
download | abaos-ec9ed8deb79a9fd508a11b122453bb39d3b587a9.tar.gz abaos-ec9ed8deb79a9fd508a11b122453bb39d3b587a9.tar.bz2 |
added snprintf and a test for it
-rw-r--r-- | src/libc/stdio.c | 101 | ||||
-rw-r--r-- | src/libc/stdio.h | 2 | ||||
-rw-r--r-- | tests/libc/Makefile | 11 | ||||
-rw-r--r-- | tests/libc/test_sprintf.c | 19 |
4 files changed, 131 insertions, 2 deletions
diff --git a/src/libc/stdio.c b/src/libc/stdio.c index 9fdf510..e0b87a8 100644 --- a/src/libc/stdio.c +++ b/src/libc/stdio.c @@ -150,6 +150,107 @@ int vprintf( const char *format, va_list args ) return n; } +int snprintf( char *buf, size_t n, const char *format, ... ) +{ + va_list args; + + va_start( args, format ); + int res = vsnprintf( buf, n, format, args ); + va_end( args ); + + return res; +} + +#define EMIT( x ) if( len < n ) { *buf = ( x ); buf++; *buf = '\0'; len++; } + +#define APPEND_STRING( s, s2 ) \ + strlcat( s, s2, n - len ); \ + s += strlen( s2 ); \ + len += strlen( s2 ); \ + if( len < n ) { \ + *s = '\0'; \ + } + +int vsnprintf( char *buf, size_t n, const char *format, va_list args ) +{ + const char *s = format; + int len = 0; + + *buf = '\0'; + while( *s != '\0' && len < n ) { + switch( *s ) { + case '\n': + EMIT( '\n' ); + break; + + case '%': + s++; + if( *s == '\0' ) { + strlcpy( buf, "<truncated % found at end of format string>", n - len ); + strlcat( buf, "\n", n - len - 1 ); + return -1; + } + + switch( *s ) { + case '%': + EMIT( '%' ); + break; + + case 'X': { + char buf2[19]; + itoa( va_arg( args, int ), (char *)buf2, 16 ); + APPEND_STRING( buf, buf2 ); + } + break; + + case 'd': { + char buf2[19]; + itoa( va_arg( args, int ), (char *)buf2, 10 ); + APPEND_STRING( buf, buf2 ); + } + break; + + case 'c': { + char buf2[2]; + buf2[0] = (char)va_arg( args, int ); + buf2[1] = '\0'; + APPEND_STRING( buf, buf2 ); + } + break; + + case 's': { + const char *s = va_arg( args, const char * ); + APPEND_STRING( buf, s ); + } + break; + + default: { + APPEND_STRING( buf, "<illegal format string %" ); + char buf2[2]; + buf2[0] = (char)( *s ); + buf2[1] = '\0'; + APPEND_STRING( buf, buf2 ); + buf2[0] = '\n'; + APPEND_STRING( buf, buf2 ); + } + } + + break; + + default: { + char buf2[2]; + buf2[0] = (char)( *s ); + buf2[1] = '\0'; + APPEND_STRING( buf, buf2 ); + } + } + s++; + } + + return len; +} + + #ifdef OS_ABAOS void __stdio_set_console( console_t *console ) { diff --git a/src/libc/stdio.h b/src/libc/stdio.h index 58c80b1..e32683f 100644 --- a/src/libc/stdio.h +++ b/src/libc/stdio.h @@ -18,6 +18,8 @@ int puts( const char *s ); int printf( const char *format, ... ); int vprintf( const char *format, va_list args ); +int snprintf( char *buf, size_t n, const char *format, ... ); +int vsnprintf( char *buf, size_t n, const char *format, va_list args ); #ifdef OS_ABAOS void __stdio_set_console( console_t *console ); diff --git a/tests/libc/Makefile b/tests/libc/Makefile index 37c383a..c21263d 100644 --- a/tests/libc/Makefile +++ b/tests/libc/Makefile @@ -37,9 +37,15 @@ test_malloc.o: test_malloc.c ../../src/libc/stdlib.h test_printf: test_printf.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o $(LD) $(LDFLAGS) -o test_printf test_printf.o ../../src/libc/stdio.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o +test_sprintf: test_sprintf.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + $(LD) $(LDFLAGS) -o test_sprintf test_sprintf.o ../../src/libc/stdio.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o + test_printf.o: test_printf.c ../../src/libc/stdlib.h $(CC) $(CFLAGS) -c -o test_printf.o test_printf.c +test_sprintf.o: test_sprintf.c ../../src/libc/stdlib.h + $(CC) $(CFLAGS) -c -o test_sprintf.o test_sprintf.c + test_exit: test_exit.o ../../src/libc/stdlib.o ../../src/libc/stdio.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o $(LD) $(LDFLAGS) -o test_exit test_exit.o ../../src/libc/stdio.o ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/kernel/memorymanagement.o kernel_stub.o kernel_stub_asm.o @@ -64,15 +70,16 @@ kernel_stub.o: kernel_stub.c kernel_stub_asm.o: kernel_stub.asm $(NASM) kernel_stub.asm $(NASMFLAGS) -o kernel_stub_asm.o -test: test_strlcpy test_strlcat test_itoa test_malloc test_exit test_printf +test: test_strlcpy test_strlcat test_itoa test_malloc test_exit test_printf test_sprintf ./test_strlcpy ./test_strlcat ./test_itoa ./test_malloc ./test_printf + ./test_sprintf ./test_exit clean: - -rm -f test_strlcpy test_strlcat test_itoa test_malloc test_printf test_exit + -rm -f test_strlcpy test_strlcat test_itoa test_malloc test_printf test_sprintf test_exit -rm -f ../../src/libc/stdlib.o ../../src/libc/string.o ../../src/libc/stdio.o ../../src/kernel/memorymanagement.o -rm -f *.o diff --git a/tests/libc/test_sprintf.c b/tests/libc/test_sprintf.c new file mode 100644 index 0000000..b1f25c7 --- /dev/null +++ b/tests/libc/test_sprintf.c @@ -0,0 +1,19 @@ +#include "string.h" +#include "stdlib.h" +#include "stdio.h" +#include "string.h" + +int main( void ) +{ + char *s = "test_string"; + int i = 47; + char c = 'X'; + char buf[100]; + const char *must = "string 'test_string', decimal 47, hex 0x2F, character 'X'\n"; + + snprintf( buf, 100, "string '%s', decimal %d, hex 0x%X, character '%c'\n", + s, i, i, c ); + if( strncmp( buf, must, strlen( must ) ) != 0 ) exit( 1 ); + + exit( 0 ); +} |