X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/e745d25d7f109057962c6904be98f5f35e874ecc..72aedaedd7afa666f7c69dfe7ef4b7ec3dbc2458:/src/error.c diff --git a/src/error.c b/src/error.c index cf4411e..758f58e 100644 --- a/src/error.c +++ b/src/error.c @@ -134,6 +134,35 @@ void cdecl__errmsg(unsigned msg) set_err(msg, &state->err); } +/* + * In the NLS-disabled case, all format strings are of the form + * + * "blah blah %s" + * + * so we exploit this to implement a simple snprintf workalike using the + * libcdecl output helpers directly. + * + * In the NLS-enabled case, we have to use snprintf as format strings may + * be translated. GNU libintl ensures a suitable version is available. + */ +static size_t +fmt_err(struct err_state *state, const char *fmt, const char *arg) +{ +#if ENABLE_NLS + snprintf(state->str, state->nstr, fmt, arg); + return strlen(fmt) + strlen(arg); +#else + struct output_state dst = { state->str, state->nstr }; + size_t rc; + + rc = cdecl__strlcpy(dst.dst, fmt, dst.dstlen); + cdecl__advance(&dst, rc-2); + cdecl__emit(&dst, arg); + + return dst.accum; +#endif +} + /* * Sets the library error to code; fmt is a printf-style string that may use * up to one %s directive, to refer to arg. @@ -141,16 +170,18 @@ void cdecl__errmsg(unsigned msg) void cdecl__err(unsigned code, const char *fmt, const char *arg) { struct err_state *state; - int rc, try = 0; + unsigned try = 0; + size_t rc; state = get_err_state(); if (!state) return; retry: - rc = snprintf(state->str, state->nstr, fmt, arg); - if (rc > 0 && rc >= state->nstr) { + rc = fmt_err(state, fmt, arg); + if (rc >= state->nstr) { assert(try++ == 0 && rc < SIZE_MAX / 4); + state = alloc_err_state(state, (size_t)(rc+1u) * 3 / 2); if (!state) return;