commit b619777dd67e271d639c6fb1d031650af8fd79e6 (HEAD, refs/remotes/origin/master) Author: Alan Mackenzie Date: Sat Mar 30 13:19:47 2019 +0000 Allow a CC Mode derived mode to have strings delimited by single quotes. Also fix the bug where the delimiters of '\033', etc. got the error face. * lisp/progmodes/cc-langs.el (c-single-quotes-quote-strings): Enhance the docr string. (c-string-delims): Change doc string to doc comment. * listp/progmodes/cc-mode.el (c-before-change-check-unbalanced-strings): In searches and comparisons, take account of the string delimiters possibly being '. Fix argument in call of c-before-change-check-unbalanced-strings. (c-parse-quotes-before-change, c-parse-quotes-after-change): Bind case-fold-search to nil. Analyze escape constructs inside character constants more accurately, in particular accepting as valid more than one character after /[0-7], /x, /u, and /U. Amend calculations to account for this extra length. diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 22b7b602f1..2dff5cf83c 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -599,13 +599,21 @@ EOL terminated statements." (c-lang-defvar c-has-bitfields (c-lang-const c-has-bitfields)) (c-lang-defconst c-single-quotes-quote-strings - "Whether the language uses single quotes for multi-char strings." + "Whether the language uses single quotes for multi-char strings. + +Note that to set up a language to use this, additionally: +\(i) the syntax of \"'\" must be \"string quote\" (7); +\(ii) the language's value of `c-has-quoted-numbers' must be nil; +\(iii) the language's value of `c-get-state-before-change-functions' may not + contain `c-parse-quotes-before-change'; +\(iv) the language's value of `c-before-font-lock-functions' may not contain + `c-parse-quotes-after-change'." t nil) (c-lang-defvar c-single-quotes-quote-strings (c-lang-const c-single-quotes-quote-strings)) (c-lang-defconst c-string-delims - "A list of characters which can delimit arbitrary length strings" +;; A list of characters which can delimit arbitrary length strings. t (if (c-lang-const c-single-quotes-quote-strings) '(?\" ?\') '(?\"))) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index b7812fa8f3..49268c4482 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -1212,12 +1212,15 @@ Note that the style variables are always made local to the buffer." (while (and (c-syntactic-re-search-forward - "\"\\|\\s|" (point-max) t t) + (if c-single-quotes-quote-strings + "[\"']\\|\\s|" + "\"\\|\\s|") + (point-max) t t) (progn (c-clear-char-property (1- (point)) 'syntax-table) (c-truncate-semi-nonlit-pos-cache (1- (point))) - (not (eq (char-before) ?\"))))) - (eq (char-before) ?\")) + (not (memq (char-before) c-string-delims))))) + (memq (char-before) c-string-delims)) (progn (c-pps-to-string-delim (point-max)) (< (point) (point-max)))))) @@ -1229,7 +1232,9 @@ Note that the style variables are always made local to the buffer." (eq beg-literal-type 'string)))) ;; Deal with deletion of backslashes before "s. (goto-char end) - (if (and (looking-at "\\\\*\"") + (if (and (looking-at (if c-single-quotes-quote-strings + "\\\\*[\"']" + "\\\\*\"")) (eq (logand (skip-chars-backward "\\\\" beg) 1) 1)) (setq c-bc-changed-stringiness (not c-bc-changed-stringiness))) (if (eq beg-literal-type 'string) @@ -1250,12 +1255,12 @@ Note that the style variables are always made local to the buffer." (forward-char) (backward-sexp) (c-clear-char-property eoll-1 'syntax-table) - (c-truncate-semi-nonlit-pos-cache eoll-1) - (c-clear-char-property (point) 'syntax-table)) + (c-clear-char-property (point) 'syntax-table) + (c-truncate-semi-nonlit-pos-cache (point))) ;; Opening " at EOB. (c-clear-char-property (1- (point)) 'syntax-table)) (when (and (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) - (eq (char-after) ?\")) ; Ignore an unterminated raw string's (. + (memq (char-after) c-string-delims)) ; Ignore an unterminated raw string's (. ;; Opening " on last line of text (without EOL). (c-clear-char-property (point) 'syntax-table) (c-truncate-semi-nonlit-pos-cache (point))))) @@ -1264,7 +1269,7 @@ Note that the style variables are always made local to the buffer." (when (and (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) - (eq (char-after) ?\")) + (memq (char-after) c-string-delims)) (c-clear-char-property (point) 'syntax-table) (c-truncate-semi-nonlit-pos-cache (point))))) @@ -1276,7 +1281,7 @@ Note that the style variables are always made local to the buffer." (c-truncate-semi-nonlit-pos-cache (1- (cdr end-limits)))) (when (and (eq beg-literal-type 'string) - (eq (char-after (car beg-limits)) ?\")) + (memq (char-after (car beg-limits)) c-string-delims)) (setq c-new-BEG (min c-new-BEG (car beg-limits))) (c-clear-char-property (car beg-limits) 'syntax-table) (c-truncate-semi-nonlit-pos-cache (car beg-limits)))))) @@ -1492,7 +1497,7 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") ;; ;; This function is called exclusively as a before-change function via the ;; variable `c-get-state-before-change-functions'. - (c-save-buffer-state () + (c-save-buffer-state (case-fold-search) (goto-char c-new-BEG) ;; We need to scan for 's from the BO (logical) line. (beginning-of-line) @@ -1508,13 +1513,13 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") ((c-quoted-number-head-before-point) (if (>= (point) c-new-BEG) (setq c-new-BEG (match-beginning 0)))) - ((looking-at "\\([^'\\]\\|\\\\.\\)'") + ((looking-at + "\\([^'\\]\\|\\\\\\([0-7]\\{1,3\\}\\|[xuU][0-9a-fA-F]+\\|.\\)\\)'") (goto-char (match-end 0)) (if (> (match-end 0) c-new-BEG) (setq c-new-BEG (1- (match-beginning 0))))) - ((or (>= (point) (1- c-new-BEG)) - (and (eq (point) (- c-new-BEG 2)) - (eq (char-after) ?\\))) + ((save-excursion + (not (search-forward "'" c-new-BEG t))) (setq c-new-BEG (1- (point)))) (t nil))) @@ -1534,19 +1539,26 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") (goto-char (match-end 0)) (if (> (match-end 0) c-new-END) (setq c-new-END (match-end 0)))) - ((looking-at "\\([^'\\]\\|\\\\.\\)'") + ((looking-at + "\\([^'\\]\\|\\\\\\([0-7]\\{1,3\\}\\|[xuU][0-9a-fA-F]+\\|.\\)\\)'") (goto-char (match-end 0)) (if (> (match-end 0) c-new-END) (setq c-new-END (match-end 0)))) + ((equal (c-get-char-property (1- (point)) 'syntax-table) '(1)) + (when (c-search-forward-char-property-with-value-on-char + 'syntax-table '(1) ?\' (c-point 'eoll)) + (setq c-new-END (max (point) c-new-END)))) (t nil))) ;; Having reached c-new-END, handle any 's after it whose context may be - ;; changed by the current buffer change. + ;; changed by the current buffer change. The idea is to catch + ;; monstrosities like ',',',',',' changing "polarity". (goto-char c-new-END) (cond ((c-quoted-number-tail-after-point) (setq c-new-END (match-end 0))) ((looking-at - "\\(\\\\.\\|.\\)?\\('\\([^'\\]\\|\\\\.\\)\\)*'") + "\\(\\\\\\([0-7]\\{1,3\\}\\|[xuU][0-9a-fA-F]+\\|.\\)\\|.\\)?\ +\\('\\([^'\\]\\|\\\\\\([0-7]\\{1,3\\}\\|[xuU][0-9a-fA-F]+\\|.\\)\\)\\)*'") (setq c-new-END (match-end 0)))) ;; Remove the '(1) syntax-table property from any "'"s within (c-new-BEG @@ -1575,7 +1587,7 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") ;; ;; This function is called exclusively as an after-change function via the ;; variable `c-before-font-lock-functions'. - (c-save-buffer-state (num-beg num-end) + (c-save-buffer-state (num-beg num-end case-fold-search) ;; Apply the needed syntax-table and c-digit-separator text properties to ;; quotes. (save-restriction @@ -1597,7 +1609,9 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") (c-put-char-properties-on-char num-beg num-end 'c-digit-separator t ?') (goto-char num-end)) - ((looking-at "\\([^\\']\\|\\\\.\\)'") ; balanced quoted expression. + ((looking-at + "\\([^\\']\\|\\\\\\([0-7]\\{1,3\\}\\|[xuU][0-9a-fA-F]+\\|.\\)\ +\\)'") ; balanced quoted expression. (goto-char (match-end 0))) (t (c-invalidate-state-cache (1- (point))) commit dd7d83e1dbe5c308384f92689d6eb27c9cde1c20 Author: Eli Zaretskii Date: Sat Mar 30 14:27:11 2019 +0300 Fix a thinko in a recent commit * src/buffer.c (Fkill_buffer): Fix last change. (Bug#31138) Reported by Mattias Engdegård . diff --git a/src/buffer.c b/src/buffer.c index 8bdc30300b..7c4691e52c 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1713,10 +1713,12 @@ cleaning up all windows currently displaying the buffer to be killed. */) /* First run the query functions; if any query is answered no, don't kill the buffer. */ if (!b->inhibit_buffer_hooks) - tem = CALLN (Frun_hook_with_args_until_failure, - Qkill_buffer_query_functions); - if (NILP (tem)) - return unbind_to (count, Qnil); + { + tem = CALLN (Frun_hook_with_args_until_failure, + Qkill_buffer_query_functions); + if (NILP (tem)) + return unbind_to (count, Qnil); + } /* Query if the buffer is still modified. */ if (INTERACTIVE && !NILP (BVAR (b, filename)) commit f2c14b2f01da00afdfb6c9c3e0a73d53e6e3fa62 Author: Mattias Engdegård Date: Tue Mar 19 13:47:13 2019 +0100 Release regexp before signalling overflow error * src/search.c (looking_at_1, search_buffer_re): Unfreeze the regexp buffer before signalling a matcher overflow, since the error processing may require quite some regexp use as well (Bug#34910). diff --git a/src/search.c b/src/search.c index 07ff0e4764..a450e920b0 100644 --- a/src/search.c +++ b/src/search.c @@ -319,7 +319,10 @@ looking_at_1 (Lisp_Object string, bool posix) ZV_BYTE - BEGV_BYTE); if (i == -2) - matcher_overflow (); + { + unbind_to (count, Qnil); + matcher_overflow (); + } val = (i >= 0 ? Qt : Qnil); if (preserve_match_data && i >= 0) @@ -1198,6 +1201,7 @@ search_buffer_re (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, pos_byte - BEGV_BYTE); if (val == -2) { + unbind_to (count, Qnil); matcher_overflow (); } if (val >= 0) @@ -1243,6 +1247,7 @@ search_buffer_re (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, lim_byte - BEGV_BYTE); if (val == -2) { + unbind_to (count, Qnil); matcher_overflow (); } if (val >= 0) commit 75ec1b1952633019f5afaf24dd87e7e4f7d31f9c Author: Mattias Engdegård Date: Tue Mar 19 13:06:20 2019 +0100 Fix spurious regexp reentrancy error * src/search.c (compile_pattern): Don't give up if the last regexp cache entry is busy. Instead, use the last (least recently used) non-busy entry, and only signal a reentrancy error if there is no free entry at all (Bug#34910). diff --git a/src/search.c b/src/search.c index e15e2b94e5..07ff0e4764 100644 --- a/src/search.c +++ b/src/search.c @@ -198,11 +198,13 @@ static struct regexp_cache * compile_pattern (Lisp_Object pattern, struct re_registers *regp, Lisp_Object translate, bool posix, bool multibyte) { - struct regexp_cache *cp, **cpp; + struct regexp_cache *cp, **cpp, **lru_nonbusy; - for (cpp = &searchbuf_head; ; cpp = &cp->next) + for (cpp = &searchbuf_head, lru_nonbusy = NULL; ; cpp = &cp->next) { cp = *cpp; + if (!cp->busy) + lru_nonbusy = cpp; /* Entries are initialized to nil, and may be set to nil by compile_pattern_1 if the pattern isn't valid. Don't apply string accessors in those cases. However, compile_pattern_1 @@ -222,13 +224,14 @@ compile_pattern (Lisp_Object pattern, struct re_registers *regp, && cp->buf.charset_unibyte == charset_unibyte) break; - /* If we're at the end of the cache, compile into the nil cell - we found, or the last (least recently used) cell with a - string value. */ + /* If we're at the end of the cache, compile into the last + (least recently used) non-busy cell in the cache. */ if (cp->next == 0) { - if (cp->busy) + if (!lru_nonbusy) error ("Too much matching reentrancy"); + cpp = lru_nonbusy; + cp = *cpp; compile_it: eassert (!cp->busy); compile_pattern_1 (cp, pattern, translate, posix); commit 9c0fa1172fd987a8f23b115145270383a11c12fc Author: Eli Zaretskii Date: Sat Mar 30 12:01:58 2019 +0300 Don't run buffer-related hooks in " *code conversion work*" buffers Note: portions of this change were mistakenly pushed as part of an unrelated commit a35a1f6a9. * src/buffer.c (Fget_buffer_create): Set inhibit_buffer_hooks non-zero for temporary buffers created by coding.c. Don't run buffer-list-update-hook for such buffers. (Frename_buffer, Fkill_buffer, record_buffer) (Fbury_buffer_internal): Don't run hooks for buffers whose inhibit_buffer_hooks flag is set. * src/buffer.h (struct buffer): New member inhibit_buffer_hooks. * src/pdumper.c (dump_buffer): Dump the new field. Update the hash value in HASH_buffer_XXX. * src/coding.c (make_conversion_work_buffer): Function deleted; code moved to code_conversion_save. (code_conversion_save): Insert code from make_conversion_work_buffer, but arrange for unwind-protecting the current buffer before switching to the work buffer. This avoids leaving reused_workbuf_in_use set if user presses C-g during encoding/decoding. (Vcode_conversion_workbuf_name): Now external variable. * src/coding.h (Vcode_conversion_reused_workbuf): Declare. diff --git a/src/buffer.c b/src/buffer.c index 5fabbc253c..8bdc30300b 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -37,6 +37,7 @@ along with GNU Emacs. If not, see . */ #include "window.h" #include "commands.h" #include "character.h" +#include "coding.h" #include "buffer.h" #include "region-cache.h" #include "indent.h" @@ -583,6 +584,11 @@ even if it is dead. The return value is never nil. */) set_string_intervals (name, NULL); bset_name (b, name); + if (STRINGP (Vcode_conversion_workbuf_name) + && strncmp (SSDATA (name), SSDATA (Vcode_conversion_workbuf_name), + SBYTES (Vcode_conversion_workbuf_name)) == 0) + b->inhibit_buffer_hooks = true; + bset_undo_list (b, SREF (name, 0) != ' ' ? Qnil : Qt); reset_buffer (b); @@ -595,7 +601,7 @@ even if it is dead. The return value is never nil. */) XSETBUFFER (buffer, b); Vbuffer_alist = nconc2 (Vbuffer_alist, list1 (Fcons (name, buffer))); /* And run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) + if (!NILP (Vrun_hooks) && !b->inhibit_buffer_hooks) call1 (Vrun_hooks, Qbuffer_list_update_hook); return buffer; @@ -1493,7 +1499,7 @@ This does not change the name of the visited file (if any). */) call0 (intern ("rename-auto-save-file")); /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) + if (!NILP (Vrun_hooks) && !current_buffer->inhibit_buffer_hooks) call1 (Vrun_hooks, Qbuffer_list_update_hook); /* Refetch since that last call may have done GC. */ @@ -1706,8 +1712,9 @@ cleaning up all windows currently displaying the buffer to be killed. */) /* First run the query functions; if any query is answered no, don't kill the buffer. */ - tem = CALLN (Frun_hook_with_args_until_failure, - Qkill_buffer_query_functions); + if (!b->inhibit_buffer_hooks) + tem = CALLN (Frun_hook_with_args_until_failure, + Qkill_buffer_query_functions); if (NILP (tem)) return unbind_to (count, Qnil); @@ -1726,7 +1733,8 @@ cleaning up all windows currently displaying the buffer to be killed. */) return unbind_to (count, Qt); /* Then run the hooks. */ - run_hook (Qkill_buffer_hook); + if (!b->inhibit_buffer_hooks) + run_hook (Qkill_buffer_hook); unbind_to (count, Qnil); } @@ -1928,7 +1936,7 @@ cleaning up all windows currently displaying the buffer to be killed. */) bset_undo_list (b, Qnil); /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) + if (!NILP (Vrun_hooks) && !b->inhibit_buffer_hooks) call1 (Vrun_hooks, Qbuffer_list_update_hook); return Qt; @@ -1970,7 +1978,7 @@ record_buffer (Lisp_Object buffer) fset_buried_buffer_list (f, Fdelq (buffer, f->buried_buffer_list)); /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) + if (!NILP (Vrun_hooks) && !XBUFFER (buffer)->inhibit_buffer_hooks) call1 (Vrun_hooks, Qbuffer_list_update_hook); } @@ -2009,7 +2017,7 @@ DEFUN ("bury-buffer-internal", Fbury_buffer_internal, Sbury_buffer_internal, (f, Fcons (buffer, Fdelq (buffer, f->buried_buffer_list))); /* Run buffer-list-update-hook. */ - if (!NILP (Vrun_hooks)) + if (!NILP (Vrun_hooks) && !XBUFFER (buffer)->inhibit_buffer_hooks) call1 (Vrun_hooks, Qbuffer_list_update_hook); return Qnil; diff --git a/src/buffer.h b/src/buffer.h index d3528ac50e..63b162161c 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -855,6 +855,13 @@ struct buffer /* Non-zero whenever the narrowing is changed in this buffer. */ bool_bf clip_changed : 1; + /* Non-zero for internally used temporary buffers that don't need to + run hooks kill-buffer-hook, buffer-list-update-hook, and + kill-buffer-query-functions. This is used in coding.c to avoid + slowing down en/decoding when there are a lot of these hooks + defined. */ + bool_bf inhibit_buffer_hooks : 1; + /* List of overlays that end at or before the current center, in order of end-position. */ struct Lisp_Overlay *overlays_before; diff --git a/src/coding.c b/src/coding.c index c6d9643677..e351cc72fa 100644 --- a/src/coding.c +++ b/src/coding.c @@ -7785,7 +7785,7 @@ encode_coding (struct coding_system *coding) /* Name (or base name) of work buffer for code conversion. */ -static Lisp_Object Vcode_conversion_workbuf_name; +Lisp_Object Vcode_conversion_workbuf_name; /* A working buffer used by the top level conversion. Once it is created, it is never destroyed. It has the name @@ -7797,7 +7797,6 @@ static Lisp_Object Vcode_conversion_reused_workbuf; /* True iff Vcode_conversion_reused_workbuf is already in use. */ static bool reused_workbuf_in_use; - static void code_conversion_restore (Lisp_Object arg) { @@ -7810,12 +7809,7 @@ code_conversion_restore (Lisp_Object arg) if (EQ (workbuf, Vcode_conversion_reused_workbuf)) reused_workbuf_in_use = 0; else - { - ptrdiff_t count = SPECPDL_INDEX (); - specbind (Qbuffer_list_update_hook, Qnil); - Fkill_buffer (workbuf); - unbind_to (count, Qnil); - } + Fkill_buffer (workbuf); } set_buffer_internal (XBUFFER (current)); } @@ -7827,24 +7821,17 @@ code_conversion_save (bool with_work_buf, bool multibyte) if (with_work_buf) { - ptrdiff_t count = SPECPDL_INDEX (); if (reused_workbuf_in_use) { Lisp_Object name = Fgenerate_new_buffer_name (Vcode_conversion_workbuf_name, Qnil); - specbind (Qbuffer_list_update_hook, Qnil); workbuf = Fget_buffer_create (name); - unbind_to (count, Qnil); } else { if (NILP (Fbuffer_live_p (Vcode_conversion_reused_workbuf))) - { - specbind (Qbuffer_list_update_hook, Qnil); - Vcode_conversion_reused_workbuf - = Fget_buffer_create (Vcode_conversion_workbuf_name); - unbind_to (count, Qnil); - } + Vcode_conversion_reused_workbuf + = Fget_buffer_create (Vcode_conversion_workbuf_name); workbuf = Vcode_conversion_reused_workbuf; } } @@ -7863,11 +7850,6 @@ code_conversion_save (bool with_work_buf, bool multibyte) bset_enable_multibyte_characters (current_buffer, multibyte ? Qt : Qnil); if (EQ (workbuf, Vcode_conversion_reused_workbuf)) reused_workbuf_in_use = 1; - else - { - Fset (Fmake_local_variable (Qkill_buffer_query_functions), Qnil); - Fset (Fmake_local_variable (Qkill_buffer_hook), Qnil); - } set_buffer_internal (current); } diff --git a/src/coding.h b/src/coding.h index e38c0ee396..0c03d1a44e 100644 --- a/src/coding.h +++ b/src/coding.h @@ -97,6 +97,8 @@ enum define_coding_undecided_arg_index extern Lisp_Object Vcoding_system_hash_table; +/* Name (or base name) of work buffer for code conversion. */ +extern Lisp_Object Vcode_conversion_workbuf_name; /* Enumeration of index to an attribute vector of a coding system. */ diff --git a/src/pdumper.c b/src/pdumper.c index 8116c75ae8..a9b3732a2d 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -2761,7 +2761,7 @@ dump_hash_table (struct dump_context *ctx, static dump_off dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer) { -#if CHECK_STRUCTS && !defined HASH_buffer_AE2C8CE357 +#if CHECK_STRUCTS && !defined HASH_buffer_2CEE653E74 # error "buffer changed. See CHECK_STRUCTS comment." #endif struct buffer munged_buffer = *in_buffer; @@ -2873,6 +2873,7 @@ dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer) DUMP_FIELD_COPY (out, buffer, prevent_redisplay_optimizations_p); DUMP_FIELD_COPY (out, buffer, clip_changed); + DUMP_FIELD_COPY (out, buffer, inhibit_buffer_hooks); dump_field_lv_rawptr (ctx, out, buffer, &buffer->overlays_before, Lisp_Vectorlike, WEIGHT_NORMAL);