]> git.draconx.ca Git - liblbx.git/blobdiff - src/error.c
liblbx: Implement improved error reporting mechanism.
[liblbx.git] / src / error.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;
+}