These ones can fill in strerror(errno) automatically.
start = strtoul(str, &endptr, 0);
if (start >= frames) {
- errmsg("frame %lu out of range.\n", start);
+ tool_err(-1, "frame %lu out of range.", start);
return -1;
}
if (endptr == str) {
- errmsg("invalid frame range: %s.\n", str);
+ tool_err(-1, "invalid frame range: %s.", str);
return -1;
}
case '-':
end = strtoul(endptr+1, &endptr, 0);
if (end >= frames) {
- errmsg("frame %lu out of range.\n", end);
+ tool_err(-1, "frame %lu out of range.", end);
return -1;
}
end = frames - 1;
break;
default:
- errmsg("invalid frame range: %s.\n", str);
+ tool_err(-1, "invalid frame range: %s.", str);
return -1;
}
if (end < start) {
- errmsg("invalid frame range: %s.\n", str);
+ tool_err(-1, "invalid frame range: %s.", str);
return -1;
}
row = malloc(4 * width);
if (!row) {
- errmsg("failed to allocate row buffer: %s\n", strerror(errno));
+ tool_err(0, "failed to allocate row buffer");
return -1;
}
of = fopen(name, "wb");
if (!of) {
- errmsg("failed to open %s: %s.\n", name, strerror(errno));
- free(row);
+ tool_err(0, "failed to open %s", name);
return -1;
}
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
- errmsg("failed to init libpng.\n", 0);
+ tool_err(-1, "failed to init libpng.");
goto err;
}
info = png_create_info_struct(png);
if (!info) {
- errmsg("failed to init libpng.\n", 0);
+ tool_err(-1, "failed to init libpng.");
png_destroy_write_struct(&png, NULL);
goto err;
}
struct lbx_imginfo info;
if (!overimg) {
- errmsg("failed to open override image: %s\n", lbx_errmsg());
+ tool_err(-1, "failed to open override image: %s", lbx_errmsg());
return -1;
}
lbx_img_getinfo(overimg, &info);
if (!info.palettesz) {
- errmsg("override image has no palette.\n", 0);
+ tool_err(-1, "override image has no palette.");
lbx_img_close(overimg);
return -1;
}
if (lbx_img_getpalette(overimg, palette) == -1) {
- errmsg("error reading override palette: %s\n", lbx_errmsg());
+ tool_err(-1, "error reading override palette: %s", lbx_errmsg());
lbx_img_close(overimg);
return -1;
}
/* For sanity. */
if (!palf && !info->palettesz && !override) {
- errmsg("no palette available.\n", 0);
+ tool_err(-1, "no palette available.");
return -1;
}
/* Read the external palette, if any. */
if (palf && lbx_img_loadpalette(palf, &lbx_default_fops, palette) != 0) {
- errmsg("error reading external palette: %s\n", lbx_errmsg());
+ tool_err(-1, "error reading external palette: %s", lbx_errmsg());
return -1;
}
/* Read the embedded palette, if any. */
if (info->palettesz && lbx_img_getpalette(img, palette) == -1) {
- errmsg("error reading embedded palette: %s\n", lbx_errmsg());
+ tool_err(-1, "error reading embedded palette: %s", lbx_errmsg());
return -1;
}
data = lbx_img_getframe(img, i);
if (!data) {
- errmsg("error in frame %u: %s\n", i, lbx_errmsg());
+ tool_err(-1, "error in frame %u: %s", i, lbx_errmsg());
continue;
}
}
if (!extracted) {
- errmsg("no frames extracted.\n", 0);
+ tool_err(-1, "no frames extracted.");
goto err;
}
case 'p':
palf = fopen(optarg, "rb");
if (!palf) {
- errmsg("failed to open %s: %m\n", optarg);
+ tool_err(0, "failed to open %s", optarg);
return EXIT_FAILURE;
}
case 'O':
overf = fopen(optarg, "rb");
if (!overf) {
- errmsg("failed to open %s: %m\n", optarg);
+ tool_err(0, "failed to open %s", optarg);
return EXIT_FAILURE;
}
break;
}
if (mode == MODE_NONE) {
- errmsg("you must specify a mode.\n", 0);
+ tool_err(-1, "you must specify a mode.");
return EXIT_FAILURE;
}
img = lbx_img_open(&stdin_handle, &lbx_pipe_fops, NULL);
if (!img) {
- errmsg("failed to open image: %s.\n", lbx_errmsg());
+ tool_err(-1, "failed to open image: %s.", lbx_errmsg());
return EXIT_FAILURE;
}
case FNM_NOMATCH:
break;
default:
- errmsg("error matching glob: %s.\n", argv[i]);
+ tool_err(-1, "error matching glob: %s", argv[i]);
return 1;
}
}
of = fopen(stat->name, "wb");
if (!of) {
- errmsg("%s: fopen: %s\n",
- stat->name, strerror(errno));
+ tool_err(0, "%s: fopen", stat->name);
return -1;
}
}
if (fwrite(buf, rc, 1, of) != 1) {
- errmsg("%s: fwrite: %s\n", stat->name, strerror(errno));
+ tool_err(0, "%s: fwrite", stat->name);
break;
}
}
if (fclose(of) == EOF) {
- errmsg("%s: fclose: %s\n", stat->name, strerror(errno));
+ tool_err(0, "%s: fclose", stat->name);
return -1;
}
file = lbx_file_open(lbx, i);
if (!file) {
- errmsg("%s: %s.\n", stat.name, lbx_errmsg());
+ tool_err(-1, "%s: %s", stat.name, lbx_errmsg());
continue;
}
lbx = lbx_open(&stdin_handle, &lbx_pipe_fops, NULL, "stdin");
if (!lbx) {
- errmsg("%s: %s.\n", file ? file : "stdin", lbx_errmsg());
+ tool_err(-1, "%s: %s", file ? file : "stdin", lbx_errmsg());
return EXIT_FAILURE;
}
rc = extract(lbx, verbose, &argv[optind]);
break;
default:
- errmsg("you must specify a mode.\n", 0);
+ tool_err(-1, "no mode specified");
}
lbx_close(lbx);
#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_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;
+}
#ifndef TOOLS_H_
#define TOOLS_H_
+#include <stdarg.h>
+
void tool_init(const char *name, int argc, char **argv);
void tool_version(void);
const char *tool_invocation(void);
-#define errmsg(fmt, ...) (\
- fprintf(stderr, "%s: " fmt, tool_invocation(), __VA_ARGS__)\
-)
+/*
+ * Error messaging routines. Similar to printf, but writes to standard error
+ * and prefixes the output with the program invocation name, automatically
+ * appending a newline. If err is 0, the result of strerror(errno) is also
+ * printed in a similar manner as perror. If err is positive, then that
+ * value is used instead of errno.
+ */
+int tool_verr(int err, const char *fmt, va_list ap);
+int tool_err(int err, const char *fmt, ...);
+
+/*
+ * Messaging routines similar to the above, except that they write to standard
+ * output and there is no option to include strerror(errno).
+ */
+int tool_vmsg(const char *fmt, va_list ap);
+int tool_msg(const char *fmt, ...);
#endif