From ec7e0cc9a64b9555c516f199ff29a26cab3d90bd Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Wed, 13 Aug 2014 19:15:20 +0200 Subject: [PATCH] Add cbprintf(3) and vcbprintf(3). Thanks to Owen Shepherd of the Public Domain C Library for helping design and formalize these interfaces. --- kernel/debugger.cpp | 2 +- kernel/include/sortix/kernel/log.h | 12 +++- libc/Makefile | 3 +- libc/include/stdio.h | 9 ++- libc/stdio/cbprintf.cpp | 39 +++++++++++ libc/stdio/vasprintf.cpp | 4 +- .../{vprintf_callback.cpp => vcbprintf.cpp} | 67 ++++++++++--------- libc/stdio/vdprintf.cpp | 6 +- libc/stdio/vfprintf_unlocked.cpp | 5 +- libc/stdio/vsnprintf.cpp | 6 +- 10 files changed, 98 insertions(+), 55 deletions(-) create mode 100644 libc/stdio/cbprintf.cpp rename libc/stdio/{vprintf_callback.cpp => vcbprintf.cpp} (91%) diff --git a/kernel/debugger.cpp b/kernel/debugger.cpp index 74878649..07b6c9bc 100644 --- a/kernel/debugger.cpp +++ b/kernel/debugger.cpp @@ -153,7 +153,7 @@ void Print(const char* format, ...) { va_list ap; va_start(ap, format); - vprintf_callback(PrintCallback, NULL, format, ap); + vcbprintf(NULL, PrintCallback, format, ap); va_end(ap); } diff --git a/kernel/include/sortix/kernel/log.h b/kernel/include/sortix/kernel/log.h index 986c5c03..ab07400a 100644 --- a/kernel/include/sortix/kernel/log.h +++ b/kernel/include/sortix/kernel/log.h @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace Sortix { @@ -95,15 +96,20 @@ inline size_t PrintF(const char* format, ...) { va_list list; va_start(list, format); - size_t result = vprintf_callback(device_callback, device_pointer, format, list); + int result = vcbprintf(device_pointer, device_callback, format, list); va_end(list); - return result; + if ( result < 0 ) + return SIZE_MAX; + return (size_t) result; } __attribute__((format(printf, 1, 0))) inline size_t PrintFV(const char* format, va_list list) { - return vprintf_callback(device_callback, device_pointer, format, list); + int result = vcbprintf(device_pointer, device_callback, format, list); + if ( result < 0 ) + return SIZE_MAX; + return (size_t) result; } } // namespace Log diff --git a/libc/Makefile b/libc/Makefile index 4585f10c..b1d6ac03 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -67,6 +67,7 @@ signal/sigorset.o \ stdio/asprintf.o \ stdio/clearerr.o \ stdio/clearerr_unlocked.o \ +stdio/cbprintf.o \ stdio/dprintf.o \ stdio/fbufsize.o \ stdio/fbufsize_unlocked.o \ @@ -142,11 +143,11 @@ stdio/sscanf.o \ stdio/ungetc.o \ stdio/ungetc_unlocked.o \ stdio/vasprintf.o \ +stdio/vcbprintf.o \ stdio/vdprintf.o \ stdio/vfprintf_unlocked.o \ stdio/vfscanf.o \ stdio/vfscanf_unlocked.o \ -stdio/vprintf_callback.o \ stdio/vscanf_callback.o \ stdio/vsnprintf.o \ stdio/vsprintf.o \ diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 2fcd00fa..107d67cf 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -320,12 +320,11 @@ void fpurge_unlocked(FILE* fp); size_t fpending_unlocked(FILE* fp); #endif -/* The Sortix backends for *printf and *scanf. */ +/* The backends for printf and scanf. */ #if __USE_SORTIX -size_t vprintf_callback(size_t (*callback)(void*, const char*, size_t), - void* user, - const char* __restrict format, - __gnuc_va_list ap) +int cbprintf(void*, size_t (*)(void*, const char*, size_t), const char*, ...) + __attribute__((__format__ (printf, 3, 4))); +int vcbprintf(void*, size_t (*)(void*, const char*, size_t), const char*, __gnuc_va_list ap) __attribute__((__format__ (printf, 3, 0))); int vscanf_callback(void* fp, int (*fgetc)(void*), diff --git a/libc/stdio/cbprintf.cpp b/libc/stdio/cbprintf.cpp new file mode 100644 index 00000000..018a040d --- /dev/null +++ b/libc/stdio/cbprintf.cpp @@ -0,0 +1,39 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + stdio/cbprintf.cpp + Formats text and outputs it via callback functions. + +*******************************************************************************/ + +#include +#include + +extern "C" +int cbprintf(void* user, + size_t (*callback)(void*, const char*, size_t), + const char* format, + ...) +{ + va_list ap; + va_start(ap, format); + int result = vcbprintf(user, callback, format, ap); + va_end(ap); + return result; +} diff --git a/libc/stdio/vasprintf.cpp b/libc/stdio/vasprintf.cpp index 584fecd7..345acf79 100644 --- a/libc/stdio/vasprintf.cpp +++ b/libc/stdio/vasprintf.cpp @@ -72,9 +72,9 @@ int vasprintf(char** restrict result_ptr, state.string_used = 0; if ( !(state.string = (char*) malloc(state.string_length * sizeof(char))) ) return *result_ptr = NULL, -1; - vprintf_callback(vasprintf_callback, &state, format, list); + int result = vcbprintf(&state, vasprintf_callback, format, list); if ( !state.string ) return *result_ptr = NULL, -1; state.string[state.string_used] = '\0'; - return *result_ptr = state.string, (int) state.string_used; + return *result_ptr = state.string, result; } diff --git a/libc/stdio/vprintf_callback.cpp b/libc/stdio/vcbprintf.cpp similarity index 91% rename from libc/stdio/vprintf_callback.cpp rename to libc/stdio/vcbprintf.cpp index f383535d..09741a98 100644 --- a/libc/stdio/vprintf_callback.cpp +++ b/libc/stdio/vcbprintf.cpp @@ -17,15 +17,13 @@ You should have received a copy of the GNU Lesser General Public License along with the Sortix C Library. If not, see . - stdio/vprintf_callback.cpp - Provides printf formatting functions that uses callbacks. + stdio/vcbprintf.cpp + Formats text and outputs it via callback functions. *******************************************************************************/ -// Number of bugs seemingly unrelated bugs that have been traced to here: -// Countless + 2 - #include +#include #include #include #include @@ -51,19 +49,19 @@ static size_t noop_callback(void*, const char*, size_t amount) return amount; } -static -size_t callback_character(size_t (*callback)(void*, const char*, size_t), - void* user, +static inline +size_t callback_character(void* user, + size_t (*callback)(void*, const char*, size_t), char c) { return callback(user, &c, 1); } extern "C" -size_t vprintf_callback(size_t (*callback)(void*, const char*, size_t), - void* user, - const char* restrict format, - va_list parameters) +int vcbprintf(void* user, + size_t (*callback)(void*, const char*, size_t), + const char* format, + va_list parameters) { if ( !callback ) callback = noop_callback; @@ -80,7 +78,7 @@ size_t vprintf_callback(size_t (*callback)(void*, const char*, size_t), while ( format[amount] && format[amount] != '%' ) amount++; if ( callback(user, format, amount) != amount ) - return SIZE_MAX; + return -1; format += amount; written += amount; continue; @@ -311,32 +309,32 @@ size_t vprintf_callback(size_t (*callback)(void*, const char*, size_t), if ( use_left_pad ) for ( size_t i = length_with_precision; i < abs_field_width; i++ ) - if ( callback_character(callback, user, ' ') != 1 ) - return SIZE_MAX; + if ( callback_character(user, callback, ' ') != 1 ) + return -1; else written++; if ( callback(user, prefix, prefix_length) != prefix_length ) - return SIZE_MAX; + return -1; written += prefix_length; if ( use_zero_pad ) for ( size_t i = normal_length; i < abs_field_width; i++ ) - if ( callback_character(callback, user, '0') != 1 ) - return SIZE_MAX; + if ( callback_character(user, callback, '0') != 1 ) + return -1; else written++; if ( use_precision ) for ( size_t i = digits_length; i < precision; i++ ) - if ( callback_character(callback, user, '0') != 1 ) - return SIZE_MAX; + if ( callback_character(user, callback, '0') != 1 ) + return -1; else written++; if ( callback(user, output, output_length) != output_length ) - return SIZE_MAX; + return -1; written += output_length; if ( use_right_pad ) for ( size_t i = length_with_precision; i < abs_field_width; i++ ) - if ( callback_character(callback, user, ' ') != 1 ) - return SIZE_MAX; + if ( callback_character(user, callback, ' ') != 1 ) + return -1; else written++; } @@ -379,19 +377,19 @@ size_t vprintf_callback(size_t (*callback)(void*, const char*, size_t), if ( !field_width_is_negative && 1 < abs_field_width ) for ( size_t i = 1; i < abs_field_width; i++ ) - if ( callback_character(callback, user, ' ') != 1 ) - return SIZE_MAX; + if ( callback_character(user, callback, ' ') != 1 ) + return -1; else written++; if ( callback(user, &c, 1) != 1 ) - return SIZE_MAX; + return -1; written++; if ( field_width_is_negative && 1 < abs_field_width ) for ( size_t i = 1; i < abs_field_width; i++ ) - if ( callback_character(callback, user, ' ') != 1 ) - return SIZE_MAX; + if ( callback_character(user, callback, ' ') != 1 ) + return -1; else written++; } @@ -422,19 +420,19 @@ size_t vprintf_callback(size_t (*callback)(void*, const char*, size_t), if ( !field_width_is_negative && string_length < abs_field_width ) for ( size_t i = string_length; i < abs_field_width; i++ ) - if ( callback_character(callback, user, ' ') != 1 ) - return SIZE_MAX; + if ( callback_character(user, callback, ' ') != 1 ) + return -1; else written++; if ( callback(user, string, string_length) != string_length ) - return SIZE_MAX; + return -1; written += string_length; if ( field_width_is_negative && string_length < abs_field_width ) for ( size_t i = string_length; i < abs_field_width; i++ ) - if ( callback_character(callback, user, ' ') != 1 ) - return SIZE_MAX; + if ( callback_character(user, callback, ' ') != 1 ) + return -1; else written++; @@ -464,5 +462,8 @@ size_t vprintf_callback(size_t (*callback)(void*, const char*, size_t), goto incomprehensible_conversion; } + if ( INT_MAX < written ) + return INT_MAX; + return written; } diff --git a/libc/stdio/vdprintf.cpp b/libc/stdio/vdprintf.cpp index 4192ba14..3a01e6aa 100644 --- a/libc/stdio/vdprintf.cpp +++ b/libc/stdio/vdprintf.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2013. + Copyright(C) Jonas 'Sortie' Termansen 2013, 2014. This file is part of the Sortix C Library. @@ -30,10 +30,10 @@ static size_t write_callback(void* user, const char* string, size_t stringlen) { - return writeall((int) (uintptr_t) user, string, stringlen * sizeof(char)); + return writeall((int) (uintptr_t) user, string, stringlen); } extern "C" int vdprintf(int fd, const char* restrict format, va_list list) { - return vprintf_callback(write_callback, (void*) (uintptr_t) fd, format, list); + return vcbprintf((void*) (uintptr_t) fd, write_callback, format, list); } diff --git a/libc/stdio/vfprintf_unlocked.cpp b/libc/stdio/vfprintf_unlocked.cpp index 8e91d83f..f842f27d 100644 --- a/libc/stdio/vfprintf_unlocked.cpp +++ b/libc/stdio/vfprintf_unlocked.cpp @@ -38,8 +38,5 @@ int vfprintf_unlocked(FILE* fp, const char* restrict format, va_list list) if ( !(fp->flags & _FILE_WRITABLE) ) return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF; - size_t result = vprintf_callback(FileWriteCallback, fp, format, list); - if ( result == SIZE_MAX ) - return -1; - return (int) result; + return vcbprintf(fp, FileWriteCallback, format, list); } diff --git a/libc/stdio/vsnprintf.cpp b/libc/stdio/vsnprintf.cpp index 449e4a90..ac654d55 100644 --- a/libc/stdio/vsnprintf.cpp +++ b/libc/stdio/vsnprintf.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of the Sortix C Library. @@ -58,8 +58,8 @@ int vsnprintf(char* restrict str, size_t size, const char* restrict format, info.size = size ? size-1 : 0; info.produced = 0; info.written = 0; - vprintf_callback(StringPrintCallback, &info, format, list); + int result = vcbprintf(&info, StringPrintCallback, format, list); if ( size ) info.str[info.written] = '\0'; - return (int) info.produced; + return result; }