From 80831e50b967c8475f1fcc0e19e3aa992f9eb242 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 9 Jun 2022 14:25:39 +0200 Subject: [PATCH] add xprintf() this introduces a "commit" callback to the xprintf kernel, to avoid pointlessly assembling a temporary output string prior to printing it. one could lift the buffer limitations by introducing a "segment" callback instead, but that would slow down xvasprintf() due to the higher callback rate, for no good reason. --- configure.ac | 2 +- src/common.h | 1 + src/util.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 5922126..3b9b145 100644 --- a/configure.ac +++ b/configure.ac @@ -83,7 +83,7 @@ if test "x$ob_cv_strftime_z" = x"no"; then fi AC_CHECK_HEADERS(poll.h sys/select.h) -AC_CHECK_FUNCS(vasprintf strnlen memrchr timegm) +AC_CHECK_FUNCS(vasprintf strnlen memrchr timegm fwrite_unlocked) AC_CHECK_LIB(socket, socket, [SOCK_LIBS="-lsocket"]) AC_CHECK_LIB(nsl, inet_ntoa, [SOCK_LIBS="$SOCK_LIBS -lnsl"]) diff --git a/src/common.h b/src/common.h index f481060..c7ad08c 100644 --- a/src/common.h +++ b/src/common.h @@ -166,6 +166,7 @@ void ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... ); void flushn( void ); char *xvasprintf( const char *fmt, va_list ap ); +void xprintf( const char *fmt, ... ); #if !defined(_POSIX_SYNCHRONIZED_IO) || _POSIX_SYNCHRONIZED_IO <= 0 # define fdatasync fsync diff --git a/src/util.c b/src/util.c index 9e5af7e..aa8f28a 100644 --- a/src/util.c +++ b/src/util.c @@ -198,8 +198,10 @@ sys_error( const char *msg, ... ) #define QPRINTF_SEGS 16 #define QPRINTF_BUFF 1000 -char * -xvasprintf( const char *fmt, va_list ap ) +typedef void (*printf_cb)( const char **segs, uint *segls, int nsegs, uint totlen, void *aux ); + +static void +xvprintf_core( const char *fmt, va_list ap, printf_cb cb, void *cb_aux ) { int nsegs = 0; uint totlen = 0; @@ -320,15 +322,54 @@ xvasprintf( const char *fmt, va_list ap ) fmt++; } } - char *out = d = nfmalloc( totlen + 1 ); + cb( segs, segls, nsegs, totlen, cb_aux ); +} + +static void +xasprintf_cb( const char **segs, uint *segls, int nsegs, uint totlen, void *aux ) +{ + char *d = nfmalloc( totlen + 1 ); + *(char **)aux = d; for (int i = 0; i < nsegs; i++) { memcpy( d, segs[i], segls[i] ); d += segls[i]; } *d = 0; +} + +char * +xvasprintf( const char *fmt, va_list ap ) +{ + char *out; + xvprintf_core( fmt, ap, xasprintf_cb, &out ); return out; } +#ifndef HAVE_FWRITE_UNLOCKED +# define flockfile(f) +# define funlockfile(f) +# define fwrite_unlocked(b, l, n, f) fwrite(b, l, n, f) +#endif + +static void +xprintf_cb( const char **segs, uint *segls, int nsegs, uint totlen ATTR_UNUSED, void *aux ATTR_UNUSED ) +{ + flockfile( stdout ); + for (int i = 0; i < nsegs; i++) + fwrite_unlocked( segs[i], 1, segls[i], stdout ); + funlockfile( stdout ); +} + +void +xprintf( const char *fmt, ... ) +{ + va_list va; + + va_start( va, fmt ); + xvprintf_core( fmt, va, xprintf_cb, NULL ); + va_end( va ); +} + void vFprintf( FILE *f, const char *msg, va_list va ) {