1 /*        $NetBSD: xsbprintf.c,v 1.3 2024/08/18 20:47:13 christos Exp $         */
2 
3 /*
4  * xsbprintf.c - string buffer formatting helpers
5  *
6  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
7  * The contents of 'html/copyright.html' apply.
8  */
9 
10 #include <config.h>
11 #include <sys/types.h>
12 
13 #include "ntp_stdlib.h"
14 
15 /* eXtended Varlist String Buffer printf
16  *
17  * Formats via 'vsnprintf' into a string buffer, with some semantic
18  * specialties:
19  *
20  * - The start of the buffer pointer is updated according to the number
21  *   of characters written.
22  * - If the buffer is insufficient to format the number of charactes,
23  *   the partial result will be be discarded, and zero is returned to
24  *   indicate nothing was written to the buffer.
25  * - On successful formatting, the return code is the return value of
26  *   the inner call to 'vsnprintf()'.
27  * - If there is any error, the state of the buffer will not be
28  *   changed. (Bytes in the buffer might be smashed, but the buffer
29  *   position does not change, and the NUL marker stays in place at the
30  *   current buffer position.)
31  * - If '(*ppbuf - pend) <= 0' (or ppbuf is NULL), fail with EINVAL.
32  */
33 int
xvsbprintf(char ** ppbuf,char * const pend,char const * pfmt,va_list va)34 xvsbprintf(
35           char       **ppbuf, /* pointer to buffer pointer (I/O) */
36           char * const pend,  /* buffer end (I)                */
37           char const  *pfmt,  /* printf-like format string       */
38           va_list      va               /* formatting args for above       */
39           )
40 {
41           char *pbuf = (ppbuf) ? *ppbuf : NULL;
42           int   rc   = -1;
43           if (pbuf && (pend - pbuf > 0)) {
44                     size_t blen = (size_t)(pend - pbuf);
45                     rc = vsnprintf(pbuf, blen, pfmt, va);
46                     if (rc > 0) {
47                               if ((size_t)rc >= blen)
48                                         rc = 0;
49                               pbuf += rc;
50                     }
51                     *pbuf = '\0'; /* fear of bad vsnprintf */
52                     *ppbuf = pbuf;
53           } else {
54                     errno = EINVAL;
55           }
56           return rc;
57 }
58 
59 /* variadic wrapper around the buffer string formatter */
60 int
xsbprintf(char ** ppbuf,char * const pend,char const * pfmt,...)61 xsbprintf(
62           char       **ppbuf, /* pointer to buffer pointer (I/O) */
63           char * const pend,  /* buffer end (I)                */
64           char const  *pfmt,  /* printf-like format string       */
65           ...                           /* formatting args for above       */
66           )
67 {
68           va_list va;
69           int     rc;
70 
71           va_start(va, pfmt);
72           rc = xvsbprintf(ppbuf, pend, pfmt, va);
73           va_end(va);
74           return rc;
75 }
76 
77 /* that's all folks! */
78