From c81b3f9cfa09bcf212214f006d879585774619e2 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 4 Jun 2013 23:34:06 -0400 Subject: [PATCH] tools: Add some smarter error printing routines. These ones can fill in strerror(errno) automatically. --- src/lbximg.c | 43 ++++++++++++----------- src/lbxtool.c | 15 ++++---- src/tools.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/tools.h | 21 ++++++++++-- 4 files changed, 140 insertions(+), 33 deletions(-) diff --git a/src/lbximg.c b/src/lbximg.c index 581a33a..ff38c89 100644 --- a/src/lbximg.c +++ b/src/lbximg.c @@ -64,12 +64,12 @@ int parserange(unsigned frames, char *str, unsigned char *bits) 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; } @@ -80,7 +80,7 @@ int parserange(unsigned frames, char *str, unsigned char *bits) 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; } @@ -88,12 +88,12 @@ int parserange(unsigned frames, char *str, unsigned char *bits) 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; } @@ -134,26 +134,25 @@ int outpng(unsigned int frameno, 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; } @@ -234,19 +233,19 @@ static int loadoverride(FILE *f, struct lbx_colour palette[static 256]) 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; } @@ -272,7 +271,7 @@ static int loadpalette(struct lbx_image *img, struct lbx_imginfo *info, /* For sanity. */ if (!palf && !info->palettesz && !override) { - errmsg("no palette available.\n", 0); + tool_err(-1, "no palette available."); return -1; } @@ -283,13 +282,13 @@ static int loadpalette(struct lbx_image *img, struct lbx_imginfo *info, /* 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; } @@ -340,7 +339,7 @@ int decode(struct lbx_image *img, FILE *palf, FILE *override, char **argv) 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; } @@ -352,7 +351,7 @@ int decode(struct lbx_image *img, FILE *palf, FILE *override, char **argv) } if (!extracted) { - errmsg("no frames extracted.\n", 0); + tool_err(-1, "no frames extracted."); goto err; } @@ -410,7 +409,7 @@ int main(int argc, char **argv) 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; } @@ -418,7 +417,7 @@ int main(int argc, char **argv) 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; @@ -438,7 +437,7 @@ int main(int argc, char **argv) } if (mode == MODE_NONE) { - errmsg("you must specify a mode.\n", 0); + tool_err(-1, "you must specify a mode."); return EXIT_FAILURE; } @@ -448,7 +447,7 @@ int main(int argc, char **argv) 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; } diff --git a/src/lbxtool.c b/src/lbxtool.c index 1c32ef4..767c309 100644 --- a/src/lbxtool.c +++ b/src/lbxtool.c @@ -56,7 +56,7 @@ int filematch(char **argv, const char *name) case FNM_NOMATCH: break; default: - errmsg("error matching glob: %s.\n", argv[i]); + tool_err(-1, "error matching glob: %s", argv[i]); return 1; } } @@ -102,8 +102,7 @@ int extract_file(LBXfile *f, const struct lbx_statbuf *stat) 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; } @@ -118,7 +117,7 @@ int extract_file(LBXfile *f, const struct lbx_statbuf *stat) } if (fwrite(buf, rc, 1, of) != 1) { - errmsg("%s: fwrite: %s\n", stat->name, strerror(errno)); + tool_err(0, "%s: fwrite", stat->name); break; } @@ -130,7 +129,7 @@ int extract_file(LBXfile *f, const struct lbx_statbuf *stat) } if (fclose(of) == EOF) { - errmsg("%s: fclose: %s\n", stat->name, strerror(errno)); + tool_err(0, "%s: fclose", stat->name); return -1; } @@ -159,7 +158,7 @@ int extract(struct lbx *lbx, int verbose, char **argv) 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; } @@ -233,7 +232,7 @@ int main(int argc, char **argv) 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; } @@ -245,7 +244,7 @@ int main(int argc, char **argv) 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); 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; +} diff --git a/src/tools.h b/src/tools.h index 315d965..c2c10ff 100644 --- a/src/tools.h +++ b/src/tools.h @@ -20,13 +20,28 @@ #ifndef TOOLS_H_ #define TOOLS_H_ +#include + 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 -- 2.43.0