This source file includes following definitions.
- __sir_seterror
- __sir_setoserror
- __sir_handleerr
- _sir_invalidparameter
- __sir_handlewin32err
- _sir_geterror
- _sir_geterrorinfo
- _sir_reset_tls_error
- PRINTF_FORMAT_ATTR
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 #include "sir/errors.h"
34 #include "sir/helpers.h"
35
36 #if defined(__MACOS__) || defined(__BSD__) || \
37 (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L && !defined(_GNU_SOURCE)))
38 # define __HAVE_XSI_STRERROR_R__
39 # if defined(__GLIBC__) && GLIBC_VERSION < 21300
40 # define __HAVE_XSI_STRERROR_R_ERRNO__
41 # endif
42 #elif defined(_GNU_SOURCE) && defined(__GLIBC__)
43 # define __HAVE_GNU_STRERROR_R__
44 #elif defined(__HAVE_STDC_SECURE_OR_EXT1__)
45 # define __HAVE_STRERROR_S__
46 #endif
47
48
49 static _sir_thread_local sir_thread_err _sir_te = {
50 _SIR_E_NOERROR, 0, {0}, {SIR_UNKNOWN, SIR_UNKNOWN, 0}
51 };
52
53 #define _SIR_E_PLATFORM_ERRORMSG "Platform error"
54 #define _SIR_E_PLATFORM_ERRORFORMAT _SIR_E_PLATFORM_ERRORMSG " code %d: %s"
55
56 static const struct {
57 uint32_t e;
58 const char* msg;
59 } sir_errors[] = {
60 {_SIR_E_NOERROR, "The operation completed successfully"},
61 {_SIR_E_NOTREADY, "libsir has not been initialized"},
62 {_SIR_E_ALREADY, "libsir is already initialized"},
63 {_SIR_E_DUPITEM, "Item already managed by libsir"},
64 {_SIR_E_NOITEM, "Item not managed by libsir"},
65 {_SIR_E_NOROOM, "Maximum number of items already stored"},
66 {_SIR_E_OPTIONS, "Option flags are invalid"},
67 {_SIR_E_LEVELS, "Level flags are invalid"},
68 {_SIR_E_TEXTSTYLE, "Text style is invalid"},
69 {_SIR_E_STRING, "Invalid string argument"},
70 {_SIR_E_NULLPTR, "NULL pointer argument"},
71 {_SIR_E_INVALID, "Invalid argument"},
72 {_SIR_E_NODEST, "No destinations registered for level"},
73 {_SIR_E_UNAVAIL, "Feature is disabled or unavailable"},
74 {_SIR_E_INTERNAL, "An internal error has occurred"},
75 {_SIR_E_COLORMODE, "Color mode is invalid"},
76 {_SIR_E_TEXTATTR, "Text attributes are invalid"},
77 {_SIR_E_TEXTCOLOR, "Text color is invalid for mode"},
78 {_SIR_E_PLUGINBAD, "Plugin module is malformed"},
79 {_SIR_E_PLUGINDAT, "Data produced by plugin is invalid"},
80 {_SIR_E_PLUGINVER, "Plugin interface version unsupported"},
81 {_SIR_E_PLUGINERR, "Plugin reported failure"},
82 {_SIR_E_PLATFORM, _SIR_E_PLATFORM_ERRORFORMAT},
83 {_SIR_E_UNKNOWN, "Unknown error"},
84 };
85
86 bool __sir_seterror(uint32_t err, const char* func, const char* file, uint32_t line) {
87 if (_sir_validerror(err)) {
88 _sir_te.lasterror = err;
89 _sir_te.loc.func = func;
90 _sir_te.loc.file = file;
91 _sir_te.loc.line = line;
92
93 if (_SIR_E_PLATFORM != err) {
94 _sir_te.os_code = 0;
95 _sir_resetstr(_sir_te.os_msg);
96 }
97 }
98 #if defined(DEBUG) && defined(SIR_SELFLOG)
99 if (_SIR_E_NOERROR != err) {
100 char errmsg[SIR_MAXERROR] = {0};
101 _sir_geterror(errmsg);
102 __sir_selflog(func, file, line, "%s", errmsg);
103 }
104 #endif
105 return false;
106 }
107
108 void __sir_setoserror(int code, const char* msg, const char* func, const char* file, uint32_t line) {
109 _sir_te.os_code = code;
110 _sir_resetstr(_sir_te.os_msg);
111
112 if (_sir_validstrnofail(msg))
113 (void)_sir_strncpy(_sir_te.os_msg, SIR_MAXERROR, msg, SIR_MAXERROR);
114
115 (void)__sir_seterror(_SIR_E_PLATFORM, func, file, line);
116 }
117
118 bool __sir_handleerr(int code, const char* func, const char* file, uint32_t line) {
119 if (SIR_E_NOERROR != code) {
120 char message[SIR_MAXERROR] = {0};
121 int finderr = 0;
122 errno = SIR_E_NOERROR;
123
124 #if defined(__HAVE_XSI_STRERROR_R__)
125 _sir_selflog("using XSI strerror_r");
126 finderr = strerror_r(code, message, SIR_MAXERROR);
127 # if defined(__HAVE_XSI_STRERROR_R_ERRNO__)
128 _sir_selflog("using XSI strerror_r for glibc < 2.13");
129 if (finderr == -1)
130 finderr = errno;
131 # endif
132 #elif defined(__HAVE_GNU_STRERROR_R__)
133 _sir_selflog("using GNU strerror_r");
134 const char* tmp = strerror_r(code, message, SIR_MAXERROR);
135 if (tmp != message)
136 (void)_sir_strncpy(message, SIR_MAXERROR, tmp, SIR_MAXERROR);
137 #elif defined(__HAVE_STRERROR_S__)
138 _sir_selflog("using strerror_s");
139 finderr = (int)strerror_s(message, SIR_MAXERROR, code);
140 #else
141 _sir_selflog("using strerror");
142 const char* tmp = strerror(code);
143 (void)_sir_strncpy(message, SIR_MAXERROR, tmp, strnlen(tmp, SIR_MAXERROR));
144 #endif
145 if (0 == finderr) {
146 __sir_setoserror(code, message, func, file, line);
147 #if defined(__HAVE_XSI_STRERROR_R__) || defined(__HAVE_STRERROR_S__)
148 } else {
149
150
151
152
153 # if defined(__HAVE_XSI_STRERROR_R__)
154 _sir_selflog("strerror_r failed! error: %d", finderr);
155 # elif defined(__HAVE_STRERROR_S__)
156 _sir_selflog("strerror_s failed! error: %d", finderr);
157 # endif
158 #endif
159 }
160 }
161 return false;
162 }
163
164 #if defined(__WIN__)
165 void _sir_invalidparameter(const wchar_t* expr, const wchar_t* func, const wchar_t* file,
166 unsigned int line, uintptr_t reserved) {
167 _sir_selflog("invalid parameter handler: expression: '%S' in %S (%S:%u)",
168 expr, func, file, line);
169 SIR_UNUSED(reserved);
170 }
171
172 bool __sir_handlewin32err(DWORD code, const char* func, const char* file, uint32_t line) {
173 char* errbuf = NULL;
174 DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
175 FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK;
176
177 DWORD fmtmsg = FormatMessageA(flags, NULL, code, 0, (LPSTR)&errbuf, SIR_MAXERROR, NULL);
178 if (0 < fmtmsg && _sir_validstrnofail(errbuf)) {
179 if (errbuf[fmtmsg - 1] == '\n' || errbuf[fmtmsg - 1] == ' ')
180 errbuf[fmtmsg - 1] = '\0';
181 __sir_setoserror((int)code, errbuf, func, file, line);
182 } else {
183 _sir_selflog("FormatMessage failed! error: %lu", GetLastError());
184 SIR_ASSERT(false);
185 }
186
187 if (errbuf) {
188 HLOCAL local_free = LocalFree((HLOCAL)errbuf);
189 SIR_ASSERT_UNUSED(NULL == local_free, local_free);
190 errbuf = NULL;
191 }
192 return false;
193 }
194 #endif
195
196 uint32_t _sir_geterror(char message[SIR_MAXERROR]) {
197 _sir_resetstr(message);
198
199 static const size_t low = 0;
200 static const size_t high = _sir_countof(sir_errors) - 1;
201
202 uint32_t retval = _SIR_E_UNKNOWN;
203
204 _SIR_DECLARE_BIN_SEARCH(low, high);
205 _SIR_BEGIN_BIN_SEARCH()
206
207 if (sir_errors[_mid].e == _sir_te.lasterror) {
208 char* heap_msg = NULL;
209
210 if (_SIR_E_PLATFORM == sir_errors[_mid].e) {
211 heap_msg = calloc(SIR_MAXERROR, sizeof(char));
212 if (_sir_validptrnofail(heap_msg)) {
213 _sir_snprintf_trunc(heap_msg, SIR_MAXERROR, _SIR_E_PLATFORM_ERRORFORMAT, _sir_te.os_code,
214 (_sir_validstrnofail(_sir_te.os_msg) ? _sir_te.os_msg : SIR_UNKNOWN));
215 }
216 }
217
218 _sir_snprintf_trunc(message, SIR_MAXERROR, SIR_ERRORFORMAT, _sir_te.loc.func,
219 _sir_te.loc.file, _sir_te.loc.line, (_sir_validstrnofail(heap_msg)
220 ? heap_msg : (_sir_validstrnofail(sir_errors[_mid].msg)
221 ? sir_errors[_mid].msg : SIR_UNKNOWN)));
222
223 _sir_safefree(&heap_msg);
224
225 retval = sir_errors[_mid].e;
226 break;
227 }
228
229 _SIR_ITERATE_BIN_SEARCH((sir_errors[_mid].e < _sir_te.lasterror ? 1 : -1));
230 _SIR_END_BIN_SEARCH();
231
232 return retval;
233 }
234
235 void _sir_geterrorinfo(sir_errorinfo* err) {
236 if (!_sir_validptr(err))
237 return;
238
239 (void)memset(err, 0, sizeof(sir_errorinfo));
240
241 err->func = _sir_te.loc.func;
242 err->file = _sir_te.loc.file;
243 err->line = _sir_te.loc.line;
244
245 err->os_code = _sir_te.os_code;
246 (void)_sir_strncpy(err->os_msg, SIR_MAXERROR, (_sir_validstrnofail(_sir_te.os_msg)
247 ? _sir_te.os_msg : SIR_UNKNOWN), SIR_MAXERROR);
248
249 err->code = _sir_geterrcode(SIR_E_UNKNOWN);
250
251 static const size_t low = 0;
252 static const size_t high = _sir_countof(sir_errors) - 1;
253
254 _SIR_DECLARE_BIN_SEARCH(low, high);
255 _SIR_BEGIN_BIN_SEARCH()
256
257 if (sir_errors[_mid].e == _sir_te.lasterror) {
258 err->code = _sir_geterrcode(sir_errors[_mid].e);
259 if (_SIR_E_PLATFORM == sir_errors[_mid].e)
260 (void)_sir_strncpy(err->msg, SIR_MAXERROR, _SIR_E_PLATFORM_ERRORMSG, SIR_MAXERROR);
261 else
262 (void)_sir_strncpy(err->msg, SIR_MAXERROR, sir_errors[_mid].msg, SIR_MAXERROR);
263 break;
264 }
265
266 _SIR_ITERATE_BIN_SEARCH((sir_errors[_mid].e < _sir_te.lasterror ? 1 : -1));
267 _SIR_END_BIN_SEARCH();
268 }
269
270 void _sir_reset_tls_error(void) {
271 _sir_te.lasterror = _SIR_E_NOERROR;
272 _sir_te.os_code = 0;
273 _sir_resetstr(_sir_te.os_msg);
274 _sir_te.loc.func = SIR_UNKNOWN;
275 _sir_te.loc.file = SIR_UNKNOWN;
276 _sir_te.loc.line = 0U;
277 }
278
279 #if defined(SIR_SELFLOG)
280 PRINTF_FORMAT_ATTR(4, 5)
281 void __sir_selflog(const char* func, const char* file, uint32_t line,
282 PRINTF_FORMAT const char* format, ...) {
283 bool success = true;
284 char prefix[256];
285
286 int write1 = snprintf(prefix, 256, "%s (%s:%"PRIu32"): ", func, file, line);
287 _sir_eqland(success, write1 > 0);
288
289 if (write1 > 0) {
290 va_list args;
291 va_list args2;
292 va_start(args, format);
293 va_copy(args2, args);
294
295 int write2 = vsnprintf(NULL, 0, format, args);
296 va_end(args);
297 _sir_eqland(success, write2 > 0);
298
299 if (write2 > 0) {
300 char* buf = (char*)malloc(write2 + 1);
301 _sir_eqland(success, NULL != buf);
302
303 if (buf) {
304 write2 = vsnprintf(buf, write2 + 1, format, args2);
305 va_end(args2);
306 _sir_eqland(success, write2 > 0);
307
308 bool error = false;
309 bool warn = false;
310 if (write2 > 0) {
311 # if !defined(__WIN__)
312 if (NULL != strcasestr(buf, "error") ||
313 NULL != strcasestr(buf, "assert")) {
314 # else
315 if (NULL != StrStrIA(buf, "error") ||
316 NULL != StrStrIA(buf, "assert")) {
317 # endif
318 error = true;
319 # if !defined(__WIN__)
320 } else if (NULL != strcasestr(buf, "warn")) {
321 # else
322 } else if (NULL != StrStrIA(buf, "warn")) {
323 # endif
324 warn = true;
325 }
326 write2 = fprintf(stderr, (error ? SIR_BRED("%s%s") SIR_EOL :
327 (warn ? SIR_YELLOW("%s%s") SIR_EOL : "%s%s" SIR_EOL)), prefix, buf);
328 _sir_eqland(success, write2 > 0);
329 }
330
331 _sir_safefree(&buf);
332 }
333 }
334 }
335
336 SIR_ASSERT_UNUSED(success, success);
337 }
338 #endif