X-Git-Url: http://git.draconx.ca/gitweb/liblbx.git/blobdiff_plain/5749c5e97a8b984720cef75f328944270874d713..c81b3f9cfa09bcf212214f006d879585774619e2:/src/tools.c diff --git a/src/tools.c b/src/tools.c index b80e521..200cf9c 100644 --- a/src/tools.c +++ b/src/tools.c @@ -19,6 +19,12 @@ #include #include +#include +#include +#include +#include +#include +#include #include #include "tools.h" @@ -46,3 +52,91 @@ const char *tool_invocation(void) assert(argv0 != NULL); return argv0; } + +/* Saturating addition. */ +static size_t add_size(size_t a, size_t b) +{ + if (a >= SIZE_MAX - b) + return SIZE_MAX; + 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_MAX || 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; +}