From: Matthew Fernandez Date: Tue, 1 Sep 2020 00:34:09 +0000 (-0700) Subject: implement a printf-like interface to agxbuf X-Git-Tag: 2.46.0~20^2^2~77^2~27 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ed05695316105ec19906272e73214bfe3fbdc37f;p=graphviz implement a printf-like interface to agxbuf --- diff --git a/lib/cgraph/agxbuf.c b/lib/cgraph/agxbuf.c index 3f2c809a6..92a9927ca 100644 --- a/lib/cgraph/agxbuf.c +++ b/lib/cgraph/agxbuf.c @@ -11,7 +11,8 @@ * Contributors: See CVS logs. Details at http://www.graphviz.org/ *************************************************************************/ - +#include +#include #include #include #include @@ -66,6 +67,47 @@ int agxbmore(agxbuf * xb, size_t ssz) return 0; } +int agxbprint(agxbuf * xb, const char *fmt, ...) { + va_list ap; + size_t size; + int result; + + va_start(ap, fmt); + + /* determine how many bytes we need to print */ + { + va_list ap2; + int rc; + va_copy(ap2, ap); + rc = vsnprintf(NULL, 0, fmt, ap2); + va_end(ap2); + if (rc < 0) { + va_end(ap); + return rc; + } + size = (size_t)rc + 1; /* account for NUL terminator */ + } + + /* do we need to expand the buffer? */ + { + size_t unused_space = (size_t)(xb->eptr - xb->ptr); + if (unused_space < size) { + size_t extra = size - unused_space; + (void)agxbmore(xb, extra); + } + } + + /* we can now safely print into the buffer */ + result = vsnprintf((char*)xb->ptr, size, fmt, ap); + assert(result == (int)(size - 1) || result < 0); + if (result > 0) { + xb->ptr += (size_t)result; + } + + va_end(ap); + return result; +} + /* agxbput_n: * Append string s of length n onto xb */ diff --git a/lib/cgraph/agxbuf.h b/lib/cgraph/agxbuf.h index deb2e8e9f..eeb12235b 100644 --- a/lib/cgraph/agxbuf.h +++ b/lib/cgraph/agxbuf.h @@ -47,6 +47,21 @@ extern "C" { AGXBUF_API void agxbinit(agxbuf * xb, unsigned int hint, unsigned char *init); +/* support for extra API misuse warnings if available */ +#ifdef __GNUC__ + #define PRINTF_LIKE(index, first) __attribute__((format(printf, index, first))) +#else + #define PRINTF_LIKE(index, first) /* nothing */ +#endif + +/* agxbprint: + * Printf-style output to an agxbuf + */ + AGXBUF_API int agxbprint(agxbuf * xb, const char *fmt, ...) + PRINTF_LIKE(2, 3); + +#undef PRINTF_LIKE + /* agxbput_n: * Append string s of length n into xb */