/* * 2ooM: The Master of Orion II Reverse Engineering Project * Utilities for out-of-band error propagation. * Copyright © 2010, 2013-2014 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 #include "error.h" #include "misc.h" // #define _(s) dgettext(PACKAGE, s) #define _(s) (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 int user_error_count, user_error_max = 2; int lbx_error_new(const char *str) { assert(user_error_count >= 0 && user_error_count <= user_error_max); if (!user_errors || user_error_count == user_error_max) { const char **new; size_t size; if (user_error_max >= MIN((size_t)-1, INT_MAX)/2 - LBX_EUBASE) return -1; if (2 * user_error_max >= (size_t)-1 / sizeof *user_errors) return -1; size = 2 * user_error_max * sizeof *user_errors; 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 >= 0 && ((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_EINVAL: *msg = _("Invalid argument"); 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; }