2 * Error handling for libcdecl.
3 * Copyright © 2011-2012, 2021 Nick Bowler
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <glthread/lock.h>
25 #include <glthread/tls.h>
28 #include "cdecl-internal.h"
30 gl_once_define(static, tls_initialized);
31 static gl_tls_key_t tls_key;
34 struct cdecl_error err;
36 char str[FLEXIBLE_ARRAY_MEMBER];
39 /* This error is reserved for extremely dire out-of-memory conditions. */
40 static struct err_state err_no_mem = {
47 const char *cdecl__strerror(unsigned code)
52 case CDECL_ENOMEM: return gettext(strtab+err_enomem);
53 case CDECL_ENOPARSE: return gettext(strtab+err_enoparse);
59 static void free_err(void *err)
61 if (err == &err_no_mem)
67 static void set_error(const struct cdecl_error *err)
69 struct err_state *state;
73 need_len = strlen(err->str) + 1;
76 state = gl_tls_get(tls_key);
77 if (state == &err_no_mem)
79 if (!state || state->nstr < need_len) {
80 struct err_state *tmp;
82 tmp = realloc(state, sizeof *state + need_len);
84 /* Re-use the existing state buffer, if any. */
86 state->err = err_no_mem.err;
90 gl_tls_set(tls_key, state);
95 state->nstr = need_len;
96 gl_tls_set(tls_key, state);
101 memcpy(state->str, err->str, need_len);
102 state->err.str = state->str;
104 state->err.str = cdecl__strerror(state->err.code);
108 static void initialize(void)
111 err_no_mem.err.str = cdecl__strerror(CDECL_ENOMEM);
113 gl_tls_key_init(tls_key, free_err);
116 * This default error message is a stop-gap measure until all library
117 * error conditions use the new interface.
119 set_error(&(const struct cdecl_error){ .code = CDECL_ENOPARSE });
122 const struct cdecl_error *cdecl_get_error(void)
124 struct err_state *state;
126 gl_once(tls_initialized, initialize);
128 state = gl_tls_get(tls_key);
134 void cdecl__set_error(const struct cdecl_error *err)
136 gl_once(tls_initialized, initialize);