Add cbprintf(3) and vcbprintf(3).

Thanks to Owen Shepherd of the Public Domain C Library for helping design
and formalize these interfaces.
This commit is contained in:
Jonas 'Sortie' Termansen 2014-08-13 19:15:20 +02:00
parent 2dffa408ad
commit ec7e0cc9a6
10 changed files with 98 additions and 55 deletions

View File

@ -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);
}

View File

@ -28,6 +28,7 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
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

View File

@ -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 \

View File

@ -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*),

39
libc/stdio/cbprintf.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
stdio/cbprintf.cpp
Formats text and outputs it via callback functions.
*******************************************************************************/
#include <stdarg.h>
#include <stdio.h>
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;
}

View File

@ -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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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 <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}