]> git.draconx.ca Git - liblbx.git/blob - src/error.c
c32d3b6188e7afb208fb83fa24fdbe38f90292a6
[liblbx.git] / src / error.c
1 /*
2  *  2ooM: The Master of Orion II Reverse Engineering Project
3  *  Utilities for out-of-band error propagation.
4  *  Copyright (C) 2010 Nick Bowler
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <libintl.h>
26
27 #include "error.h"
28
29 #define _(s) dgettext(PACKAGE, s)
30
31 #if !defined(LBX_ERROR_LIMIT)
32 #       define LBX_ERROR_LIMIT 256
33 #endif
34
35 static unsigned error_base, error_tip;
36 static int error_ring[LBX_ERROR_LIMIT];
37
38 static const char **user_errors;
39 static unsigned user_error_count;
40 static unsigned user_error_max = 2;
41
42 int lbx_error_new(const char *str)
43 {
44         assert(user_error_count <= user_error_max);
45         if (!user_errors || user_error_count == user_error_max) {
46                 size_t size = sizeof *user_errors * user_error_max * 2;
47                 const char **new;
48
49                 new = realloc(user_errors, size);
50                 if (!new)
51                         return -1;
52                 user_error_max *= 2;
53                 user_errors = new;
54         }
55
56         user_errors[user_error_count] = str;
57         return LBX_EUBASE + user_error_count++;
58 }
59
60 int lbx_error_raise(int code)
61 {
62         if (code == LBX_EOK) {
63                 return -1;
64         } else if (code >= LBX_EMAX && code < LBX_EUBASE
65                    || code >= LBX_EUBASE + user_error_count) {
66                 fprintf(stderr, "%s: invalid error code %d\n", __func__, code);
67                 return -1;
68         }
69
70         error_ring[error_tip++] = code;
71         error_tip %= LBX_ERROR_LIMIT;
72
73         if (error_tip == error_base) {
74                 error_base = (error_base + 1) % LBX_ERROR_LIMIT;
75                 return -1;
76         }
77
78         return 0;
79 }
80
81 static void getmsg(int error, const char **msg)
82 {
83         if (error < 0) {
84                 *msg = strerror(-error);
85                 return;
86         }
87
88         switch (error) {
89         case LBX_EOK:
90                 *msg = _("Success");
91                 break;
92         case LBX_EMAGIC:
93                 *msg = _("Bad magic number");
94                 break;
95         case LBX_EFORMAT:
96                 *msg = _("Invalid file format");
97                 break;
98         case LBX_ENOENT:
99                 *msg = _("Specified item does not exist");
100                 break;
101         case LBX_ENOMEM:
102                 *msg = _("Memory allocation failed");
103                 break;
104         case LBX_EEOF:
105                 *msg = _("Unexpected end of file");
106                 break;
107         default:
108                 *msg = user_errors[error - LBX_EUBASE];
109         }
110 }
111
112 int lbx_error_peek(const char **msg)
113 {
114         int error = error_tip == error_base ? LBX_EOK : error_ring[error_base];
115
116         assert(error < LBX_EMAX || error >= LBX_EUBASE);
117         assert(error < LBX_EUBASE + user_error_count);
118
119         if (msg)
120                 getmsg(error, msg);
121         return error;
122 }
123
124
125 int lbx_error_get(const char **msg)
126 {
127         int error = lbx_error_peek(msg);
128
129         if (error != LBX_EOK)
130                 error_base = (error_base + 1) % LBX_ERROR_LIMIT;
131         return error;
132 }