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/>.
23 #include <glthread/lock.h>
24 #include <glthread/tls.h>
27 #include "cdecl-internal.h"
29 gl_once_define(static, tls_initialized);
30 static gl_tls_key_t tls_key;
33 struct cdecl_error err;
38 /* This error is reserved for extremely dire out-of-memory conditions. */
39 static struct err_state err_no_mem = {
46 const char *cdecl__strerror(unsigned code)
51 case CDECL_ENOMEM: return gettext(strtab+err_enomem);
52 case CDECL_ENOPARSE: return gettext(strtab+err_enoparse);
58 static void free_err(void *err)
60 if (err == &err_no_mem)
66 static void set_error(const struct cdecl_error *err)
68 struct err_state *state;
72 need_len = strlen(err->str) + 1;
75 state = gl_tls_get(tls_key);
76 if (state == &err_no_mem)
78 if (!state || state->nstr < need_len) {
79 struct err_state *tmp;
81 tmp = realloc(state, sizeof *state + need_len);
83 /* Re-use the existing state buffer, if any. */
85 state->err = err_no_mem.err;
89 gl_tls_set(tls_key, state);
94 state->nstr = need_len;
95 gl_tls_set(tls_key, state);
100 memcpy(state->str, err->str, need_len);
101 state->err.str = state->str;
103 state->err.str = cdecl__strerror(state->err.code);
107 static void initialize(void)
110 err_no_mem.err.str = cdecl__strerror(CDECL_ENOMEM);
112 gl_tls_key_init(tls_key, free_err);
115 * This default error message is a stop-gap measure until all library
116 * error conditions use the new interface.
118 set_error(&(const struct cdecl_error){ .code = CDECL_ENOPARSE });
121 const struct cdecl_error *cdecl_get_error(void)
123 struct err_state *state;
125 gl_once(tls_initialized, initialize);
127 state = gl_tls_get(tls_key);
133 void cdecl__set_error(const struct cdecl_error *err)
135 gl_once(tls_initialized, initialize);