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