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)
50 assert(code < sizeof offtab / sizeof offtab[0]);
51 assert(offtab[code] != 0);
53 return gettext((char *)&strtab + offtab[code]);
56 static void free_err(void *err)
58 if (err == &err_no_mem)
64 static void set_error(const struct cdecl_error *err)
66 struct err_state *state;
70 need_len = strlen(err->str) + 1;
73 state = gl_tls_get(tls_key);
74 if (state == &err_no_mem)
76 if (!state || state->nstr < need_len) {
77 struct err_state *tmp;
79 tmp = realloc(state, sizeof *state + need_len);
81 /* Re-use the existing state buffer, if any. */
83 state->err = err_no_mem.err;
87 gl_tls_set(tls_key, state);
92 state->nstr = need_len;
93 gl_tls_set(tls_key, state);
98 memcpy(state->str, err->str, need_len);
99 state->err.str = state->str;
101 state->err.str = cdecl__strerror(state->err.code);
105 static void initialize(void)
108 err_no_mem.err.str = cdecl__strerror(CDECL_ENOMEM);
110 gl_tls_key_init(tls_key, free_err);
113 * This default error message is a stop-gap measure until all library
114 * error conditions use the new interface.
116 set_error(&(const struct cdecl_error){ .code = CDECL_ENOPARSE });
119 const struct cdecl_error *cdecl_get_error(void)
121 struct err_state *state;
123 gl_once(tls_initialized, initialize);
125 state = gl_tls_get(tls_key);
131 void cdecl__set_error(const struct cdecl_error *err)
133 gl_once(tls_initialized, initialize);