diff --git a/CHANGELOG.md b/CHANGELOG.md index d8206323..fd01e737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,8 @@ * Extending a word/line-wise selection now uses the original selection mode instead of switching to character-wise. * The scrollback search box no longer accepts non-printable characters. +* Non-formatting C0 control characters, `BS`, `HT` and `DEL` are now + stripped from pasted text. ### Deprecated diff --git a/selection.c b/selection.c index 00292541..8ed9b0cc 100644 --- a/selection.c +++ b/selection.c @@ -1559,7 +1559,7 @@ fdm_receive_decoder_uri(struct clipboard_receive *ctx, char *data, size_t size) char *start = ctx->buf.data; char *end = NULL; - while ((end = memchr(start, '\n', ctx->buf.idx - (start - ctx->buf.data))) != NULL) { + while ((end = memchr(start, '\r', ctx->buf.idx - (start - ctx->buf.data))) != NULL) { decode_one_uri(ctx, start, end - start); start = end + 1; } @@ -1608,12 +1608,49 @@ fdm_receive(struct fdm *fdm, int fd, int events, void *data) if (count == 0) break; - /* Call cb while at same time replacing \r\n with \n */ + /* + * Call cb while at same time replace: + * - \r\n -> \r + * - \n -> \r + * - C0 -> (strip non-formatting C0 characters) + * - \e -> (i.e. strip ESC) + */ char *p = text; size_t left = count; again: - for (size_t i = 0; i < left - 1; i++) { - if (p[i] == '\r' && p[i + 1] == '\n') { + for (size_t i = 0; i < left; i++) { + switch (p[i]) { + default: + break; + + case '\n': + p[i] = '\r'; + break; + + case '\r': + /* Convert \r\n -> \r */ + if (i + 1 < left && p[i + 1] == '\n') { + ctx->decoder(ctx, p, i + 1); + + xassert(i + 2 <= left); + p += i + 2; + left -= i + 2; + goto again; + } + break; + + /* C0 non-formatting control characters (\b \t \n \r excluded) */ + case '\x01': case '\x02': case '\x03': case '\x04': case '\x05': + case '\x06': case '\x07': case '\x0b': case '\x0c': case '\x0e': + case '\x0f': case '\x10': case '\x11': case '\x12': case '\x13': + case '\x14': case '\x15': case '\x16': case '\x17': case '\x18': + case '\x19': case '\x1a': case '\x1b': case '\x1c': case '\x1d': + case '\x1e': case '\x1f': + /* FALLTHROUGH */ + + /* Additional control characters stripped by default (but + * configurable) in XTerm: BS, HT, DEL */ + case '\b': case '\t': case '\x7f': ctx->decoder(ctx, p, i); xassert(i + 1 <= left);