summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-07-23 15:28:13 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2017-07-23 15:28:13 +0200
commitec9ed8deb79a9fd508a11b122453bb39d3b587a9 (patch)
tree6e35f78af8922083ff5b77dac04e4330e4ac0bb3
parentab8803f7cfdc7c7b258fb3e59fb2d55bacf7522a (diff)
downloadabaos-ec9ed8deb79a9fd508a11b122453bb39d3b587a9.tar.gz
abaos-ec9ed8deb79a9fd508a11b122453bb39d3b587a9.tar.bz2
added snprintf and a test for it
-rw-r--r--src/libc/stdio.c101
-rw-r--r--src/libc/stdio.h2
-rw-r--r--tests/libc/Makefile11
-rw-r--r--tests/libc/test_sprintf.c19
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 );
+}