From 52e527a02f40686f355d18ab2ba2d1d7c9fa0fbc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= Date: Thu, 2 Jun 2022 11:46:18 +0200 Subject: [PATCH] Make ?\LF generate 10, not -1 (bug#55738) The old -1 value was an artefact of the reader implementation. * src/lread.c (read_escape): Remove the `stringp` argument; assume character literal syntax. Never return -1. (read_string_literal): Handle string-specific escape semantics here and simplify. * test/src/lread-tests.el (lread-escaped-lf): New test. --- src/lread.c | 60 ++++++++++++++++++++--------------------- test/src/lread-tests.el | 5 ++++ 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/lread.c b/src/lread.c index 52fc0fff307..4b7d38a8e6c 100644 --- a/src/lread.c +++ b/src/lread.c @@ -2633,7 +2633,7 @@ enum { UNICODE_CHARACTER_NAME_LENGTH_BOUND = 200 }; If the escape sequence forces unibyte, return eight-bit char. */ static int -read_escape (Lisp_Object readcharfun, bool stringp) +read_escape (Lisp_Object readcharfun) { int c = READCHAR; /* \u allows up to four hex digits, \U up to eight. Default to the @@ -2663,12 +2663,6 @@ read_escape (Lisp_Object readcharfun, bool stringp) return '\t'; case 'v': return '\v'; - case '\n': - return -1; - case ' ': - if (stringp) - return -1; - return ' '; case 'M': c = READCHAR; @@ -2676,7 +2670,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) error ("Invalid escape character syntax"); c = READCHAR; if (c == '\\') - c = read_escape (readcharfun, 0); + c = read_escape (readcharfun); return c | meta_modifier; case 'S': @@ -2685,7 +2679,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) error ("Invalid escape character syntax"); c = READCHAR; if (c == '\\') - c = read_escape (readcharfun, 0); + c = read_escape (readcharfun); return c | shift_modifier; case 'H': @@ -2694,7 +2688,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) error ("Invalid escape character syntax"); c = READCHAR; if (c == '\\') - c = read_escape (readcharfun, 0); + c = read_escape (readcharfun); return c | hyper_modifier; case 'A': @@ -2703,19 +2697,19 @@ read_escape (Lisp_Object readcharfun, bool stringp) error ("Invalid escape character syntax"); c = READCHAR; if (c == '\\') - c = read_escape (readcharfun, 0); + c = read_escape (readcharfun); return c | alt_modifier; case 's': c = READCHAR; - if (stringp || c != '-') + if (c != '-') { UNREAD (c); return ' '; } c = READCHAR; if (c == '\\') - c = read_escape (readcharfun, 0); + c = read_escape (readcharfun); return c | super_modifier; case 'C': @@ -2726,7 +2720,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) case '^': c = READCHAR; if (c == '\\') - c = read_escape (readcharfun, 0); + c = read_escape (readcharfun); if ((c & ~CHAR_MODIFIER_MASK) == '?') return 0177 | (c & CHAR_MODIFIER_MASK); else if (! ASCII_CHAR_P ((c & ~CHAR_MODIFIER_MASK))) @@ -3011,7 +3005,7 @@ read_char_literal (Lisp_Object readcharfun) } if (ch == '\\') - ch = read_escape (readcharfun, 0); + ch = read_escape (readcharfun); int modifiers = ch & CHAR_MODIFIER_MASK; ch &= ~CHAR_MODIFIER_MASK; @@ -3065,14 +3059,24 @@ read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)], if (ch == '\\') { - ch = read_escape (readcharfun, 1); - - /* CH is -1 if \ newline or \ space has just been seen. */ - if (ch == -1) + /* First apply string-specific escape rules: */ + ch = READCHAR; + switch (ch) { + case 's': + /* `\s' is always a space in strings. */ + ch = ' '; + break; + case ' ': + case '\n': + /* `\SPC' and `\LF' generate no characters at all. */ if (p == read_buffer) cancel = true; continue; + default: + UNREAD (ch); + ch = read_escape (readcharfun); + break; } int modifiers = ch & CHAR_MODIFIER_MASK; @@ -3084,19 +3088,13 @@ read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)], force_multibyte = true; else /* I.e. ASCII_CHAR_P (ch). */ { - /* Allow `\C- ' and `\C-?'. */ - if (modifiers == CHAR_CTL) + /* Allow `\C-SPC' and `\^SPC'. This is done here because + the literals ?\C-SPC and ?\^SPC (rather inconsistently) + yield (' ' | CHAR_CTL); see bug#55738. */ + if (modifiers == CHAR_CTL && ch == ' ') { - if (ch == ' ') - { - ch = 0; - modifiers = 0; - } - else if (ch == '?') - { - ch = 127; - modifiers = 0; - } + ch = 0; + modifiers = 0; } if (modifiers & CHAR_SHIFT) { diff --git a/test/src/lread-tests.el b/test/src/lread-tests.el index 47351c1d116..99eec9d5487 100644 --- a/test/src/lread-tests.el +++ b/test/src/lread-tests.el @@ -317,4 +317,9 @@ literals (Bug#20852)." (should (equal (read-from-string "#_") '(## . 2)))) +(ert-deftest lread-escaped-lf () + ;; ?\LF should produce LF (only inside string literals do we ignore \LF). + (should (equal (read-from-string "?\\\n") '(?\n . 3))) + (should (equal (read-from-string "\"a\\\nb\"") '("ab" . 6)))) + ;;; lread-tests.el ends here -- 2.39.2