/*
* 2ooM: The Master of Orion II Reverse Engineering Project
* Helper functions for liblbx command-line applications.
* Copyright © 2013 Nick Bowler
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "tools.h"
static const char *progname, *argv0;
void tool_init(const char *name, int argc, char **argv)
{
progname = name;
argv0 = argv[0] ? argv[0] : progname;
}
void tool_version(void)
{
assert(argv0 != NULL);
printf("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
printf("Copyright (C) 2013 Nick Bowler.\n");
puts("License GPLv3+: GNU GPL version 3 or later .");
puts("This is free software: you are free to change and redistribute it.");
puts("There is NO WARRANTY, to the extent permitted by law.");
}
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_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;
}