commit a461baae79af3cea8780e9d9a845a1e859e96e5e (HEAD, refs/remotes/origin/master) Merge: d00df0aaf9 cf223dc928 Author: Paul Eggert Date: Sun Mar 8 16:57:41 2020 -0700 Merge from origin/emacs-27 cf223dc928 ; * src/timefns.c: Fix typo in previous change. 20d3d3a950 * src/timefns.c: Add comments. commit cf223dc928119bb544c3370ad59fe3e175a8236e (refs/remotes/origin/emacs-27) Author: Paul Eggert Date: Sun Mar 8 16:49:32 2020 -0700 ; * src/timefns.c: Fix typo in previous change. diff --git a/src/timefns.c b/src/timefns.c index 4079358fc5..553daf6e6a 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -616,7 +616,7 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) (N * FLT_RADIX**SCALE) / D [or, if SCALE is negative, N / (D * FLT_RADIX**-SCALE)] as a bignum, convert the bignum to double, then divide the double by FLT_RADIX**SCALE. First scale N - N (or scale D, if SCALE is negative) ... */ + (or scale D, if SCALE is negative) ... */ ptrdiff_t scale = ddig - ndig + DBL_MANT_DIG + 1; if (scale < 0) { commit 20d3d3a9509ed24b4fb701919bf4a677c7d9e249 Author: Paul Eggert Date: Sun Mar 8 16:43:54 2020 -0700 * src/timefns.c: Add comments. diff --git a/src/timefns.c b/src/timefns.c index 8e2bb214ed..4079358fc5 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -421,6 +421,9 @@ decode_float_time (double t, struct lisp_time *result) else if (flt_radix_power_size <= scale) return isnan (t) ? EDOM : EOVERFLOW; + /* Compute TICKS, HZ such that TICKS / HZ exactly equals T, where HZ is + T's frequency or 1, whichever is greater. Here, “frequency” means + 1/precision. Cache HZ values in flt_radix_power. */ double scaled = scalbn (t, scale); eassert (trunc (scaled) == scaled); ticks = double_to_integer (scaled); @@ -442,6 +445,7 @@ decode_float_time (double t, struct lisp_time *result) static Lisp_Object ticks_hz_list4 (Lisp_Object ticks, Lisp_Object hz) { + /* mpz[0] = floor ((ticks * trillion) / hz). */ mpz_t const *zticks = bignum_integer (&mpz[0], ticks); #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX mpz_mul_ui (mpz[0], *zticks, TRILLION); @@ -449,6 +453,9 @@ ticks_hz_list4 (Lisp_Object ticks, Lisp_Object hz) mpz_mul (mpz[0], *zticks, ztrillion); #endif mpz_fdiv_q (mpz[0], mpz[0], *bignum_integer (&mpz[1], hz)); + + /* mpz[0] = floor (mpz[0] / trillion), with US = the high six digits of the + 12-digit remainder, and PS = the low six digits. */ #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX unsigned long int fullps = mpz_fdiv_q_ui (mpz[0], mpz[0], TRILLION); int us = fullps / 1000000; @@ -458,11 +465,14 @@ ticks_hz_list4 (Lisp_Object ticks, Lisp_Object hz) int ps = mpz_fdiv_q_ui (mpz[1], mpz[1], 1000000); int us = mpz_get_ui (mpz[1]); #endif + + /* mpz[0] = floor (mpz[0] / 1 << LO_TIME_BITS), with lo = remainder. */ unsigned long ulo = mpz_get_ui (mpz[0]); if (mpz_sgn (mpz[0]) < 0) ulo = -ulo; int lo = ulo & ((1 << LO_TIME_BITS) - 1); mpz_fdiv_q_2exp (mpz[0], mpz[0], LO_TIME_BITS); + return list4 (make_integer_mpz (), make_fixnum (lo), make_fixnum (us), make_fixnum (ps)); } @@ -482,6 +492,7 @@ mpz_set_time (mpz_t rop, time_t t) static void timespec_mpz (struct timespec t) { + /* mpz[0] = sec * TIMESPEC_HZ + nsec. */ mpz_set_ui (mpz[0], t.tv_nsec); mpz_set_time (mpz[1], t.tv_sec); mpz_addmul_ui (mpz[0], mpz[1], TIMESPEC_HZ); @@ -508,7 +519,9 @@ timespec_ticks (struct timespec t) static Lisp_Object lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) { - /* For speed, just return TICKS if T is (TICKS . HZ). */ + /* The idea is to return the floor of ((T.ticks * HZ) / T.hz). */ + + /* For speed, just return T.ticks if T.hz == HZ. */ if (FASTER_TIMEFNS && EQ (t.hz, hz)) return t.ticks; @@ -540,6 +553,8 @@ lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) static Lisp_Object lisp_time_seconds (struct lisp_time t) { + /* The idea is to return the floor of T.ticks / T.hz. */ + if (!FASTER_TIMEFNS) return lisp_time_hz_ticks (t, make_fixnum (1)); @@ -587,6 +602,7 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) && integer_to_intmax (numerator, &intmax_numerator)) return intmax_numerator; + /* Compute number of base-FLT_RADIX digits in numerator and denominator. */ mpz_t const *n = bignum_integer (&mpz[0], numerator); mpz_t const *d = bignum_integer (&mpz[1], denominator); ptrdiff_t nbits = mpz_sizeinbase (*n, 2); @@ -599,7 +615,8 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) /* Scale with SCALE when doing integer division. That is, compute (N * FLT_RADIX**SCALE) / D [or, if SCALE is negative, N / (D * FLT_RADIX**-SCALE)] as a bignum, convert the bignum to double, - then divide the double by FLT_RADIX**SCALE. */ + then divide the double by FLT_RADIX**SCALE. First scale N + N (or scale D, if SCALE is negative) ... */ ptrdiff_t scale = ddig - ndig + DBL_MANT_DIG + 1; if (scale < 0) { @@ -614,12 +631,12 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) mpz_mul_2exp (mpz[0], *n, scale * LOG2_FLT_RADIX); n = &mpz[0]; } - + /* ... and then divide, with quotient Q and remainder R. */ mpz_t *q = &mpz[2]; mpz_t *r = &mpz[3]; mpz_tdiv_qr (*q, *r, *n, *d); - /* The amount to add to the absolute value of *Q so that truncating + /* The amount to add to the absolute value of Q so that truncating it to double will round correctly. */ int incr; @@ -658,6 +675,7 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) if (!FASTER_TIMEFNS || incr != 0) (mpz_sgn (*n) < 0 ? mpz_sub_ui : mpz_add_ui) (*q, *q, incr); + /* Rescale the integer Q back to double. This step does not round. */ return scalbn (mpz_get_d (*q), -scale); } @@ -902,6 +920,10 @@ lisp_to_timespec (struct lisp_time t) mpz_t *q = &mpz[0]; mpz_t const *qt = q; + /* Floor-divide (T.ticks * TIMESPEC_HZ) by T.hz, + yielding quotient Q (tv_sec) and remainder NS (tv_nsec). + Return an invalid timespec if Q does not fit in time_t. + For speed, prefer fixnum arithmetic if it works. */ if (FASTER_TIMEFNS && EQ (t.hz, timespec_hz)) { if (FIXNUMP (t.ticks)) @@ -945,8 +967,8 @@ lisp_to_timespec (struct lisp_time t) ns = mpz_fdiv_q_ui (*q, *q, TIMESPEC_HZ); } - /* With some versions of MinGW, tv_sec is a 64-bit type, whereas - time_t is a 32-bit type. */ + /* Check that Q fits in time_t, not merely in T.tv_sec. With some versions + of MinGW, tv_sec is a 64-bit type, whereas time_t is a 32-bit type. */ time_t sec; if (mpz_time (*qt, &sec)) { @@ -1026,10 +1048,14 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool subtract) { if (EQ (b, make_fixnum (0))) return a; + + /* For speed, use EMACS_INT arithmetic if it will do. */ if (FIXNUMP (a)) return make_int (subtract ? XFIXNUM (a) - XFIXNUM (b) : XFIXNUM (a) + XFIXNUM (b)); + + /* For speed, use mpz_add_ui/mpz_sub_ui if it will do. */ if (eabs (XFIXNUM (b)) <= ULONG_MAX) { ((XFIXNUM (b) < 0) == subtract ? mpz_add_ui : mpz_sub_ui) @@ -1038,6 +1064,7 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool subtract) } } + /* Fall back on bignum arithmetic if necessary. */ if (!mpz_done) (subtract ? mpz_sub : mpz_add) (mpz[0], *bignum_integer (&mpz[0], a), @@ -1221,6 +1248,8 @@ time_cmp (Lisp_Object a, Lisp_Object b) if (EQ (a, b)) return 0; + /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing + ATICKS * BHZ to BTICKS * AHZ. */ struct lisp_time tb = lisp_time_struct (b, 0); mpz_t const *za = bignum_integer (&mpz[0], ta.ticks); mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks); @@ -1498,6 +1527,7 @@ SEC is always an integer between 0 and 59.) usage: (decode-time &optional TIME ZONE FORM) */) (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form) { + /* Compute broken-down local time LOCAL_TM from SPECIFIED_TIME and ZONE. */ struct lisp_time lt = lisp_time_struct (specified_time, 0); struct timespec ts = lisp_to_timespec (lt); if (! timespec_valid_p (ts)) @@ -1512,6 +1542,7 @@ usage: (decode-time &optional TIME ZONE FORM) */) if (!tm) time_error (localtime_errno); + /* Let YEAR = LOCAL_TM.tm_year + TM_YEAR_BASE. */ Lisp_Object year; if (FASTER_TIMEFNS && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year @@ -1528,12 +1559,15 @@ usage: (decode-time &optional TIME ZONE FORM) */) year = make_integer_mpz (); } + /* Compute SEC from LOCAL_TM.tm_sec and HZ. */ Lisp_Object hz = lt.hz, sec; if (EQ (hz, make_fixnum (1)) || !EQ (form, Qt)) sec = make_fixnum (local_tm.tm_sec); else { - Lisp_Object ticks; /* hz * tm_sec + mod (lt.ticks, hz) */ + /* Let TICKS = HZ * LOCAL_TM.tm_sec + mod (LT.ticks, HZ) + and SEC = (TICKS . HZ). */ + Lisp_Object ticks; intmax_t n; if (FASTER_TIMEFNS && FIXNUMP (lt.ticks) && FIXNUMP (hz) && !INT_MULTIPLY_WRAPV (XFIXNUM (hz), local_tm.tm_sec, &n) @@ -1663,6 +1697,7 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) yeararg = args[5]; } + /* Let SEC = floor (LT.ticks / HZ), with SUBSECTICKS the remainder. */ struct lisp_time lt; decode_lisp_time (secarg, 0, <, 0); Lisp_Object hz = lt.hz, sec, subsecticks; commit d00df0aaf9105128d80f6e395974474cf5975499 Author: Daniel Gröber Date: Sun Mar 8 14:04:13 2020 -0400 * lisp/term/rxvt.el: Enable backeted paste and window title rxvt-unicode uses the same escape sequences as xterm so just re-use the xterm functions to enable them. The `xterm-rxvt-function-map` keymap already has (define-key map "\e[200~" [xterm-paste]) so we're already handling the paste sequence and only need to enable it. Tested on rxvt-unicode version 9.22. (rxvt-set-window-title): New var. (terminal-init-rxvt): Use it; enable bracketed paste mode; run terminal-init-rxvt-hook. diff --git a/lisp/term/rxvt.el b/lisp/term/rxvt.el index ca6c468f52..31e3d6ede4 100644 --- a/lisp/term/rxvt.el +++ b/lisp/term/rxvt.el @@ -26,6 +26,16 @@ (require 'term/xterm) +(defgroup rxvt nil + "(U)RXVT support." + :version "28.1" + :group 'terminals) + +(defcustom rxvt-set-window-title nil + "Whether Emacs should set window titles to an Emacs frame in RXVT." + :version "28.1" + :type 'boolean) + (defvar rxvt-function-map (let ((map (make-sparse-keymap))) (set-keymap-parent map xterm-rxvt-function-map) @@ -171,7 +181,16 @@ (xterm-register-default-colors rxvt-standard-colors) (rxvt-set-background-mode) ;; This recomputes all the default faces given the colors we've just set up. - (tty-set-up-initial-frame-faces)) + (tty-set-up-initial-frame-faces) + + ;; Unconditionally enable bracketed paste mode: terminals that don't + ;; support it just ignore the sequence. + (xterm--init-bracketed-paste-mode) + + (when rxvt-set-window-title + (xterm--init-frame-title)) + + (run-hooks 'terminal-init-rxvt-hook)) ;; rxvt puts the default colors into an environment variable ;; COLORFGBG. We use this to set the background mode in a more commit 35a13fca32c3371ca25d87f7447b4bd4f65de710 Author: Alan Mackenzie Date: Sun Mar 8 16:21:15 2020 +0000 CC Mode: allow specified directives (e.g. pragma) to be indented as statements * lisp/progmodes/cc-cmds.el (c-align-cpp-indent-to-body) (c-cpp-indent-to-body-flag, c-electric-pragma) (c-add-indent-to-body-to-abbrev-table, c-clear-stale-indent-to-body-abbrevs) (c-toggle-cpp-indent-to-body): New functions and variables. * lisp/progmodes/cc-langs.el (c-std-abbrev-keywords): New lang const/var. * lisp/progmodes/cc-mode.el (c-populate-abbrev-table): New function. (c-basic-common-init): call the c-populate-abbrev-table. (c-mode, c++-mode, objc-mode, java-mode, idl-mode, pike-mode, awk-mode): Remove the setting of MODE-abbrev-table. * lisp/progmodes/cc-vars.el (c-cpp-indent-to-body-directives): New defcustom. * doc/misc/cc-mode.texi (Custom Macros): Introduce and refer to .... (Indenting Directives): New page documenting the new mechanism. diff --git a/doc/misc/cc-mode.texi b/doc/misc/cc-mode.texi index 544ff85335..f99a890670 100644 --- a/doc/misc/cc-mode.texi +++ b/doc/misc/cc-mode.texi @@ -350,11 +350,12 @@ Line-Up Functions * Misc Line-Up:: -Customizing Macros +Custom Macros * Macro Backslashes:: * Macros with ;:: * Noise Macros:: +* Indenting Directives:: @end detailmenu @end menu @@ -6949,6 +6950,10 @@ is @code{nil}, all lines inside macro definitions are analyzed as @code{cpp-macro-cont}. @end defopt +Sometimes you may want to indent particular directives +(e.g. @code{#pragma}) as though they were statements. To do this, see +@ref{Indenting Directives}. + Because a macro can expand into anything at all, near where one is invoked @ccmode{} can only indent and fontify code heuristically. Sometimes it gets it wrong. Usually you should try to design your @@ -6965,6 +6970,7 @@ Macros}. * Macro Backslashes:: * Macros with ;:: * Noise Macros:: +* Indenting Directives:: @end menu @comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -7074,7 +7080,7 @@ initialization code, after the mode hooks have run. @end defun @comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -@node Noise Macros, , Macros with ;, Custom Macros +@node Noise Macros, Indenting Directives, Macros with ;, Custom Macros @comment node-name, next, previous, up @section Noise Macros @cindex noise macros @@ -7130,6 +7136,48 @@ has run. This function is called by @ccmode{}'s initialization code, after the mode hooks have run. @end defun +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@node Indenting Directives, , Noise Macros, Custom Macros +@comment node-name, next, previous, up +@section Indenting Directives +@cindex Indenting Directives +@cindex Indenting #pragma +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +Sometimes you may want to indent particular preprocessor directives +(e.g. @code{#pragma}) as though they were statements. To do this, +first set up @code{c-cpp-indent-to-body-directives} to include the +directive name(s), then enable the ``indent to body'' feature with +@code{c-toggle-cpp-indent-to-body}. + +@defopt c-cpp-indent-to-body-directives +@vindex cpp-indent-to-body-directives (c-) +This variable is a list of names of CPP directives (not including the +introducing @samp{#}) which will be indented as though statements. +Each element is a string, and must be a valid identifier. The default +value is @code{("pragma")}. + +If you add more directives to this variable, or remove directives from +it, whilst ``indent to body'' is active, you need to re-enable the +feature by calling @code{c-toggle-cpp-indent-to-body} for these +changes to take effect@footnote{Note that the removal of directives +doesn't work satisfactorally on XEmacs or on very old versions of +Emacs}. +@end defopt + +@defun c-toggle-cpp-indent-to-body +@findex toggle-cpp-indent-to-body (c-) +With @kbd{M-x c-toggle-cpp-indent-to-body}, you enable or disable the +``indent to body'' feature. When called programmatically, it takes an +optional numerical argument. A positive value will enable the +feature, a zero or negative value will disable it. + +You should set up @code{c-cpp-indent-to-body-directives} before +calling this function, since the function sets internal state which +depends on that variable. +@end defun + + @comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @node Odds and Ends, Sample Init File, Custom Macros, Top @comment node-name, next, previous, up diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index a60812230b..1b557c41a5 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -48,6 +48,7 @@ (cc-bytecomp-defvar filladapt-mode) ; c-fill-paragraph contains a kludge ; which looks at this. (cc-bytecomp-defun electric-pair-post-self-insert-function) +(cc-bytecomp-defvar c-indent-to-body-directives) ;; Indentation / Display syntax functions (defvar c-fix-backslashes t) @@ -1441,6 +1442,98 @@ keyword on the line, the keyword is not inserted inside a literal, and (indent-according-to-mode) (delete-char -2))))) +(defun c-align-cpp-indent-to-body () + "Align a \"#pragma\" line under the previous line. +This function is intented for use as a member of `c-special-indent-hook'." + (when (assq 'cpp-macro c-syntactic-context) + (when + (save-excursion + (save-match-data + (back-to-indentation) + (and + (looking-at (concat c-opt-cpp-symbol "[ \t]*\\([a-zA-Z0-9_]+\\)")) + (member (match-string-no-properties 1) + c-cpp-indent-to-body-directives)))) + (c-indent-line (delete '(cpp-macro) c-syntactic-context))))) + +(defvar c-cpp-indent-to-body-flag nil) +;; Non-nil when CPP directives such as "#pragma" should be indented to under +;; the preceding statement. +(make-variable-buffer-local 'c-cpp-indent-to-body-flag) + +(defun c-electric-pragma () + "Reindent the current line if appropriate. + +This function is used to reindent a preprocessor line when the +symbol for the directive, typically \"pragma\", triggers this +function as a hook function of an abbreviation. + +The \"#\" of the preprocessor construct is aligned under the +first anchor point of the line's syntactic context. + +The line is reindented if the construct is not in a string or +comment, there is exactly one \"#\" contained in optional +whitespace before it on the current line, and `c-electric-flag' +and `c-syntactic-indentation' are both non-nil." + (save-excursion + (save-match-data + (when + (and + c-cpp-indent-to-body-flag + c-electric-flag + c-syntactic-indentation + last-abbrev-location + c-opt-cpp-symbol ; "#" or nil. + (progn (back-to-indentation) + (looking-at (concat c-opt-cpp-symbol "[ \t]*"))) + (>= (match-end 0) last-abbrev-location) + (not (c-literal-limits))) + (c-indent-line (delete '(cpp-macro) (c-guess-basic-syntax))))))) + +(defun c-add-indent-to-body-to-abbrev-table (d) + ;; Create an abbreviation table entry for the directive D, and add it to the + ;; current abbreviation table. Existing abbreviation (e.g. for "else") do + ;; not get overwritten. + (when (and c-buffer-is-cc-mode + local-abbrev-table + (not (abbrev-symbol d local-abbrev-table))) + (condition-case nil + (define-abbrev local-abbrev-table d d 'c-electric-pragma 0 t) + (wrong-number-of-arguments + (define-abbrev local-abbrev-table d d 'c-electric-pragma))))) + +(defun c-clear-stale-indent-to-body-abbrevs () + ;; Fill in this comment. FIXME!!! + (when (fboundp 'abbrev-get) + (mapatoms (lambda (a) + (when (and (abbrev-get a ':system) ; Preserve a user's abbrev! + (not (member (symbol-name a) c-std-abbrev-keywords)) + (not (member (symbol-name a) + c-cpp-indent-to-body-directives))) + (unintern a local-abbrev-table))) + local-abbrev-table))) + +(defun c-toggle-cpp-indent-to-body (&optional arg) + "Toggle the C preprocessor indent-to-body feature. +When enabled, preprocessor directives which are words in +`c-indent-to-body-directives' are indented as if they were statements. + +Optional numeric ARG, if supplied, turns on the feature when positive, +turns it off when negative, and just toggles it when zero or +left out." + (interactive "P") + (setq c-cpp-indent-to-body-flag + (c-calculate-state arg c-cpp-indent-to-body-flag)) + (if c-cpp-indent-to-body-flag + (progn + (c-clear-stale-indent-to-body-abbrevs) + (mapc 'c-add-indent-to-body-to-abbrev-table + c-cpp-indent-to-body-directives) + (add-hook 'c-special-indent-hook 'c-align-cpp-indent-to-body nil t)) + (remove-hook 'c-special-indent-hook 'c-align-cpp-indent-to-body t)) + (message "c-cpp-indent-to-body %sabled" + (if c-cpp-indent-to-body-flag "en" "dis"))) + (declare-function subword-forward "subword" (&optional arg)) diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index e7e7cfd4b0..1e72352f71 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -3030,7 +3030,14 @@ Note that Java specific rules are currently applied to tell this from ;; can start a declaration.) "entity" "process" "service" "session" "storage")) - +(c-lang-defconst c-std-abbrev-keywords + "List of keywords which may need to cause electric indentation." + t '("else" "while") + c++ (append (c-lang-const c-std-abbrev-keywords) '("catch")) + java (append (c-lang-const c-std-abbrev-keywords) '("catch" "finally")) + idl nil) +(c-lang-defvar c-std-abbrev-keywords (c-lang-const c-std-abbrev-keywords)) + ;;; Constants built from keywords. ;; Note: No `*-kwds' language constants may be defined below this point. diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index a39c50e413..f92d3efdeb 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -278,6 +278,29 @@ control). See \"cc-mode.el\" for more info." (setq defs (cdr defs))))) (put 'c-define-abbrev-table 'lisp-indent-function 1) +(defun c-populate-abbrev-table () + ;; Insert the standard keywords which may need electric indentation into the + ;; current mode's abbreviation table. + (let ((table (intern (concat (symbol-name major-mode) "-abbrev-table"))) + (defs c-std-abbrev-keywords) + ) + (unless (and (boundp table) + (abbrev-table-p (symbol-value table))) + (define-abbrev-table table nil)) + (setq local-abbrev-table (symbol-value table)) + (while defs + (unless (intern-soft (car defs) local-abbrev-table) ; Don't overwrite the + ; abbrev's use count. + (condition-case nil + (define-abbrev (symbol-value table) + (car defs) (car defs) + 'c-electric-continued-statement 0 t) + (wrong-number-of-arguments + (define-abbrev (symbol-value table) + (car defs) (car defs) + 'c-electric-continued-statement 0)))) + (setq defs (cdr defs))))) + (defun c-bind-special-erase-keys () ;; Only used in Emacs to bind C-c C- and C-c C- ;; to the proper keys depending on `normal-erase-is-backspace'. @@ -550,6 +573,8 @@ that requires a literal mode spec at compile time." (setq c-buffer-is-cc-mode mode) + (c-populate-abbrev-table) + ;; these variables should always be buffer local; they do not affect ;; indentation style. (make-local-variable 'comment-start) @@ -2444,11 +2469,6 @@ opening \" and the next unescaped end of line." (funcall (c-lang-const c-make-mode-syntax-table c)) "Syntax table used in c-mode buffers.") -(c-define-abbrev-table 'c-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0) - ("while" "while" c-electric-continued-statement 0)) - "Abbreviation table used in c-mode buffers.") - (defvar c-mode-map (let ((map (c-make-inherited-keymap))) map) @@ -2560,12 +2580,6 @@ the code is C or C++ and based on that chooses whether to enable (funcall (c-lang-const c-make-mode-syntax-table c++)) "Syntax table used in c++-mode buffers.") -(c-define-abbrev-table 'c++-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0) - ("while" "while" c-electric-continued-statement 0) - ("catch" "catch" c-electric-continued-statement 0)) - "Abbreviation table used in c++-mode buffers.") - (defvar c++-mode-map (let ((map (c-make-inherited-keymap))) map) @@ -2614,11 +2628,6 @@ Key bindings: (funcall (c-lang-const c-make-mode-syntax-table objc)) "Syntax table used in objc-mode buffers.") -(c-define-abbrev-table 'objc-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0) - ("while" "while" c-electric-continued-statement 0)) - "Abbreviation table used in objc-mode buffers.") - (defvar objc-mode-map (let ((map (c-make-inherited-keymap))) map) @@ -2665,13 +2674,6 @@ Key bindings: (funcall (c-lang-const c-make-mode-syntax-table java)) "Syntax table used in java-mode buffers.") -(c-define-abbrev-table 'java-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0) - ("while" "while" c-electric-continued-statement 0) - ("catch" "catch" c-electric-continued-statement 0) - ("finally" "finally" c-electric-continued-statement 0)) - "Abbreviation table used in java-mode buffers.") - (defvar java-mode-map (let ((map (c-make-inherited-keymap))) map) @@ -2722,9 +2724,6 @@ Key bindings: (funcall (c-lang-const c-make-mode-syntax-table idl)) "Syntax table used in idl-mode buffers.") -(c-define-abbrev-table 'idl-mode-abbrev-table nil - "Abbreviation table used in idl-mode buffers.") - (defvar idl-mode-map (let ((map (c-make-inherited-keymap))) map) @@ -2767,11 +2766,6 @@ Key bindings: (funcall (c-lang-const c-make-mode-syntax-table pike)) "Syntax table used in pike-mode buffers.") -(c-define-abbrev-table 'pike-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0) - ("while" "while" c-electric-continued-statement 0)) - "Abbreviation table used in pike-mode buffers.") - (defvar pike-mode-map (let ((map (c-make-inherited-keymap))) map) @@ -2819,11 +2813,6 @@ Key bindings: ;;;###autoload (add-to-list 'interpreter-mode-alist '("nawk" . awk-mode)) ;;;###autoload (add-to-list 'interpreter-mode-alist '("gawk" . awk-mode)) -(c-define-abbrev-table 'awk-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0) - ("while" "while" c-electric-continued-statement 0)) - "Abbreviation table used in awk-mode buffers.") - (defvar awk-mode-map (let ((map (c-make-inherited-keymap))) map) diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el index 556ff6059f..3995b21185 100644 --- a/lisp/progmodes/cc-vars.el +++ b/lisp/progmodes/cc-vars.el @@ -1649,6 +1649,15 @@ white space either before or after the operator, but not both." :type 'boolean :group 'c) +(defcustom c-cpp-indent-to-body-directives '("pragma") + "Preprocessor directives which will be indented as statements. + +A list of Preprocessor directives which when reindented, or newly +typed in, will cause the \"#\" introducing the directive to be +indented as a statement." + :type '(repeat string) + :group 'c) + ;; Initialize the next two to a regexp which never matches. (defvar c-noise-macro-with-parens-name-re regexp-unmatchable) (make-variable-buffer-local 'c-noise-macro-with-parens-name-re) commit 66bc47d12aba72ff738a9f5575e0b93eefc641ba Author: Eli Zaretskii Date: Sun Mar 8 17:00:10 2020 +0200 Fix the MinGW build as followup to recent "nofollow" changes * src/w32.c (fdutimens): Call utimensat instead of utime. (set_file_times): Function deleted. (convert_from_timespec): Renamed from convert_from_time_t and modified to accept 'struct timespec' argument instead of 'time_t'. (utimensat): Renamed from utime and modified to accept 'struct timespec [2]' argument and an additional argument FLAG. Emulate Posix 'utimensat'. Call 'convert_from_timespec'. (w32_copy_file): Call 'utimensat' instead of 'set_file_times'. * src/fileio.c (Fcopy_file) [WINDOWSNT]: Make the error message be identical to that on Posix platforms. * nt/inc/sys/stat.h (utimensat): Provide prototype. * nt/mingw-cfg.site (ac_cv_func_futimens) (gl_cv_func_futimens_works, ac_cv_func_utimensat) (gl_cv_func_utimensat_works): Override Gnulib tests. * nt/gnulib-cfg.mk (OMIT_GNULIB_MODULE_futimens) (OMIT_GNULIB_MODULE_utimensat): Disable these Gnulib modules. diff --git a/nt/gnulib-cfg.mk b/nt/gnulib-cfg.mk index 1d120a973d..e3b945720d 100644 --- a/nt/gnulib-cfg.mk +++ b/nt/gnulib-cfg.mk @@ -65,3 +65,5 @@ OMIT_GNULIB_MODULE_unistd = true OMIT_GNULIB_MODULE_canonicalize-lgpl = true OMIT_GNULIB_MODULE_fchmodat = true OMIT_GNULIB_MODULE_lchmod = true +OMIT_GNULIB_MODULE_futimens = true +OMIT_GNULIB_MODULE_utimensat = true diff --git a/nt/inc/sys/stat.h b/nt/inc/sys/stat.h index 7bf780dbaa..f58d5ab657 100644 --- a/nt/inc/sys/stat.h +++ b/nt/inc/sys/stat.h @@ -164,4 +164,9 @@ int __cdecl __MINGW_NOTHROW fstatat (int, char const *, struct stat *, int); int __cdecl __MINGW_NOTHROW chmod (const char*, int); +/* Provide prototypes of library functions that are emulated on w32 + and whose prototypes are usually found in sys/stat.h on POSIX + platforms. */ +extern int utimensat (int, const char *, struct timespec const[2], int); + #endif /* INC_SYS_STAT_H_ */ diff --git a/nt/mingw-cfg.site b/nt/mingw-cfg.site index 5bd5b83463..2271eef98d 100644 --- a/nt/mingw-cfg.site +++ b/nt/mingw-cfg.site @@ -105,6 +105,10 @@ gl_cv_func_fstatat_zero_flag=yes ac_cv_func_fchmodat=yes gl_cv_func_fchmodat_works="not-needed-so-yes" ac_cv_func_lchmod=yes +ac_cv_func_futimens=not-needed +gl_cv_func_futimens_works="not-needed-so-yes" +ac_cv_func_utimensat=yes +gl_cv_func_utimensat_works=yes # Aliased to _commit in ms-w32.h ac_cv_func_fsync=yes ac_cv_func_fdatasync=yes diff --git a/src/fileio.c b/src/fileio.c index 82fd798920..ffe79559a3 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -2077,7 +2077,7 @@ permissions. */) report_file_error ("Copying permissions from", file); case -3: xsignal2 (Qfile_date_error, - build_string ("Resetting file times"), newname); + build_string ("Cannot set file date"), newname); case -4: report_file_error ("Copying permissions to", newname); } diff --git a/src/w32.c b/src/w32.c index 40f286ad6c..698e10e234 100644 --- a/src/w32.c +++ b/src/w32.c @@ -3178,33 +3178,9 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2]) return _futime (fd, &_ut); } else - { - struct utimbuf ut; - - ut.actime = timespec[0].tv_sec; - ut.modtime = timespec[1].tv_sec; - /* Call 'utime', which is implemented below, not the MS library - function, which fails on directories. */ - return utime (file, &ut); - } + return utimensat (fd, file, timespec, 0); } -/* Set the access and modification time stamps of FD (a.k.a. FILE) to be - ATIME and MTIME, respectively. - FD must be either negative -- in which case it is ignored -- - or a file descriptor that is open on FILE. - If FD is nonnegative, then FILE can be NULL. */ -static int -set_file_times (int fd, const char *filename, - struct timespec atime, struct timespec mtime) -{ - struct timespec timespec[2]; - timespec[0] = atime; - timespec[1] = mtime; - return fdutimens (fd, filename, timespec); -} - - /* ------------------------------------------------------------------------- */ /* IO support and wrapper functions for the Windows API. */ /* ------------------------------------------------------------------------- */ @@ -4985,7 +4961,7 @@ convert_time (FILETIME ft) } static void -convert_from_time_t (time_t time, FILETIME * pft) +convert_from_timespec (struct timespec time, FILETIME * pft) { ULARGE_INTEGER tmp; @@ -4996,7 +4972,8 @@ convert_from_time_t (time_t time, FILETIME * pft) } /* time in 100ns units since 1-Jan-1601 */ - tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base; + tmp.QuadPart = + (ULONGLONG) time.tv_sec * 10000000L + time.tv_nsec / 100 + utc_base; pft->dwHighDateTime = tmp.HighPart; pft->dwLowDateTime = tmp.LowPart; } @@ -5663,8 +5640,8 @@ fstatat (int fd, char const *name, struct stat *st, int flags) return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW)); } -/* Provide fstat and utime as well as stat for consistent handling of - file timestamps. */ +/* Provide fstat and utimensat as well as stat for consistent handling + of file timestamps. */ int fstat (int desc, struct stat * buf) { @@ -5775,23 +5752,65 @@ fstat (int desc, struct stat * buf) return 0; } -/* A version of 'utime' which handles directories as well as - files. */ +/* Emulate utimensat. */ int -utime (const char *name, struct utimbuf *times) +utimensat (int fd, const char *name, const struct timespec times[2], int flag) { - struct utimbuf deftime; + struct timespec ltimes[2]; HANDLE fh; FILETIME mtime; FILETIME atime; + DWORD flags_and_attrs = FILE_FLAG_BACKUP_SEMANTICS; + + /* Rely on a hack: an open directory is modeled as file descriptor 0. + This is good enough for the current usage in Emacs, but is fragile. + + FIXME: Add proper support for utimensat. + Gnulib does this and can serve as a model. */ + char fullname[MAX_UTF8_PATH]; + + if (fd != AT_FDCWD) + { + char lastc = dir_pathname[strlen (dir_pathname) - 1]; + + if (_snprintf (fullname, sizeof fullname, "%s%s%s", + dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name) + < 0) + { + errno = ENAMETOOLONG; + return -1; + } + name = fullname; + } if (times == NULL) { - deftime.modtime = deftime.actime = time (NULL); - times = &deftime; + memset (ltimes, 0, sizeof (ltimes)); + ltimes[0] = ltimes[1] = current_timespec (); + } + else + { + if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) + return 0; /* nothing to do */ + if ((times[0].tv_nsec != UTIME_NOW && times[0].tv_nsec != UTIME_OMIT + && !(0 <= times[0].tv_nsec && times[0].tv_nsec < 1000000000)) + || (times[1].tv_nsec != UTIME_NOW && times[1].tv_nsec != UTIME_OMIT + && !(0 <= times[1].tv_nsec && times[1].tv_nsec < 1000000000))) + { + errno = EINVAL; /* reject invalid timespec values */ + return -1; + } + + memcpy (ltimes, times, sizeof (ltimes)); + if (ltimes[0].tv_nsec == UTIME_NOW) + ltimes[0] = current_timespec (); + if (ltimes[1].tv_nsec == UTIME_NOW) + ltimes[1] = current_timespec (); } + if (flag == AT_SYMLINK_NOFOLLOW) + flags_and_attrs |= FILE_FLAG_OPEN_REPARSE_POINT; if (w32_unicode_filenames) { wchar_t name_utf16[MAX_PATH]; @@ -5805,7 +5824,7 @@ utime (const char *name, struct utimbuf *times) allows other processes to delete files inside it, while we have the directory open. */ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + 0, OPEN_EXISTING, flags_and_attrs, NULL); } else { @@ -5816,13 +5835,26 @@ utime (const char *name, struct utimbuf *times) fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + 0, OPEN_EXISTING, flags_and_attrs, NULL); } if (fh != INVALID_HANDLE_VALUE) { - convert_from_time_t (times->actime, &atime); - convert_from_time_t (times->modtime, &mtime); - if (!SetFileTime (fh, NULL, &atime, &mtime)) + FILETIME *patime, *pmtime; + if (ltimes[0].tv_nsec == UTIME_OMIT) + patime = NULL; + else + { + convert_from_timespec (ltimes[0], &atime); + patime = &atime; + } + if (ltimes[1].tv_nsec == UTIME_OMIT) + pmtime = NULL; + else + { + convert_from_timespec (ltimes[1], &mtime); + pmtime = &mtime; + } + if (!SetFileTime (fh, NULL, patime, pmtime)) { CloseHandle (fh); errno = EACCES; @@ -6741,16 +6773,16 @@ w32_copy_file (const char *from, const char *to, FIXME? */ else if (!keep_time) { - struct timespec now; + struct timespec tnow[2]; DWORD attributes; + tnow[0] = tnow[1] = current_timespec (); if (w32_unicode_filenames) { /* Ensure file is writable while its times are set. */ attributes = GetFileAttributesW (to_w); SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY); - now = current_timespec (); - if (set_file_times (-1, to, now, now)) + if (utimensat (AT_FDCWD, to, tnow, 0)) { /* Restore original attributes. */ SetFileAttributesW (to_w, attributes); @@ -6765,8 +6797,7 @@ w32_copy_file (const char *from, const char *to, { attributes = GetFileAttributesA (to_a); SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY); - now = current_timespec (); - if (set_file_times (-1, to, now, now)) + if (utimensat (AT_FDCWD, to, tnow, 0)) { SetFileAttributesA (to_a, attributes); if (acl)