1*eabc0478Schristos /* $NetBSD: xsbprintf.c,v 1.3 2024/08/18 20:47:13 christos Exp $ */ 2067f5680Schristos 3067f5680Schristos /* 4067f5680Schristos * xsbprintf.c - string buffer formatting helpers 5067f5680Schristos * 6067f5680Schristos * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. 7067f5680Schristos * The contents of 'html/copyright.html' apply. 8067f5680Schristos */ 9067f5680Schristos 10067f5680Schristos #include <config.h> 11067f5680Schristos #include <sys/types.h> 12067f5680Schristos 13067f5680Schristos #include "ntp_stdlib.h" 14067f5680Schristos 15067f5680Schristos /* eXtended Varlist String Buffer printf 16067f5680Schristos * 17067f5680Schristos * Formats via 'vsnprintf' into a string buffer, with some semantic 18067f5680Schristos * specialties: 19067f5680Schristos * 20067f5680Schristos * - The start of the buffer pointer is updated according to the number 21067f5680Schristos * of characters written. 22067f5680Schristos * - If the buffer is insufficient to format the number of charactes, 23067f5680Schristos * the partial result will be be discarded, and zero is returned to 24067f5680Schristos * indicate nothing was written to the buffer. 25067f5680Schristos * - On successful formatting, the return code is the return value of 26067f5680Schristos * the inner call to 'vsnprintf()'. 27067f5680Schristos * - If there is any error, the state of the buffer will not be 28067f5680Schristos * changed. (Bytes in the buffer might be smashed, but the buffer 29067f5680Schristos * position does not change, and the NUL marker stays in place at the 30067f5680Schristos * current buffer position.) 31067f5680Schristos * - If '(*ppbuf - pend) <= 0' (or ppbuf is NULL), fail with EINVAL. 32067f5680Schristos */ 33067f5680Schristos int 34067f5680Schristos xvsbprintf( 35067f5680Schristos char **ppbuf, /* pointer to buffer pointer (I/O) */ 36067f5680Schristos char * const pend, /* buffer end (I) */ 37067f5680Schristos char const *pfmt, /* printf-like format string */ 38067f5680Schristos va_list va /* formatting args for above */ 39067f5680Schristos ) 40067f5680Schristos { 41067f5680Schristos char *pbuf = (ppbuf) ? *ppbuf : NULL; 42067f5680Schristos int rc = -1; 43067f5680Schristos if (pbuf && (pend - pbuf > 0)) { 44067f5680Schristos size_t blen = (size_t)(pend - pbuf); 45067f5680Schristos rc = vsnprintf(pbuf, blen, pfmt, va); 46067f5680Schristos if (rc > 0) { 47067f5680Schristos if ((size_t)rc >= blen) 48067f5680Schristos rc = 0; 49067f5680Schristos pbuf += rc; 50067f5680Schristos } 51067f5680Schristos *pbuf = '\0'; /* fear of bad vsnprintf */ 52067f5680Schristos *ppbuf = pbuf; 53067f5680Schristos } else { 54067f5680Schristos errno = EINVAL; 55067f5680Schristos } 56067f5680Schristos return rc; 57067f5680Schristos } 58067f5680Schristos 59067f5680Schristos /* variadic wrapper around the buffer string formatter */ 60067f5680Schristos int 61067f5680Schristos xsbprintf( 62067f5680Schristos char **ppbuf, /* pointer to buffer pointer (I/O) */ 63067f5680Schristos char * const pend, /* buffer end (I) */ 64067f5680Schristos char const *pfmt, /* printf-like format string */ 65067f5680Schristos ... /* formatting args for above */ 66067f5680Schristos ) 67067f5680Schristos { 68067f5680Schristos va_list va; 69067f5680Schristos int rc; 70067f5680Schristos 71067f5680Schristos va_start(va, pfmt); 72067f5680Schristos rc = xvsbprintf(ppbuf, pend, pfmt, va); 73067f5680Schristos va_end(va); 74067f5680Schristos return rc; 75067f5680Schristos } 76067f5680Schristos 77067f5680Schristos /* that's all folks! */ 78