]> git.draconx.ca Git - liblbx.git/blob - src/error.c
liblbx: Rename LBX_ENOENT to LBX_EINVAL.
[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 © 2010, 2013-2014 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 <limits.h>
26 #include <inttypes.h>
27 #include <libintl.h>
28
29 #include "error.h"
30
31 #define _(s) dgettext(PACKAGE, s)
32
33 #if !defined(LBX_ERROR_LIMIT)
34 #       define LBX_ERROR_LIMIT 256
35 #endif
36
37 static unsigned error_base, error_tip;
38 static int error_ring[LBX_ERROR_LIMIT];
39
40 static const char **user_errors;
41 static int user_error_count, user_error_max = 2;
42
43 #define MIN(a, b) ((a) < (b) ? (a) : (b))
44
45 int lbx_error_new(const char *str)
46 {
47         assert(user_error_count >= 0 && user_error_count <= user_error_max);
48
49         if (!user_errors || user_error_count == user_error_max) {
50                 const char **new;
51                 size_t size;
52
53                 if (user_error_max >= MIN(SIZE_MAX, INT_MAX)/2 - LBX_EUBASE)
54                         return -1;
55                 if (2 * user_error_max >= SIZE_MAX / sizeof *user_errors)
56                         return -1;
57
58                 size = 2 * user_error_max * sizeof *user_errors;
59                 new = realloc(user_errors, size);
60                 if (!new)
61                         return -1;
62                 user_error_max *= 2;
63                 user_errors = new;
64         }
65
66         user_errors[user_error_count] = str;
67         return LBX_EUBASE + user_error_count++;
68 }
69
70 int lbx_error_raise(int code)
71 {
72         if (code == LBX_EOK) {
73                 return -1;
74         } else if (code >= 0 && ((code >= LBX_EMAX && code < LBX_EUBASE)
75                                   || code >= LBX_EUBASE + user_error_count)) {
76                 fprintf(stderr, "%s: invalid error code %d\n", __func__, code);
77                 return -1;
78         }
79
80         error_ring[error_tip++] = code;
81         error_tip %= LBX_ERROR_LIMIT;
82
83         if (error_tip == error_base) {
84                 error_base = (error_base + 1) % LBX_ERROR_LIMIT;
85                 return -1;
86         }
87
88         return 0;
89 }
90
91 static void getmsg(int error, const char **msg)
92 {
93         if (error < 0) {
94                 *msg = strerror(-error);
95                 return;
96         }
97
98         switch (error) {
99         case LBX_EOK:
100                 *msg = _("Success");
101                 break;
102         case LBX_EMAGIC:
103                 *msg = _("Bad magic number");
104                 break;
105         case LBX_EFORMAT:
106                 *msg = _("Invalid file format");
107                 break;
108         case LBX_EINVAL:
109                 *msg = _("Invalid argument");
110                 break;
111         case LBX_ENOMEM:
112                 *msg = _("Memory allocation failed");
113                 break;
114         case LBX_EEOF:
115                 *msg = _("Unexpected end of file");
116                 break;
117         default:
118                 *msg = user_errors[error - LBX_EUBASE];
119         }
120 }
121
122 int lbx_error_peek(const char **msg)
123 {
124         int error = error_tip == error_base ? LBX_EOK : error_ring[error_base];
125
126         assert(error < LBX_EMAX || error >= LBX_EUBASE);
127         assert(error < LBX_EUBASE + user_error_count);
128
129         if (msg)
130                 getmsg(error, msg);
131         return error;
132 }
133
134
135 int lbx_error_get(const char **msg)
136 {
137         int error = lbx_error_peek(msg);
138
139         if (error != LBX_EOK)
140                 error_base = (error_base + 1) % LBX_ERROR_LIMIT;
141         return error;
142 }