]> granicus.if.org Git - graphviz/commitdiff
implement a printf-like interface to agxbuf
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Tue, 1 Sep 2020 00:34:09 +0000 (17:34 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Thu, 17 Sep 2020 04:08:22 +0000 (21:08 -0700)
lib/cgraph/agxbuf.c
lib/cgraph/agxbuf.h

index 3f2c809a6b3d684001c10d04d0b3dfdf1fb863d9..92a9927ca48a4ed59b59f1e0777bbc5802c458a6 100644 (file)
@@ -11,7 +11,8 @@
  * Contributors: See CVS logs. Details at http://www.graphviz.org/
  *************************************************************************/
 
-
+#include <assert.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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
  */
index deb2e8e9fdf85b337b924e29537337e371670450..eeb12235bee6d5350f950d42ecef38c5128d22cc 100644 (file)
@@ -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
  */