diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 9352cbe5..40bea9b7 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -133,7 +133,7 @@ void cmd_load_buffer_callback(struct client *c, int closed, void *data) { const char *bufname = data; - char *pdata, *cause; + char *pdata, *cause, *saved; size_t psize; if (!closed) @@ -154,6 +154,11 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data) if (paste_set(pdata, psize, bufname, &cause) != 0) { /* No context so can't use server_client_msg_error. */ + if (~c->flags & CLIENT_UTF8) { + saved = cause; + cause = utf8_sanitize(saved); + free(saved); + } evbuffer_add_printf(c->stderr_data, "%s", cause); server_push_stderr(c); free(pdata); diff --git a/cmd-queue.c b/cmd-queue.c index ff8c69cb..5015981c 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -69,14 +69,21 @@ cmdq_print(struct cmd_q *cmdq, const char *fmt, ...) struct client *c = cmdq->client; struct window *w; va_list ap; + char *tmp, *msg; va_start(ap, fmt); if (c == NULL) /* nothing */; else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { - evbuffer_add_vprintf(c->stdout_data, fmt, ap); - + if (~c->flags & CLIENT_UTF8) { + vasprintf(&tmp, fmt, ap); + msg = utf8_sanitize(tmp); + free(tmp); + evbuffer_add(c->stdout_data, msg, strlen(msg)); + free(msg); + } else + evbuffer_add_vprintf(c->stdout_data, fmt, ap); evbuffer_add(c->stdout_data, "\n", 1); server_push_stdout(c); } else { @@ -101,6 +108,7 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) va_list ap; char *msg; size_t msglen; + char *tmp; va_start(ap, fmt); msglen = xvasprintf(&msg, fmt, ap); @@ -109,9 +117,14 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) if (c == NULL) cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg); else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { + if (~c->flags & CLIENT_UTF8) { + tmp = msg; + msg = utf8_sanitize(tmp); + free(tmp); + msglen = strlen(msg); + } evbuffer_add(c->stderr_data, msg, msglen); evbuffer_add(c->stderr_data, "\n", 1); - server_push_stderr(c); c->retval = 1; } else { diff --git a/tmux.h b/tmux.h index 618240b0..de19159d 100644 --- a/tmux.h +++ b/tmux.h @@ -2189,6 +2189,7 @@ u_int utf8_combine(const struct utf8_data *); int utf8_split(u_int, struct utf8_data *); u_int utf8_split2(u_int, u_char *); int utf8_strvis(char *, const char *, size_t, int); +char *utf8_sanitize(const char *); struct utf8_data *utf8_fromcstr(const char *); char *utf8_tocstr(struct utf8_data *); u_int utf8_cstrwidth(const char *); diff --git a/utf8.c b/utf8.c index e61bf996..cb20ea6d 100644 --- a/utf8.c +++ b/utf8.c @@ -585,6 +585,50 @@ utf8_strvis(char *dst, const char *src, size_t len, int flag) return (dst - start); } +/* + * Sanitize a string, changing any UTF-8 characters to '_'. Caller should free + * the returned string. Anything not valid printable ASCII or UTF-8 is + * stripped. + */ +char * +utf8_sanitize(const char *src) +{ + char *dst; + size_t n; + int more; + struct utf8_data utf8data; + u_int i; + + dst = NULL; + + n = 0; + while (*src != '\0') { + dst = xreallocarray(dst, n + 1, sizeof *dst); + if (utf8_open(&utf8data, *src)) { + more = 1; + while (*++src != '\0' && more) + more = utf8_append(&utf8data, *src); + if (!more) { + dst = xreallocarray(dst, n + utf8data.width, + sizeof *dst); + for (i = 0; i < utf8data.width; i++) + dst[n++] = '_'; + continue; + } + src -= utf8data.have; + } + if (*src > 0x1f && *src < 0x7f) + dst[n] = *src; + src++; + + n++; + } + + dst = xreallocarray(dst, n + 1, sizeof *dst); + dst[n] = '\0'; + return (dst); +} + /* * Convert a string into a buffer of UTF-8 characters. Terminated by size == 0. * Caller frees.