#include "darray.h"
#include "dstr.h"
#include "gprintf.h"
+#include "growbuf.h"
#include "macros.h"
/*----- Tunable constants -------------------------------------------------*/
break;
default:
fprintf(stderr,
- "FATAL dstr_vputf: unknown format specifier `%c'\n", p[-1]);
+ "FATAL vgprintf: unknown format specifier `%c'\n", p[-1]);
abort();
}
/* --- 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;
}
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':
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 --- */
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)