#include <config.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <inttypes.h>
#include <assert.h>
#include "tools.h"
assert(argv0 != NULL);
return argv0;
}
+
+/* Saturating addition. */
+static size_t add_size(size_t a, size_t b)
+{
+ if (a >= (size_t)-1 - b)
+ return (size_t)-1;
+ return a + b;
+}
+
+static int vfmsg_internal(FILE *f, int err, const char *fmt, va_list ap)
+{
+ size_t invokelen, fmtlen, errlen, totlen;
+ char *newfmt, *errmsg;
+ int rc;
+
+ invokelen = strlen(tool_invocation());
+ fmtlen = fmt ? strlen(fmt) : 0;
+ errlen = err > 0 ? strlen(errmsg = strerror(err)) : 0;
+
+ totlen = add_size(invokelen, sizeof "\n");
+ if (fmtlen > 0) {
+ totlen = add_size(totlen, strlen(": "));
+ totlen = add_size(totlen, fmtlen);
+ }
+ if (errlen > 0) {
+ totlen = add_size(totlen, strlen(": "));
+ totlen = add_size(totlen, errlen);
+ }
+
+ if (totlen == (size_t)-1 || totlen > INT_MAX)
+ return -1;
+
+ newfmt = malloc(totlen);
+ if (!newfmt)
+ return -1;
+
+ if (errlen && fmtlen)
+ rc = sprintf(newfmt, "%s: %s: %s\n", argv0, fmt, errmsg);
+ else if (errlen)
+ rc = sprintf(newfmt, "%s: %s\n", argv0, errmsg);
+ else if (fmtlen)
+ rc = sprintf(newfmt, "%s: %s\n", argv0, fmt);
+ else
+ rc = sprintf(newfmt, "%s\n", argv0);
+
+ assert(rc < totlen);
+ if (rc < 0)
+ goto out;
+
+ rc = vfprintf(f, newfmt, ap);
+out:
+ free(newfmt);
+ return rc;
+}
+
+int tool_vmsg(const char *fmt, va_list ap)
+{
+ return vfmsg_internal(stdout, -1, fmt, ap);
+}
+
+int tool_verr(int err, const char *fmt, va_list ap)
+{
+ return vfmsg_internal(stderr, err == 0 ? errno : err, fmt, ap);
+}
+
+int tool_msg(const char *fmt, ...)
+{
+ va_list ap;
+ int rc;
+
+ va_start(ap, fmt);
+ rc = tool_vmsg(fmt, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+int tool_err(int err, const char *fmt, ...)
+{
+ va_list ap;
+ int rc;
+
+ va_start(ap, fmt);
+ rc = tool_verr(err, fmt, ap);
+ va_end(ap);
+
+ return rc;
+}