diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index 579f7880cfe..7fa0804d270 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -422,9 +422,7 @@ portable; curved quotes are less ambiguous and typically look nicer. Electric Quote mode makes it easier to type curved quotes. As you type characters it optionally converts @t{`} to @t{‘}, @t{'} to @t{’}, -@t{``} to @t{“}, and @t{''} to @t{”}. These conversions are -suppressed in buffers whose coding systems cannot represent curved -quote characters. +@t{``} to @t{“}, and @t{''} to @t{”}. @vindex electric-quote-paragraph @vindex electric-quote-comment diff --git a/doc/lispref/debugging.texi b/doc/lispref/debugging.texi index 5ff95827d27..6c0908acccb 100644 --- a/doc/lispref/debugging.texi +++ b/doc/lispref/debugging.texi @@ -152,6 +152,13 @@ presence of @code{condition-case}. (To invoke the debugger, the error must still fulfill the criteria specified by @code{debug-on-error} and @code{debug-ignored-errors}.) +@cindex emacsclient, getting a backtrace +@cindex backtrace from emacsclient's @option{--eval} +For example, setting this variable is useful to get a backtrace from +code evaluated by emacsclient's @option{--eval} option. If Lisp code +evaluated by emacsclient signals an error while this variable is +non-@code{nil}, the backtrace will popup in the running Emacs. + @strong{Warning:} Setting this variable to non-@code{nil} may have annoying effects. Various parts of Emacs catch errors in the normal course of affairs, and you may not even realize that errors happen diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index e7a739f88f3..dc4075dbab4 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -1556,15 +1556,15 @@ keys may not be symbols: @end smallexample @end defun -@defun alist-get key value &optional default remove +@defun alist-get key alist &optional default remove This function is like @code{assq}, but instead of returning the entire -association for @var{key}, @code{(@var{key} . @var{value})}, it -returns just the @var{value}. If @var{key} is not found in -@var{alist} it returns @var{default}. +association for @var{key} in @var{alist}, +@w{@code{(@var{key} . @var{value})}}, it returns just the @var{value}. +If @var{key} is not found in @var{alist}, it returns @var{default}. This is a generalized variable (@pxref{Generalized Variables}) that can be used to change a value with @code{setf}. When using it to set -a value, optional argument @var{remove} non-nil means to remove +a value, optional argument @var{remove} non-@code{nil} means to remove @var{key} from @var{alist} if the new value is @code{eql} to @var{default}. @end defun diff --git a/lisp/electric.el b/lisp/electric.el index 0ec0a1efba1..f35f8b99db3 100644 --- a/lisp/electric.el +++ b/lisp/electric.el @@ -430,12 +430,6 @@ The variable `electric-layout-rules' says when and how to insert newlines." :version "25.1" :type 'boolean :safe 'booleanp :group 'electricity) -(defun electric--insertable-p (string) - (or (not buffer-file-coding-system) - (eq (coding-system-base buffer-file-coding-system) 'undecided) - (not (unencodable-char-position nil nil buffer-file-coding-system - nil string)))) - (defun electric-quote-post-self-insert-function () "Function that `electric-quote-mode' adds to `post-self-insert-hook'. This requotes when a quoting key is typed." @@ -460,8 +454,7 @@ This requotes when a quoting key is typed." (when start (save-excursion (if (eq last-command-event ?\`) - (cond ((and (electric--insertable-p "“") - (search-backward "‘`" (- (point) 2) t)) + (cond ((search-backward "‘`" (- (point) 2) t) (replace-match "“") (when (and electric-pair-mode (eq (cdr-safe @@ -469,16 +462,13 @@ This requotes when a quoting key is typed." (char-after))) (delete-char 1)) (setq last-command-event ?“)) - ((and (electric--insertable-p "‘") - (search-backward "`" (1- (point)) t)) + ((search-backward "`" (1- (point)) t) (replace-match "‘") (setq last-command-event ?‘))) - (cond ((and (electric--insertable-p "”") - (search-backward "’'" (- (point) 2) t)) + (cond ((search-backward "’'" (- (point) 2) t) (replace-match "”") (setq last-command-event ?”)) - ((and (electric--insertable-p "’") - (search-backward "'" (1- (point)) t)) + ((search-backward "'" (1- (point)) t) (replace-match "’") (setq last-command-event ?’))))))))) diff --git a/lisp/help-fns.el b/lisp/help-fns.el index e4e23330e37..87e7d8f87bb 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el @@ -106,23 +106,24 @@ to get buffer-local values.") ;;;###autoload (defun describe-function (function) - "Display the full documentation of FUNCTION (a symbol)." + "Display the full documentation of FUNCTION (a symbol). +When called from lisp, FUNCTION may also be a function object." (interactive - (let ((fn (function-called-at-point)) - (enable-recursive-minibuffers t) - val) - (setq val (completing-read (if fn - (format "Describe function (default %s): " fn) - "Describe function: ") - #'help--symbol-completion-table - #'fboundp - t nil nil (and fn (symbol-name fn)))) - (list (if (equal val "") - fn (intern val))))) - (or (and function (symbolp function)) - (user-error "You didn't specify a function symbol")) - (or (fboundp function) - (user-error "Symbol's function definition is void: %s" function)) + (let* ((fn (function-called-at-point)) + (enable-recursive-minibuffers t) + (val (completing-read + (if fn + (format "Describe function (default %s): " fn) + "Describe function: ") + #'help--symbol-completion-table #'fboundp t nil nil + (and fn (symbol-name fn))))) + (unless (equal val "") + (setq fn (intern val))) + (unless (and fn (symbolp fn)) + (user-error "You didn't specify a function symbol")) + (unless (fboundp fn) + (user-error "Symbol's function definition is void: %s" fn)) + (list fn))) ;; We save describe-function-orig-buffer on the help xref stack, so ;; it is restored by the back/forward buttons. 'help-buffer' diff --git a/lisp/simple.el b/lisp/simple.el index 70bd759edab..d915ee2eb63 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -4957,8 +4957,8 @@ To kill a whole line, when point is not at the beginning, type \ \\[move-beginning-of-line] \\[kill-line] \\[kill-line]. If `show-trailing-whitespace' is non-nil, this command will just -kill the rest of the current line, even if there are only -nonblanks there. +kill the rest of the current line, even if there are no nonblanks +there. If option `kill-whole-line' is non-nil, then this command kills the whole line including its terminating newline, when used at the beginning of a line diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index af875e89907..ac020d09539 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -2393,7 +2393,7 @@ When called interactively with a prefix argument, prompt for REMOTE-LOCATION." "Show the history of the region FROM..TO." (interactive "r") (let* ((lfrom (line-number-at-pos from)) - (lto (line-number-at-pos to)) + (lto (line-number-at-pos (1- to))) (file buffer-file-name) (backend (vc-backend file)) (buf (get-buffer-create "*VC-history*"))) diff --git a/src/dired.c b/src/dired.c index e468147e8b2..c69164b2a1f 100644 --- a/src/dired.c +++ b/src/dired.c @@ -253,9 +253,11 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, QUIT; bool wanted = (NILP (match) - || re_search (bufp, SSDATA (name), len, 0, len, 0) >= 0); + || (re_match_object = name, + re_search (bufp, SSDATA (name), len, 0, len, 0) >= 0)); immediate_quit = 0; + re_match_object = Qnil; /* Stop protecting name from GC. */ if (wanted) { diff --git a/src/regex.c b/src/regex.c index 1917a8480ae..8bc830356d0 100644 --- a/src/regex.c +++ b/src/regex.c @@ -153,6 +153,8 @@ /* Converts the pointer to the char to BEG-based offset from the start. */ # define PTR_TO_OFFSET(d) POS_AS_IN_BUFFER (POINTER_TO_OFFSET (d)) +/* Strings are 0-indexed, buffers are 1-indexed; we pun on the boolean + result to get the right base index. */ # define POS_AS_IN_BUFFER(p) ((p) + (NILP (re_match_object) || BUFFERP (re_match_object))) # define RE_MULTIBYTE_P(bufp) ((bufp)->multibyte) @@ -1363,11 +1365,62 @@ typedef struct #define NEXT_FAILURE_HANDLE(h) fail_stack.stack[(h) - 3].integer #define TOP_FAILURE_HANDLE() fail_stack.frame +#ifdef emacs +# define STR_BASE_PTR(obj) \ + (NILP (obj) ? current_buffer->text->beg \ + : STRINGP (obj) ? SDATA (obj) \ + : NULL) +#else +# define STR_BASE_PTR(obj) NULL +#endif #define ENSURE_FAIL_STACK(space) \ while (REMAINING_AVAIL_SLOTS <= space) { \ + re_char *orig_base = STR_BASE_PTR (re_match_object); \ + bool might_relocate = orig_base != NULL; \ + ptrdiff_t string1_off, end1_off, end_match_1_off; \ + ptrdiff_t string2_off, end2_off, end_match_2_off; \ + ptrdiff_t d_off, dend_off, dfail_off; \ + if (might_relocate) \ + { \ + if (string1) \ + { \ + string1_off = string1 - orig_base; \ + end1_off = end1 - orig_base; \ + end_match_1_off = end_match_1 - orig_base; \ + } \ + if (string2) \ + { \ + string2_off = string2 - orig_base; \ + end2_off = end2 - orig_base; \ + end_match_2_off = end_match_2 - orig_base; \ + } \ + d_off = d - orig_base; \ + dend_off = dend - orig_base; \ + dfail_off = dfail - orig_base; \ + } \ if (!GROW_FAIL_STACK (fail_stack)) \ return -2; \ + /* In Emacs, GROW_FAIL_STACK might relocate string pointers. */ \ + if (might_relocate) \ + { \ + re_char *new_base = STR_BASE_PTR (re_match_object); \ + if (string1) \ + { \ + string1 = new_base + string1_off; \ + end1 = new_base + end1_off; \ + end_match_1 = new_base + end_match_1_off; \ + } \ + if (string2) \ + { \ + string2 = new_base + string2_off; \ + end2 = new_base + end2_off; \ + end_match_2 = new_base + end_match_2_off; \ + } \ + d = new_base + d_off; \ + dend = new_base + dend_off; \ + dfail = new_base + dfail_off; \ + } \ DEBUG_PRINT ("\n Doubled stack; size now: %zd\n", (fail_stack).size);\ DEBUG_PRINT (" slots available: %zd\n", REMAINING_AVAIL_SLOTS);\ } @@ -4293,6 +4346,10 @@ re_search_2 (struct re_pattern_buffer *bufp, const char *str1, size_t size1, /* Loop through the string, looking for a place to start matching. */ for (;;) { + ptrdiff_t offset1, offset2; + re_char *orig_base; + bool might_relocate; + /* If the pattern is anchored, skip quickly past places we cannot match. We don't bother to treat startpos == 0 specially @@ -4409,6 +4466,17 @@ re_search_2 (struct re_pattern_buffer *bufp, const char *str1, size_t size1, && !bufp->can_be_null) return -1; + /* re_match_2_internal may allocate, relocating the Lisp text + object that we're searching. */ + IF_LINT (offset2 = 0); /* Work around GCC bug 78081. */ + orig_base = STR_BASE_PTR (re_match_object); + might_relocate = orig_base != NULL; + if (might_relocate) + { + if (string1) offset1 = string1 - orig_base; + if (string2) offset2 = string2 - orig_base; + } + val = re_match_2_internal (bufp, string1, size1, string2, size2, startpos, regs, stop); @@ -4418,6 +4486,13 @@ re_search_2 (struct re_pattern_buffer *bufp, const char *str1, size_t size1, if (val == -2) return -2; + if (might_relocate) + { + re_char *new_base = STR_BASE_PTR (re_match_object); + if (string1) string1 = offset1 + new_base; + if (string2) string2 = offset2 + new_base; + } + advance: if (!range) break; @@ -4905,8 +4980,8 @@ WEAK_ALIAS (__re_match, re_match) #endif /* not emacs */ #ifdef emacs -/* In Emacs, this is the string or buffer in which we - are matching. It is used for looking up syntax properties. */ +/* In Emacs, this is the string or buffer in which we are matching. + See the declaration in regex.h for details. */ Lisp_Object re_match_object; #endif diff --git a/src/regex.h b/src/regex.h index b672d3fdef7..cb0796fe9cb 100644 --- a/src/regex.h +++ b/src/regex.h @@ -175,8 +175,14 @@ extern reg_syntax_t re_syntax_options; #ifdef emacs # include "lisp.h" -/* In Emacs, this is the string or buffer in which we - are matching. It is used for looking up syntax properties. */ +/* In Emacs, this is the string or buffer in which we are matching. + It is used for looking up syntax properties, and also to recompute + pointers in case the object is relocated as a side effect of + calling malloc (if it calls r_alloc_sbrk in ralloc.c). + + If the value is a Lisp string object, we are matching text in that + string; if it's nil, we are matching text in the current buffer; if + it's t, we are matching text in a C string. */ extern Lisp_Object re_match_object; #endif diff --git a/src/search.c b/src/search.c index 9b8fc584120..bcb5ee95edb 100644 --- a/src/search.c +++ b/src/search.c @@ -280,8 +280,10 @@ looking_at_1 (Lisp_Object string, bool posix) immediate_quit = 1; QUIT; /* Do a pending quit right away, to avoid paradoxical behavior */ - /* Get pointers and sizes of the two strings - that make up the visible portion of the buffer. */ + /* Get pointers and sizes of the two strings that make up the + visible portion of the buffer. Note that we can use pointers + here, unlike in search_buffer, because we only call re_match_2 + once, after which we never use the pointers again. */ p1 = BEGV_ADDR; s1 = GPT_BYTE - BEGV_BYTE; @@ -400,6 +402,7 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start, (NILP (Vinhibit_changing_match_data) ? &search_regs : NULL)); immediate_quit = 0; + re_match_object = Qnil; /* Stop protecting string from GC. */ /* Set last_thing_searched only when match data is changed. */ if (NILP (Vinhibit_changing_match_data)) @@ -470,6 +473,7 @@ fast_string_match_internal (Lisp_Object regexp, Lisp_Object string, SBYTES (string), 0, SBYTES (string), 0); immediate_quit = 0; + re_match_object = Qnil; /* Stop protecting string from GC. */ return val; } @@ -557,6 +561,7 @@ fast_looking_at (Lisp_Object regexp, ptrdiff_t pos, ptrdiff_t pos_byte, len = re_match_2 (buf, (char *) p1, s1, (char *) p2, s2, pos_byte, NULL, limit_byte); immediate_quit = 0; + re_match_object = Qnil; /* Stop protecting string from GC. */ return len; } @@ -1171,8 +1176,8 @@ search_buffer (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, if (RE && !(trivial_regexp_p (string) && NILP (Vsearch_spaces_regexp))) { - unsigned char *p1, *p2; - ptrdiff_t s1, s2; + unsigned char *base; + ptrdiff_t off1, off2, s1, s2; struct re_pattern_buffer *bufp; bufp = compile_pattern (string, @@ -1186,16 +1191,19 @@ search_buffer (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, can take too long. */ QUIT; /* Do a pending quit right away, to avoid paradoxical behavior */ - /* Get pointers and sizes of the two strings - that make up the visible portion of the buffer. */ + /* Get offsets and sizes of the two strings that make up the + visible portion of the buffer. We compute offsets instead of + pointers because re_search_2 may call malloc and therefore + change the buffer text address. */ - p1 = BEGV_ADDR; + base = current_buffer->text->beg; + off1 = BEGV_ADDR - base; s1 = GPT_BYTE - BEGV_BYTE; - p2 = GAP_END_ADDR; + off2 = GAP_END_ADDR - base; s2 = ZV_BYTE - GPT_BYTE; if (s1 < 0) { - p2 = p1; + off2 = off1; s2 = ZV_BYTE - BEGV_BYTE; s1 = 0; } @@ -1210,7 +1218,9 @@ search_buffer (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, { ptrdiff_t val; - val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2, + val = re_search_2 (bufp, + (char*) (base + off1), s1, + (char*) (base + off2), s2, pos_byte - BEGV_BYTE, lim_byte - pos_byte, (NILP (Vinhibit_changing_match_data) ? &search_regs : &search_regs_1), @@ -1255,8 +1265,10 @@ search_buffer (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, { ptrdiff_t val; - val = re_search_2 (bufp, (char *) p1, s1, (char *) p2, s2, - pos_byte - BEGV_BYTE, lim_byte - pos_byte, + val = re_search_2 (bufp, + (char*) (base + off1), s1, + (char*) (base + off2), s2, + pos_byte - BEGV_BYTE, lim_byte - pos_byte, (NILP (Vinhibit_changing_match_data) ? &search_regs : &search_regs_1), lim_byte - BEGV_BYTE); diff --git a/src/w32heap.c b/src/w32heap.c index 658a8a5d691..443472b4708 100644 --- a/src/w32heap.c +++ b/src/w32heap.c @@ -129,18 +129,18 @@ static DWORD_PTR committed = 0; /* The maximum block size that can be handled by a non-growable w32 heap is limited by the MaxBlockSize value below. - This point deserves and explanation. + This point deserves an explanation. - The W32 heap allocator can be used for a growable - heap or a non-growable one. + The W32 heap allocator can be used for a growable heap or a + non-growable one. A growable heap is not compatible with a fixed base address for the heap. Only a non-growable one is. One drawback of non-growable heaps is that they can hold only objects smaller than a certain - size (the one defined below). Most of the largest blocks are GC'ed - before dumping. In any case and to be safe, we implement a simple + size (the one defined below). Most of the larger blocks are GC'ed + before dumping. In any case, and to be safe, we implement a simple first-fit allocation algorithm starting at the end of the - dumped_data[] array like depicted below: + dumped_data[] array as depicted below: ---------------------------------------------- | | | | @@ -273,7 +273,7 @@ init_heap (void) else { /* Find the RtlCreateHeap function. Headers for this function - are provided with the w32 ddk, but the function is available + are provided with the w32 DDK, but the function is available in ntdll.dll since XP. */ HMODULE hm_ntdll = LoadLibrary ("ntdll.dll"); RtlCreateHeap_Proc s_pfn_Rtl_Create_Heap