From: Nick Bowler Date: Thu, 11 Feb 2010 03:08:04 +0000 (-0500) Subject: liblbx: Implement improved error reporting mechanism. X-Git-Url: http://git.draconx.ca/gitweb/liblbx.git/commitdiff_plain/fa7c556d251ebcb41ef9709b4d85a2c820dee94b liblbx: Implement improved error reporting mechanism. We now use a FIFO-of-errors approach (similar to libltdl) as opposed to an errno-esque approach. --- diff --git a/src/Makefile.inc b/src/Makefile.inc index 8b39a52..c033f53 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -5,12 +5,12 @@ # without any warranty. lbxdir = $(includedir)/lbx -lbx_HEADERS = src/lbx.h src/image.h +lbx_HEADERS = src/lbx.h src/image.h src/error.h noinst_HEADERS += src/misc.h src/tools.h src/pack.h lib_LTLIBRARIES += liblbx.la -liblbx_la_SOURCES = src/lbx.c src/fops.c src/image.c src/pack.c +liblbx_la_SOURCES = src/lbx.c src/fops.c src/image.c src/pack.c src/error.c bin_PROGRAMS += lbxtool lbxtool_SOURCES = src/lbxtool.c diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..c32d3b6 --- /dev/null +++ b/src/error.c @@ -0,0 +1,132 @@ +/* + * 2ooM: The Master of Orion II Reverse Engineering Project + * Utilities for out-of-band error propagation. + * Copyright (C) 2010 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 "error.h" + +#define _(s) dgettext(PACKAGE, s) + +#if !defined(LBX_ERROR_LIMIT) +# define LBX_ERROR_LIMIT 256 +#endif + +static unsigned error_base, error_tip; +static int error_ring[LBX_ERROR_LIMIT]; + +static const char **user_errors; +static unsigned user_error_count; +static unsigned user_error_max = 2; + +int lbx_error_new(const char *str) +{ + assert(user_error_count <= user_error_max); + if (!user_errors || user_error_count == user_error_max) { + size_t size = sizeof *user_errors * user_error_max * 2; + const char **new; + + new = realloc(user_errors, size); + if (!new) + return -1; + user_error_max *= 2; + user_errors = new; + } + + user_errors[user_error_count] = str; + return LBX_EUBASE + user_error_count++; +} + +int lbx_error_raise(int code) +{ + if (code == LBX_EOK) { + return -1; + } else if (code >= LBX_EMAX && code < LBX_EUBASE + || code >= LBX_EUBASE + user_error_count) { + fprintf(stderr, "%s: invalid error code %d\n", __func__, code); + return -1; + } + + error_ring[error_tip++] = code; + error_tip %= LBX_ERROR_LIMIT; + + if (error_tip == error_base) { + error_base = (error_base + 1) % LBX_ERROR_LIMIT; + return -1; + } + + return 0; +} + +static void getmsg(int error, const char **msg) +{ + if (error < 0) { + *msg = strerror(-error); + return; + } + + switch (error) { + case LBX_EOK: + *msg = _("Success"); + break; + case LBX_EMAGIC: + *msg = _("Bad magic number"); + break; + case LBX_EFORMAT: + *msg = _("Invalid file format"); + break; + case LBX_ENOENT: + *msg = _("Specified item does not exist"); + break; + case LBX_ENOMEM: + *msg = _("Memory allocation failed"); + break; + case LBX_EEOF: + *msg = _("Unexpected end of file"); + break; + default: + *msg = user_errors[error - LBX_EUBASE]; + } +} + +int lbx_error_peek(const char **msg) +{ + int error = error_tip == error_base ? LBX_EOK : error_ring[error_base]; + + assert(error < LBX_EMAX || error >= LBX_EUBASE); + assert(error < LBX_EUBASE + user_error_count); + + if (msg) + getmsg(error, msg); + return error; +} + + +int lbx_error_get(const char **msg) +{ + int error = lbx_error_peek(msg); + + if (error != LBX_EOK) + error_base = (error_base + 1) % LBX_ERROR_LIMIT; + return error; +} diff --git a/src/error.h b/src/error.h new file mode 100644 index 0000000..577078a --- /dev/null +++ b/src/error.h @@ -0,0 +1,67 @@ +#ifndef LBX_ERROR_H_ +#define LBX_ERROR_H_ + +enum { + LBX_EOK, + LBX_EMAGIC, + LBX_EFORMAT, + LBX_ENOENT, + LBX_ENOMEM, + LBX_EEOF, + LBX_EMAX, + + LBX_EUBASE = 9000 +}; + +/* + * Create a new user error. User errors are primarily intended to be used by + * lbx_file_ops callback functions, but can be used for any purpose. + * + * Returns a positive code on success (which can be subsequently passed to + * lbx_error_raise), or a negative value on failure. + */ +int lbx_error_new(const char *str); + +/* + * Signal an error. The given code is recorded for later retreival by + * lbx_error_get. Errors are reported on a first-in, first-out basis. + * Errors are stored in a ring buffer which can overflow, at which point + * the oldest unretrieved error will be deleted. + * + * Negative codes represent system errors. That is, the negation of some + * (positive) errno value as returned by a library function. If a positive + * code does not correspond to any error, nothing is recorded. + * + * Returns -1 if the error code was not valid, or if an unretreived code + * was deleted. Otherwise, this function returns 0. + */ +int lbx_error_raise(int code); + +/* + * Retrieves an error. The oldest reported error is removed from the buffer. + * If msg is not NULL, a pointer to a human-readable description of the error + * is stored in *msg. + * + * Returns the retrieved error code, or 0 if there were no errors. + */ +int lbx_error_get(const char **msg); + +/* + * Retrieves an error. This function is the same as lbx_error_get, except that + * the error code is not removed from the buffer and will be reported by a + * subsequent call to lbx_error_get or lbx_error_peek. + */ +int lbx_error_peek(const char **msg); + +/* + * Helper function for when you only care about the message. + */ +static inline const char *lbx_errmsg(void) +{ + const char *msg; + + lbx_error_get(&msg); + return msg; +} + +#endif diff --git a/src/fops.c b/src/fops.c index 746455f..e546b10 100644 --- a/src/fops.c +++ b/src/fops.c @@ -17,19 +17,28 @@ * along with this program. If not, see . */ #include +#include #include "misc.h" +#include "error.h" #include "lbx.h" /* Default I/O operations for ordinary files. */ static size_t file_read(void *buf, size_t size, void *handle) { - return fread(buf, 1, size, (FILE *)handle); + size_t rc = fread(buf, 1, size, (FILE *)handle); + + if (rc < size && ferror((FILE *)handle)) + lbx_error_raise(-errno); + return rc; } static int file_seek(void *handle, long offset, int whence) { - return fseek((FILE *)handle, offset, whence); + if (fseek((FILE *)handle, offset, whence) == -1) { + lbx_error_raise(-errno); + return -1; + } } static long file_tell(void *handle) @@ -55,7 +64,7 @@ static size_t pipe_read(void *buf, size_t size, void *handle) struct lbx_pipe_state *state = handle; size_t rc; - rc = fread(buf, 1, size, state->f); + rc = file_read(buf, size, state->f); state->offset += rc; return rc; } diff --git a/src/image.c b/src/image.c index 69d4ebb..a5a4bff 100644 --- a/src/image.c +++ b/src/image.c @@ -28,6 +28,7 @@ #include "pack.h" #include "misc.h" #include "lbx.h" +#include "error.h" #include "image.h" #define FLAG_RAW 0x0100 /* Image is stored as a flat array of bytes. */ @@ -67,7 +68,7 @@ static struct lbx_image *lbximg_init(unsigned char hdr[static HDR_LEN]) img = malloc(sizeof *img + sizeof img->offsets[0] * (nframes+1)); if (!img) { - lbx_errno = -errno; + lbx_error_raise(LBX_ENOMEM); return NULL; } @@ -94,9 +95,8 @@ struct lbx_image *lbximg_open(void *f, const struct lbx_file_ops *fops, struct lbx_image *img; if (fops->read(hdr_buf, sizeof hdr_buf, f) != sizeof hdr_buf) { - lbx_errno = -errno; if (fops->eof(f)) - lbx_errno = LBX_EEOF; + lbx_error_raise(LBX_EEOF); return NULL; } @@ -124,9 +124,8 @@ struct lbx_image *lbximg_open(void *f, const struct lbx_file_ops *fops, unsigned char buf[4]; if (fops->read(buf, sizeof buf, f) != sizeof buf) { - lbx_errno = -errno; if (fops->eof(f)) - lbx_errno = LBX_EEOF; + lbx_error_raise(LBX_EEOF); free(img); return NULL; } @@ -138,9 +137,8 @@ struct lbx_image *lbximg_open(void *f, const struct lbx_file_ops *fops, unsigned char buf[4]; if (fops->read(buf, sizeof buf, f) != sizeof buf) { - lbx_errno = -errno; if (fops->eof(f)) - lbx_errno = LBX_EEOF; + lbx_error_raise(LBX_EEOF); free(img); return NULL; } @@ -150,7 +148,7 @@ struct lbx_image *lbximg_open(void *f, const struct lbx_file_ops *fops, img->paloff = fops->tell(f); if (img->palstart + img->palcount > 256) { - lbx_errno = LBX_EFORMAT; + lbx_error_raise(LBX_EFORMAT); free(img); return NULL; } @@ -231,7 +229,7 @@ static int _lbx_drawrow(int first, struct lbx_image *img) /* Ensure that the row fits in the image. */ if (img->height - img->currenty <= yval || xval >= img->width) { - lbx_errno = LBX_EFORMAT; + lbx_error_raise(LBX_EFORMAT); return -1; } @@ -241,7 +239,7 @@ static int _lbx_drawrow(int first, struct lbx_image *img) xval = unpack_16_le(buf+2); if (img->width - img->currentx <= xval) { - lbx_errno = LBX_EFORMAT; + lbx_error_raise(LBX_EFORMAT); return -1; } img->currentx += xval; @@ -250,7 +248,7 @@ static int _lbx_drawrow(int first, struct lbx_image *img) } if (count > img->width - img->currentx) { - lbx_errno = LBX_EFORMAT; + lbx_error_raise(LBX_EFORMAT); return -1; } @@ -270,9 +268,8 @@ static int _lbx_drawrow(int first, struct lbx_image *img) return 0; readerr: - lbx_errno = -errno; if (img->fops->eof(img->f)) - lbx_errno = LBX_EEOF; + lbx_error_raise(LBX_EEOF); return -1; } @@ -283,13 +280,13 @@ static unsigned char **allocframebuffer(size_t width, size_t height) tmp = calloc(height, width); if (!tmp) { - lbx_errno = -errno; + lbx_error_raise(LBX_ENOMEM); return NULL; } new = malloc(height * sizeof *new); if (!new) { - lbx_errno = -errno; + lbx_error_raise(LBX_ENOMEM); free(tmp); return NULL; } @@ -308,20 +305,18 @@ static unsigned char **read_raw_frame(struct lbx_image *img, int frame) assert(img->flags & FLAG_RAW); if (img->fops->seek(img->f, img->offsets[frame], SEEK_SET)) { - lbx_errno = -errno; return NULL; } if (img->fops->read(img->framedata[0], size, img->f) != size) { - lbx_errno = -errno; if (img->fops->eof(img->f)) - lbx_errno = LBX_EEOF; + lbx_error_raise(LBX_EEOF); return NULL; } memset(img->mask[0], 1, size); if (img->fops->tell(img->f) > img->offsets[frame+1]) { - lbx_errno = LBX_EFORMAT; + lbx_error_raise(LBX_EFORMAT); return NULL; } @@ -331,7 +326,7 @@ static unsigned char **read_raw_frame(struct lbx_image *img, int frame) unsigned char **lbximg_getframe(struct lbx_image *img, int frame) { if (frame >= img->frames || frame < 0) { - lbx_errno = LBX_ERANGE; + lbx_error_raise(LBX_ENOENT); return NULL; } @@ -374,7 +369,6 @@ unsigned char **lbximg_getframe(struct lbx_image *img, int frame) int rc, first = 1; if (img->fops->seek(img->f, img->offsets[frame], SEEK_SET)) { - lbx_errno = -errno; return NULL; } @@ -385,7 +379,7 @@ unsigned char **lbximg_getframe(struct lbx_image *img, int frame) first = 0; if (img->fops->tell(img->f) > img->offsets[frame+1]) { - lbx_errno = LBX_EFORMAT; + lbx_error_raise(LBX_EFORMAT); return NULL; } } while (!rc); @@ -404,12 +398,13 @@ lbximg_loadpalette(void *f, const struct lbx_file_ops *fops, for (i = 0; i < 256; i++) { if (fops->read(entry, sizeof entry, f) != sizeof entry) { - lbx_errno = (fops->eof(f)) ? LBX_EEOF : -errno; + if (fops->eof(f)) + lbx_error_raise(LBX_EEOF); return -1; } if (entry[0] != 1) { - lbx_errno = LBX_EFORMAT; + lbx_error_raise(LBX_EFORMAT); return -1; } @@ -436,7 +431,6 @@ lbximg_getpalette(struct lbx_image *img, struct lbx_colour palette[static 256]) return 0; if (img->fops->seek(img->f, img->paloff, SEEK_SET)) { - lbx_errno = -errno; return -1; } @@ -447,7 +441,7 @@ lbximg_getpalette(struct lbx_image *img, struct lbx_colour palette[static 256]) } if (entry[0] != 0) { - lbx_errno = LBX_EFORMAT; + lbx_error_raise(LBX_EFORMAT); return -1; } @@ -461,7 +455,8 @@ lbximg_getpalette(struct lbx_image *img, struct lbx_colour palette[static 256]) return 0; readerr: - lbx_errno = img->fops->eof(img->f) ? LBX_EEOF : -errno; + if (img->fops->eof(img->f)) + lbx_error_raise(LBX_EEOF); return -1; } diff --git a/src/lbx.c b/src/lbx.c index 0e26315..26a59bd 100644 --- a/src/lbx.c +++ b/src/lbx.c @@ -28,13 +28,12 @@ #include "pack.h" #include "misc.h" +#include "error.h" #include "lbx.h" #define LBX_MAGIC 0x0000fead #define LBX_HDR_SIZE 8 -int lbx_errno = 0; - struct lbx_state { char *name; @@ -62,13 +61,13 @@ static struct lbx_state *lbx_init(unsigned char hdr[static LBX_HDR_SIZE]) struct lbx_state *lbx; if (magic != LBX_MAGIC) { - lbx_errno = -LBX_EMAGIC; + lbx_error_raise(LBX_EMAGIC); return NULL; } lbx = malloc(sizeof *lbx + sizeof lbx->offsets[0] * (nfiles+1)); if (!lbx) { - lbx_errno = -errno; + lbx_error_raise(LBX_ENOMEM); return NULL; } @@ -98,12 +97,13 @@ struct lbx_state *lbx_open(void *f, const struct lbx_file_ops *fops, dupname = str_dup(name); if (!dupname) { - lbx_errno = -errno; + lbx_error_raise(LBX_ENOMEM); goto err; } if (fops->read(hdr_buf, sizeof hdr_buf, f) != sizeof hdr_buf) { - lbx_errno = -errno; + if (fops->eof(f)) + lbx_error_raise(LBX_EEOF); goto err; } @@ -120,9 +120,8 @@ struct lbx_state *lbx_open(void *f, const struct lbx_file_ops *fops, unsigned char buf[4]; if (fops->read(buf, sizeof buf, f) != sizeof buf) { - lbx_errno = -errno; if (fops->eof(f)) - lbx_errno = LBX_EEOF; + lbx_error_raise(LBX_EEOF); goto err; } @@ -196,8 +195,8 @@ lbx_file_stat(struct lbx_state *lbx, unsigned fileno, struct lbx_statbuf *buf) static char str[256]; /* FIXME */ if (fileno >= lbx->nfiles) { + lbx_error_raise(LBX_ENOENT); buf->name = NULL; - lbx_errno = LBX_ERANGE; return -1; } @@ -224,19 +223,18 @@ struct lbx_file_state *lbx_file_open(struct lbx_state *lbx, unsigned fileno) struct lbx_file_state *state; if (fileno >= lbx->nfiles) { - lbx_errno = LBX_ERANGE; + lbx_error_raise(LBX_ENOENT); return NULL; } lbx->last_file = NULL; if (lbx->fops->seek(lbx->f, lbx->offsets[fileno], SEEK_SET) != 0) { - lbx_errno = -errno; return NULL; } state = malloc(sizeof *state); if (!state) { - lbx_errno = -errno; + lbx_error_raise(LBX_ENOMEM); return NULL; } @@ -318,19 +316,3 @@ void lbx_file_close(struct lbx_file_state *f) f->lbx->last_file = NULL; free(f); } - -const char *lbx_strerror(void) -{ - if (lbx_errno < 0) - return strerror(-lbx_errno); - - switch (lbx_errno) { - case LBX_ESUCCESS: return "Success"; - case LBX_EMAGIC: return "Bad magic number"; - case LBX_EEOF: return "Unexpected end-of-file"; - case LBX_ERANGE: return "Index out of range"; - case LBX_EFORMAT: return "Invalid file format"; - } - - return "Unknown error"; -} diff --git a/src/lbx.h b/src/lbx.h index 3570803..6b7ca02 100644 --- a/src/lbx.h +++ b/src/lbx.h @@ -3,16 +3,6 @@ #include -/* Errors */ -enum { - LBX_ESUCCESS, - LBX_EMAGIC, - LBX_EEOF, - LBX_ERANGE, - LBX_EFORMAT, -}; -extern int lbx_errno; - struct lbx_file_ops { size_t (*read)(void *buf, size_t size, void *handle); int (*seek)(void *handle, long offset, int whence); @@ -60,7 +50,4 @@ long lbx_file_tell(LBXfile *f); int lbx_file_eof(LBXfile *f); void lbx_file_close(LBXfile *f); -/* Misc operations */ -const char *lbx_strerror(void); - #endif diff --git a/src/lbximg.c b/src/lbximg.c index d52f688..e5e3d07 100644 --- a/src/lbximg.c +++ b/src/lbximg.c @@ -29,6 +29,7 @@ #include "tools.h" #include "image.h" +#include "error.h" #include "lbx.h" /* Global flags */ @@ -238,7 +239,7 @@ 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_strerror()); + errmsg("failed to open override image: %s\n", lbx_errmsg()); return -1; } lbximg_getinfo(overimg, &info); @@ -250,7 +251,7 @@ static int loadoverride(FILE *f, struct lbx_colour palette[static 256]) } if (lbximg_getpalette(overimg, palette) == -1) { - errmsg("error reading override palette: %s\n", lbx_strerror()); + errmsg("error reading override palette: %s\n", lbx_errmsg()); lbximg_close(overimg); return -1; } @@ -287,13 +288,13 @@ static int loadpalette(LBXimg *img, struct lbx_imginfo *info, /* Read the external palette, if any. */ if (palf && lbximg_loadpalette(palf, &lbx_default_fops, palette) != 0) { - errmsg("error reading external palette: %s\n", lbx_strerror()); + errmsg("error reading external palette: %s\n", lbx_errmsg()); return -1; } /* Read the embedded palette, if any. */ if (info->palettesz && lbximg_getpalette(img, palette) == -1) { - errmsg("error reading embedded palette: %s\n", lbx_strerror()); + errmsg("error reading embedded palette: %s\n", lbx_errmsg()); return -1; } @@ -344,7 +345,7 @@ int decode(LBXimg *img, FILE *palf, FILE *override, char **argv) data = lbximg_getframe(img, i); if (!data) { - errmsg("error in frame %u: %s\n", i, lbx_strerror()); + errmsg("error in frame %u: %s\n", i, lbx_errmsg()); continue; } @@ -452,7 +453,7 @@ int main(int argc, char **argv) img = lbximg_open(&stdin_handle, &lbx_pipe_fops, NULL); if (!img) { - errmsg("failed to open image: %s.\n", lbx_strerror()); + errmsg("failed to open image: %s.\n", lbx_errmsg()); return EXIT_FAILURE; } diff --git a/src/lbxtool.c b/src/lbxtool.c index f393eaa..9c4b57b 100644 --- a/src/lbxtool.c +++ b/src/lbxtool.c @@ -26,7 +26,7 @@ #include "tools.h" #include "lbx.h" - +#include "error.h" static void printusage(void) { @@ -166,8 +166,7 @@ int extract(LBX *lbx, int verbose, char **argv) { file = lbx_file_open(lbx, i); if (!file) { - errmsg("failed to open archive member %s: %s.\n", - stat.name, lbx_strerror()); + errmsg("%s: %s.\n", stat.name, lbx_errmsg()); continue; } @@ -241,7 +240,7 @@ int main(int argc, char **argv) lbx = lbx_open(&stdin_handle, &lbx_pipe_fops, NULL, "stdin"); if (!lbx) { - errmsg("failed to open archive: %s.\n", lbx_strerror()); + errmsg("%s: %s.\n", file ? file : "stdin", lbx_errmsg()); return EXIT_FAILURE; }