chiark / gitweb /
struct/buf.3.in: Correct the type of `buf_put' in the synopsis.
[mLib] / utils / gprintf.c
index f527186373599d53b271ff4a12fa666610052996..45cd35afc9325b34d49fff159fb7880e7a6e224a 100644 (file)
@@ -48,6 +48,7 @@
 #include "darray.h"
 #include "dstr.h"
 #include "gprintf.h"
+#include "growbuf.h"
 #include "macros.h"
 
 /*----- Tunable constants -------------------------------------------------*/
@@ -373,7 +374,7 @@ int vgprintf(const struct gprintf_ops *ops, void *out,
        break;
       default:
        fprintf(stderr,
-               "FATAL dstr_vputf: unknown format specifier `%c'\n", p[-1]);
+               "FATAL vgprintf: unknown format specifier `%c'\n", p[-1]);
        abort();
     }
 
@@ -408,17 +409,21 @@ int vgprintf(const struct gprintf_ops *ops, void *out,
     /* --- Output the literal portion --- */
 
     if (fs->n) {
-      if (ops->putm(out, fs->p, fs->n)) return (-1);
-      tot += fs->n;
+      n = ops->putm(out, fs->p, fs->n); if (n < 0) return (-1);
+      tot += n;
     }
 
     /* --- And now the variable portion --- */
 
     if (fs->fmt == fmt_unset) {
       switch (fs->ch) {
-       case 0: break;
-       case '%': ops->putch(out, '%'); break;
-       default: abort();
+       case 0:
+         break;
+       case '%':
+         n = ops->putch(out, '%'); if (n < 0) return (-1);
+         tot += n; break;
+       default:
+         abort();
       }
       continue;
     }
@@ -496,8 +501,8 @@ int vgprintf(const struct gprintf_ops *ops, void *out,
        break;
 #else
 #  define MSG "<no float support>"
-       if (ops->putm(out, MSG, sizeof(MSG) - 1)) return (-1);
-       continue;
+       n = ops->putm(out, MSG, sizeof(MSG) - 1); if (n < 0) return (-1);
+       tot += n; continue;
 #  undef MSG
 #endif
       case 's':
@@ -522,14 +527,14 @@ int vgprintf(const struct gprintf_ops *ops, void *out,
     switch (fs->fmt) {
 #define CASE(code, ty)                                                 \
        case fmt_##code:                                                \
-         i = ops->nputf(out, sz, dd.buf, fa[fs->arg].u.code);          \
+         n = ops->nputf(out, sz, dd.buf, fa[fs->arg].u.code);          \
          break;
       OUTPUT_FMTTYPES(CASE)
 #undef CASE
       default: abort();
     }
-    if (i < 0) return (-1);
-    tot += i;
+    if (n < 0) return (-1);
+    tot += n;
   }
 
   /* --- We're done --- */
@@ -563,6 +568,48 @@ int gprintf(const struct gprintf_ops *ops, void *out, const char *p, ...)
   return (n);
 }
 
+/*----- Utilities ---------------------------------------------------------*/
+
+/* --- @gprintf_memputf@ --- *
+ *
+ * Arguments:  @arena *a@ = memory allocation arena
+ *             @char **buf_inout@ = address of output buffer pointer
+ *             @size_t *sz_inout@ = address of buffer size
+ *             @size_t maxsz@ = buffer size needed for this operation
+ *             @const char *p@ = pointer to format string
+ *             @va_list *ap@ = captured format-arguments tail
+ *
+ * Returns:    The formatted length.
+ *
+ * Use:                Generic utility for mostly implementing the @nputf@ output
+ *             function, if you don't have a better option.
+ *
+ *             On entry, @*buf_inout@ should be null or a buffer pointer,
+ *             with @*sz_inout@ either zero or the buffer's size,
+ *             respectively.  On exit, @*buf_input@ and @*sz_inout@ will be
+ *             updated, if necessary, to describe a sufficiently large
+ *             buffer, and the formatted string will have been written to
+ *             the buffer.
+ *
+ *             When the buffer is no longer required, free it using
+ *             @x_free@.
+ */
+
+size_t gprintf_memputf(arena *a, char **buf_inout, size_t *sz_inout,
+                      size_t maxsz, const char *p, va_list ap)
+{
+  int n;
+
+  GROWBUF_REPLACE(size_t, a, *buf_inout, *sz_inout, maxsz, 64, 1);
+#ifdef HAVE_SNPRINTF
+  n = vsnprintf(*buf_inout, maxsz + 1, p, ap);
+#else
+  n = vsprintf(*buf_inout, p, ap);
+#endif
+  assert(0 <= n && n <= maxsz);
+  return (n);
+}
+
 /*----- Standard printers -------------------------------------------------*/
 
 static int file_putch(void *out, int ch)