]> git.draconx.ca Git - liblbx.git/commitdiff
liblbx: Implement improved error reporting mechanism.
authorNick Bowler <nbowler@draconx.ca>
Thu, 11 Feb 2010 03:08:04 +0000 (22:08 -0500)
committerNick Bowler <nbowler@draconx.ca>
Thu, 11 Feb 2010 04:46:58 +0000 (23:46 -0500)
We now use a FIFO-of-errors approach (similar to libltdl) as opposed to
an errno-esque approach.

src/Makefile.inc
src/error.c [new file with mode: 0644]
src/error.h [new file with mode: 0644]
src/fops.c
src/image.c
src/lbx.c
src/lbx.h
src/lbximg.c
src/lbxtool.c

index 8b39a5203cd067775facadda425c02af9cc12fce..c033f5376cb20ad3c0398fa46bbb6ff1fdf5b775 100644 (file)
@@ -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 (file)
index 0000000..c32d3b6
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+
+#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 (file)
index 0000000..577078a
--- /dev/null
@@ -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
index 746455fd14d9f2346790c69c7c62bd94b504c584..e546b1097692f3e0f5b07c9403828772de62f53b 100644 (file)
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 #include <stdio.h>
+#include <errno.h>
 
 #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;
 }
index 69d4ebb4b8e9fc71713768365e1ad19401c6e127..a5a4bffcc2a4f9cf5956c4c4da719f46eac97b59 100644 (file)
@@ -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;
 }
 
index 0e26315fc8652acdc922a7f526140d5288463ab9..26a59bd66604141855773c4f7b80772d4c6ba045 100644 (file)
--- a/src/lbx.c
+++ b/src/lbx.c
 
 #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";
-}
index 3570803e4958c18284c45e8dd2bfc84d53a18430..6b7ca02ba4a609f41a732819d1e9cb36fa3e2669 100644 (file)
--- a/src/lbx.h
+++ b/src/lbx.h
@@ -3,16 +3,6 @@
 
 #include <stdio.h>
 
-/* 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
index d52f68840f5effee60652a2f3396f6287d288849..e5e3d07903387c401158a67499a1243aee335cda 100644 (file)
@@ -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;
        }
 
index f393eaab3b43657364a51169a810637e53a76bc1..9c4b57bbf623d6dafaa45f76084b964db07703d8 100644 (file)
@@ -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;
        }