xref: /netbsd-src/external/bsd/ntp/dist/libntp/xsbprintf.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
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