/*
* 2ooM: The Master of Orion II Reverse Engineering Project
* Utilities for out-of-band error propagation.
* Copyright © 2010, 2013 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
#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 int user_error_count, user_error_max = 2;
#define MIN(a, b) ((a) < (b) ? (a) : (b))
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_MAX, INT_MAX)/2 - LBX_EUBASE)
return -1;
if (2 * user_error_max >= SIZE_MAX / 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_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;
}