/* * 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; }