emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 1804fec 2/2: Merge branch 'master' of git.savannah.


From: Stephen Gildea
Subject: [Emacs-diffs] master 1804fec 2/2: Merge branch 'master' of git.savannah.gnu.org:/srv/git/emacs
Date: Wed, 1 Aug 2018 01:39:28 -0400 (EDT)

branch: master
commit 1804fece02691798394c9e9bd519cd4a53776018
Merge: 17205d3 82d6416
Author: Stephen Gildea <address@hidden>
Commit: Stephen Gildea <address@hidden>

    Merge branch 'master' of git.savannah.gnu.org:/srv/git/emacs
---
 admin/MAINTAINERS                       |  12 +-
 build-aux/config.guess                  | 112 ++--
 build-aux/config.sub                    |  10 +-
 configure.ac                            |   7 +-
 doc/emacs/files.texi                    |   2 +
 doc/emacs/indent.texi                   |  21 +-
 doc/emacs/maintaining.texi              |  16 +-
 doc/emacs/misc.texi                     |   4 +-
 doc/emacs/mule.texi                     |  19 +-
 doc/lispref/eval.texi                   |   3 -
 doc/lispref/frames.texi                 |  10 +-
 doc/lispref/minibuf.texi                |   2 +-
 doc/lispref/numbers.texi                |  36 +-
 doc/lispref/sequences.texi              |   6 +-
 doc/lispref/strings.texi                |  27 +-
 doc/lispref/threads.texi                |  23 +-
 doc/misc/efaq.texi                      |   4 +-
 doc/misc/flymake.texi                   |   2 +-
 doc/misc/tramp.texi                     |  52 +-
 etc/NEWS                                |  86 ++-
 etc/NEWS.26                             |   8 +
 etc/emacs.service                       |   2 +-
 lib-src/pop.c                           |   8 +-
 lib/gnulib.mk.in                        | 118 +++-
 lisp/auth-source.el                     |   2 +-
 lisp/bookmark.el                        |   7 +-
 lisp/comint.el                          |  19 +-
 lisp/emacs-lisp/cl-print.el             |   4 +-
 lisp/emacs-lisp/lisp-mode.el            |  16 +-
 lisp/emacs-lisp/rx.el                   |  32 +-
 lisp/env.el                             |   6 +-
 lisp/epg-config.el                      |  32 +-
 lisp/eshell/em-dirs.el                  |   3 +
 lisp/eshell/em-ls.el                    |   1 +
 lisp/eshell/em-unix.el                  |  10 +
 lisp/eshell/esh-cmd.el                  |  51 +-
 lisp/eshell/esh-ext.el                  |   1 +
 lisp/files.el                           |   4 +-
 lisp/format.el                          |   2 +
 lisp/gnus/gnus-art.el                   |   6 +
 lisp/gnus/gnus-sum.el                   |   8 +-
 lisp/ielm.el                            |  14 +-
 lisp/imenu.el                           |  13 +-
 lisp/indent.el                          |   9 +-
 lisp/international/fontset.el           |   9 +-
 lisp/international/mule-conf.el         |   9 +-
 lisp/international/mule-diag.el         |   3 +-
 lisp/international/quail.el             |  20 +-
 lisp/language/thai.el                   |   4 +-
 lisp/net/rlogin.el                      |   8 +-
 lisp/net/soap-client.el                 |  21 +-
 lisp/net/tramp.el                       |  12 +-
 lisp/net/trampver.el                    |   2 +-
 lisp/profiler.el                        |   6 +-
 lisp/progmodes/cc-engine.el             |  12 +-
 lisp/progmodes/elisp-mode.el            |   2 +-
 lisp/progmodes/hideif.el                |   2 +-
 lisp/progmodes/python.el                |  95 ++--
 lisp/progmodes/subword.el               |   4 +-
 lisp/register.el                        |  15 +-
 lisp/scroll-bar.el                      |  24 +-
 lisp/shadowfile.el                      | 478 ++++++++--------
 lisp/shell.el                           |   4 +-
 lisp/simple.el                          |  12 +-
 lisp/subr.el                            |  12 +-
 lisp/term.el                            |  20 +-
 lisp/term/tty-colors.el                 |  14 +-
 lisp/textmodes/flyspell.el              |  14 +-
 lisp/textmodes/ispell.el                |   5 +-
 lisp/textmodes/reftex-vars.el           |   6 +-
 lisp/vc/add-log.el                      |  77 ++-
 lisp/vc/diff.el                         |   5 +-
 lisp/vc/log-edit.el                     |   6 +-
 lisp/w32-fns.el                         |   2 +-
 lisp/wdired.el                          |  51 +-
 nt/inc/ms-w32.h                         |  12 +-
 nt/inc/sys/socket.h                     |   5 +
 src/alloc.c                             |   2 +-
 src/callint.c                           |   2 +-
 src/character.c                         |  10 +-
 src/chartab.c                           |   4 +-
 src/dbusbind.c                          |   4 +-
 src/dired.c                             |   2 +-
 src/editfns.c                           |  66 ++-
 src/emacs.c                             |  11 +
 src/eval.c                              |  20 +-
 src/fileio.c                            |  35 +-
 src/fns.c                               | 103 ++--
 src/frame.c                             |  27 +-
 src/gnutls.c                            |  38 +-
 src/image.c                             |   2 +-
 src/intervals.c                         |   2 +-
 src/intervals.h                         |   2 +-
 src/json.c                              |   2 +-
 src/keyboard.c                          |  47 +-
 src/lisp.h                              |   3 +-
 src/lread.c                             |   9 +-
 src/menu.c                              |   6 +-
 src/nsfns.m                             |   4 +-
 src/nsmenu.m                            |   2 +-
 src/nsselect.m                          |   6 +-
 src/process.c                           |  20 +-
 src/terminal.c                          |   2 +-
 src/textprop.c                          |   2 +-
 src/thread.c                            |  41 +-
 src/thread.h                            |   3 +
 src/w32cygwinx.c                        |  37 +-
 src/w32term.c                           |   2 +-
 src/xdisp.c                             |   2 +-
 src/xfaces.c                            |   4 +-
 src/xfns.c                              |   4 +-
 src/xmenu.c                             |   4 +-
 src/xselect.c                           |   4 +-
 src/xwidget.c                           |   2 +-
 test/Makefile.in                        |   1 -
 test/lisp/auth-source-tests.el          |  20 +
 test/lisp/emacs-lisp/lisp-mode-tests.el |  23 +
 test/lisp/emacs-lisp/package-tests.el   |  12 +-
 test/lisp/epg-tests.el                  |  34 +-
 test/lisp/shadowfile-tests.el           | 932 ++++++++++++++++++++++++++++++++
 test/lisp/wdired-tests.el               | 105 ++++
 test/src/editfns-tests.el               |  10 +-
 test/src/fns-tests.el                   |  11 +
 test/src/thread-tests.el                |  34 +-
 124 files changed, 2672 insertions(+), 847 deletions(-)

diff --git a/admin/MAINTAINERS b/admin/MAINTAINERS
index 753a676..1a4157a 100644
--- a/admin/MAINTAINERS
+++ b/admin/MAINTAINERS
@@ -61,7 +61,7 @@ Michael Albinus
             lisp/net/tramp*.el
             lisp/url/url-tramp.el
             doc/misc/tramp*.texi
-            test/lisp/net/tramp-tests.el
+            test/lisp/net/tramp*-tests.el
             test/lisp/url/url-tramp-tests.el
 
         D-Bus
@@ -210,11 +210,21 @@ Paul Eggert
 Michael Albinus
        src/inotify.c
         lisp/autorevert.el
+        lisp/files.el (file-name-non-special)
        lisp/eshell/em-tramp.el
+       lisp/net/ange-ftp.el
        lisp/notifications.el
+       lisp/shadowfile.el
         test/lisp/autorevert-tests.el
+        test/lisp/files-tests.el (file-name-non-special)
+       test/lisp/shadowfile-tests.el
        test/src/inotify-test.el
 
+       Secret Service API in
+           lisp/auth-source.el
+           doc/misc/auth.texi
+           test/lisp/auth-source-tests.el
+
 Nicolas Petton
        lisp/emacs-lisp/subr-x.el
        lisp/arc-mode.el
diff --git a/build-aux/config.guess b/build-aux/config.guess
index 2b79f6d..ba6af63 100755
--- a/build-aux/config.guess
+++ b/build-aux/config.guess
@@ -2,7 +2,7 @@
 # Attempt to guess a canonical system name.
 #   Copyright 1992-2018 Free Software Foundation, Inc.
 
-timestamp='2018-07-06'
+timestamp='2018-07-18'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -84,8 +84,6 @@ if test $# != 0; then
   exit 1
 fi
 
-trap 'exit 1' 1 2 15
-
 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a
 # compiler to aid in system detection is discouraged as it requires
 # temporary files to be created and, as you can see below, it is a
@@ -96,30 +94,35 @@ trap 'exit 1' 1 2 15
 
 # Portable tmp directory creation inspired by the Autoconf team.
 
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && 
exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 
;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n 
"$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp 
2>/dev/null) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp 2>/dev/null) && echo 
"Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } 
;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
- ,,)    echo "int x;" > "$dummy.c" ;
-       for c in cc gcc c89 c99 ; do
-         if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
-            CC_FOR_BUILD="$c"; break ;
-         fi ;
-       done ;
-       if test x"$CC_FOR_BUILD" = x ; then
-         CC_FOR_BUILD=no_compiler_found ;
-       fi
-       ;;
- ,,*)   CC_FOR_BUILD=$CC ;;
- ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 1 2 13 15
+trap 'exitcode=$?; test -z "$tmp" || rm -fr "$tmp"; exit $exitcode' 0
+
+set_cc_for_build() {
+    : "${TMPDIR=/tmp}"
+    # shellcheck disable=SC2039
+    { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n 
"$tmp" && test -d "$tmp" ; } ||
+       { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir 
"$tmp" 2>/dev/null) ; } ||
+       { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo 
"Warning: creating insecure temp directory" >&2 ; } ||
+       { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 
1 ; }
+    dummy=$tmp/dummy
+    case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+       ,,)    echo "int x;" > "$dummy.c"
+              for driver in cc gcc c89 c99 ; do
+                  if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; 
then
+                      CC_FOR_BUILD="$driver"
+                      break
+                  fi
+              done
+              if test x"$CC_FOR_BUILD" = x ; then
+                  CC_FOR_BUILD=no_compiler_found
+              fi
+              ;;
+       ,,*)   CC_FOR_BUILD=$CC ;;
+       ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+    esac
+}
 
 # This is needed to find uname on a Pyramid OSx when run in the BSD universe.
 # (address@hidden 1994-08-24)
@@ -138,7 +141,7 @@ Linux|GNU|GNU/*)
        # We could probably try harder.
        LIBC=gnu
 
-       eval "$set_cc_for_build"
+       set_cc_for_build
        cat <<-EOF > "$dummy.c"
        #include <features.h>
        #if defined(__UCLIBC__)
@@ -199,7 +202,7 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
                os=netbsdelf
                ;;
            arm*|i386|m68k|ns32k|sh3*|sparc|vax)
-               eval "$set_cc_for_build"
+               set_cc_for_build
                if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
                        | grep -q __ELF__
                then
@@ -389,20 +392,15 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        echo i386-pc-auroraux"$UNAME_RELEASE"
        exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
-       eval "$set_cc_for_build"
-       SUN_ARCH=i386
-       # If there is a compiler, see if it is configured for 64-bit objects.
-       # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
-       # This test works for both compilers.
-       if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
-           if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
-               (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
-               grep IS_64BIT_ARCH >/dev/null
-           then
-               SUN_ARCH=x86_64
-           fi
-       fi
-       echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+       UNAME_REL="`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+       case `isainfo -b` in
+           32)
+               echo i386-pc-solaris2"$UNAME_REL"
+               ;;
+           64)
+               echo x86_64-pc-solaris2"$UNAME_REL"
+               ;;
+       esac
        exit ;;
     sun4*:SunOS:6*:*)
        # According to config.sub, this is the proper way to canonicalize
@@ -482,7 +480,7 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        echo clipper-intergraph-clix"$UNAME_RELEASE"
        exit ;;
     mips:*:*:UMIPS | mips:*:*:RISCos)
-       eval "$set_cc_for_build"
+       set_cc_for_build
        sed 's/^        //' << EOF > "$dummy.c"
 #ifdef __cplusplus
 #include <stdio.h>  /* for printf() prototype */
@@ -579,7 +577,7 @@ EOF
        exit ;;
     *:AIX:2:3)
        if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
-               eval "$set_cc_for_build"
+               set_cc_for_build
                sed 's/^                //' << EOF > "$dummy.c"
                #include <sys/systemcfg.h>
 
@@ -660,7 +658,7 @@ EOF
                    esac
                fi
                if [ "$HP_ARCH" = "" ]; then
-                   eval "$set_cc_for_build"
+                   set_cc_for_build
                    sed 's/^            //' << EOF > "$dummy.c"
 
                #define _HPUX_SOURCE
@@ -700,7 +698,7 @@ EOF
        esac
        if [ "$HP_ARCH" = hppa2.0w ]
        then
-           eval "$set_cc_for_build"
+           set_cc_for_build
 
            # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
            # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
@@ -726,7 +724,7 @@ EOF
        echo ia64-hp-hpux"$HPUX_REV"
        exit ;;
     3050*:HI-UX:*:*)
-       eval "$set_cc_for_build"
+       set_cc_for_build
        sed 's/^        //' << EOF > "$dummy.c"
        #include <unistd.h>
        int
@@ -840,6 +838,17 @@ EOF
     *:BSD/OS:*:*)
        echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
        exit ;;
+    arm*:FreeBSD:*:*)
+       UNAME_PROCESSOR=`uname -p`
+       set_cc_for_build
+       if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+           | grep -q __ARM_PCS_VFP
+       then
+           echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo 
${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi
+       else
+           echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo 
${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf
+       fi
+       exit ;;
     *:FreeBSD:*:*)
        UNAME_PROCESSOR=`/usr/bin/uname -p`
        case "$UNAME_PROCESSOR" in
@@ -922,7 +931,7 @@ EOF
        echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
        exit ;;
     arm*:Linux:*:*)
-       eval "$set_cc_for_build"
+       set_cc_for_build
        if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
            | grep -q __ARM_EABI__
        then
@@ -971,7 +980,7 @@ EOF
        echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
        exit ;;
     mips:Linux:*:* | mips64:Linux:*:*)
-       eval "$set_cc_for_build"
+       set_cc_for_build
        sed 's/^        //' << EOF > "$dummy.c"
        #undef CPU
        #undef ${UNAME_MACHINE}
@@ -1285,7 +1294,7 @@ EOF
        exit ;;
     *:Darwin:*:*)
        UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
-       eval "$set_cc_for_build"
+       set_cc_for_build
        if test "$UNAME_PROCESSOR" = unknown ; then
            UNAME_PROCESSOR=powerpc
        fi
@@ -1358,6 +1367,7 @@ EOF
        # "uname -m" is not consistent, so use $cputype instead. 386
        # is converted to i386 for consistency with other x86
        # operating systems.
+       # shellcheck disable=SC2154
        if test "$cputype" = 386; then
            UNAME_MACHINE=i386
        else
diff --git a/build-aux/config.sub b/build-aux/config.sub
index c95acc6..52eb02e 100755
--- a/build-aux/config.sub
+++ b/build-aux/config.sub
@@ -2,7 +2,7 @@
 # Configuration validation subroutine script.
 #   Copyright 1992-2018 Free Software Foundation, Inc.
 
-timestamp='2018-07-03'
+timestamp='2018-07-25'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -307,7 +307,7 @@ case $1 in
                                os=mach
                                ;;
                        vsta)
-                               basic_machine=i386-unknown
+                               basic_machine=i386-pc
                                os=vsta
                                ;;
                        isi68 | isi)
@@ -371,7 +371,7 @@ case $1 in
                                os=sysv4
                                ;;
                        netbsd386)
-                               basic_machine=i386-unknown
+                               basic_machine=i386-pc
                                os=netbsd
                                ;;
                        netwinder)
@@ -739,6 +739,7 @@ case $basic_machine in
        | mipsr5900-* | mipsr5900el-* \
        | mipstx39-* | mipstx39el-* \
        | mmix-* \
+       | moxie-* \
        | mt-* \
        | msp430-* \
        | nds32-* | nds32le-* | nds32be-* \
@@ -1263,9 +1264,6 @@ case $basic_machine in
        pmac | pmac-mpw)
                basic_machine=powerpc-apple
                ;;
-       *-unknown)
-               # Make sure to match an already-canonicalized machine name.
-               ;;
        *)
                echo Invalid configuration \`"$1"\': machine 
\`"$basic_machine"\' not recognized 1>&2
                exit 1
diff --git a/configure.ac b/configure.ac
index 6613ce1..b691867 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5468,9 +5468,10 @@ echo
 
 if test "$HAVE_NS" = "yes"; then
    echo
-   AS_ECHO(["You must run \"${MAKE-make} install\" in order to test the built 
application.
-The installed application will go to nextstep/Emacs.app and can be
-run or moved from there."])
+   AS_ECHO(["Run '${MAKE-make}' to build Emacs, then run 'src/emacs' to test 
it.
+Run '${MAKE-make} install' in order to build an application bundle.
+The application will go to nextstep/Emacs.app and can be run or moved
+from there."])
    if test "$EN_NS_SELF_CONTAINED" = "yes"; then
       echo "The application will be fully self-contained."
     else
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index f0a11fd..a7cc57e 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -881,6 +881,8 @@ You can answer ``no'' to bypass copying of this file, this 
time.  If
 you want to cancel the shadowing permanently for a certain file, use
 @address@hidden shadow-cancel}} to eliminate or change the shadow file group.
 
+File Shadowing is not available on MS Windows.
+
 @node Time Stamps
 @subsection Updating Time Stamps Automatically
 @cindex time stamps
diff --git a/doc/emacs/indent.texi b/doc/emacs/indent.texi
index b38e858..bf43909 100644
--- a/doc/emacs/indent.texi
+++ b/doc/emacs/indent.texi
@@ -60,9 +60,9 @@ repositioned to the first non-whitespace character on the 
line.
 @node Indentation Commands
 @section Indentation Commands
 
-Apart from the @key{TAB} (@code{indent-for-tab-command}) command,
-Emacs provides a variety of commands to perform indentation in other
-ways.
+Apart from the @address@hidden (@code{indent-for-tab-command})
+command, Emacs provides a variety of commands to perform indentation
+in other ways.
 
 @table @kbd
 @item C-M-o
@@ -113,8 +113,8 @@ appears after the newline that is deleted.  @xref{Fill 
Prefix}.
 @item C-M-\
 @kindex C-M-\
 @findex indent-region
-Indent all the lines in the region, as though you had typed @key{TAB}
-at the beginning of each line (@code{indent-region}).
+Indent all the lines in the region, as though you had typed
address@hidden@key{TAB}} at the beginning of each line (@code{indent-region}).
 
 If a numeric argument is supplied, indent every line in the region to
 that column number.
@@ -128,11 +128,12 @@ in the region, moving the affected lines as a rigid unit.
 
 If called with no argument, the command activates a transient mode for
 adjusting the indentation of the affected lines interactively.  While
-this transient mode is active, typing @key{LEFT} or @key{RIGHT}
-indents leftward and rightward, respectively, by one space.  You can
-also type @address@hidden or @address@hidden to indent leftward
-or rightward to the next tab stop (@pxref{Tab Stops}).  Typing any
-other key disables the transient mode, and resumes normal editing.
+this transient mode is active, typing @address@hidden or
address@hidden@key{RIGHT}} indents leftward and rightward, respectively, by one
+space.  You can also type @address@hidden or @address@hidden to
+indent leftward or rightward to the next tab stop (@pxref{Tab Stops}).
+Typing any other key disables the transient mode, and resumes normal
+editing.
 
 If called with a prefix argument @var{n}, this command indents the
 lines forward by @var{n} spaces (without enabling the transient mode).
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 024fd97..b31cacf 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -1655,10 +1655,20 @@ not just to the next change log entry.  You can also use
 log files into a buffer in Change Log Mode, preserving the date
 ordering of entries.
 
address@hidden add-log-dont-create-changelog-file
   Version control systems are another way to keep track of changes in
-your program and keep a change log.  In the VC log buffer, typing
address@hidden C-a} (@code{log-edit-insert-changelog}) inserts the relevant
-change log entry, if one exists.  @xref{Log Buffer}.
+your program and keep a change log.  Many projects that use a VCS don't
+keep a separate versioned change log file nowadays, so you may wish to
+avoid having such a file in the repository.  If the value of
address@hidden is address@hidden, commands
+like @kbd{C-x 4 a} (@code{add-change-log-entry-other-window}) will
+record changes in a suitably named temporary buffer instead of a file,
+if such a file does not already exist.
+
+Whether you have a change log file or use a temporary buffer for
+change logs, you can type @kbd{C-c C-a}
+(@code{log-edit-insert-changelog}) in the VC Log buffer to insert the
+relevant change log entries, if they exist.  @xref{Log Buffer}.
 
 @node Format of ChangeLog
 @subsection Format of ChangeLog
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index 3d34414..236cb07 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -1026,8 +1026,8 @@ Move backward across one shell command, but not beyond 
the current line
 Ask the shell for its working directory, and update the Shell buffer's
 default directory.  @xref{Directory Tracking}.
 
address@hidden M-x send-invisible @key{RET} @var{text} @key{RET}
address@hidden send-invisible
address@hidden M-x comint-send-invisible @key{RET} @var{text} @key{RET}
address@hidden comint-send-invisible
 Send @var{text} as input to the shell, after reading it without
 echoing.  This is useful when a shell command runs a program that asks
 for a password.
diff --git a/doc/emacs/mule.texi b/doc/emacs/mule.texi
index 401c83d..6c0c5b2 100644
--- a/doc/emacs/mule.texi
+++ b/doc/emacs/mule.texi
@@ -156,12 +156,19 @@ system encodes the character safely and with a single byte
 (@pxref{Coding Systems}).  If the character's encoding is longer than
 one byte, Emacs shows @samp{file ...}.
 
-  As a special case, if the character lies in the range 128 (0200
-octal) through 159 (0237 octal), it stands for a raw byte that
-does not correspond to any specific displayable character.  Such a
-character lies within the @code{eight-bit-control} character set,
-and is displayed as an escaped octal character code.  In this case,
address@hidden =} shows @samp{part of display ...} instead of @samp{file}.
address@hidden eight-bit character set
address@hidden raw bytes
+  On rare occasions, Emacs encounters @dfn{raw bytes}: single bytes
+whose values are in the range 128 (0200 octal) through 255 (0377
+octal), which Emacs cannot interpret as part of a known encoding of
+some non-ASCII character.  Such raw bytes are treated as if they
+belonged to a special character set @code{eight-bit}; Emacs displays
+them as escaped octal codes (this can be customized; @pxref{Display
+Custom}).  In this case, @kbd{C-x =} shows @samp{raw-byte} instead of
address@hidden  In addition, @kbd{C-x =} shows the character codes of
+raw bytes as if they were in the range @code{#x3FFF80..#x3FFFFF},
+which is where Emacs maps them to distinguish them from Unicode
+characters in the range @code{#x0080..#x00FF}.
 
 @cindex character set of character at point
 @cindex font of character at point
diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi
index 4e8b0df..c9401be 100644
--- a/doc/lispref/eval.texi
+++ b/doc/lispref/eval.texi
@@ -507,9 +507,6 @@ Emacs Lisp with a reference to where each is described.
 @item setq-default
 @pxref{Creating Buffer-Local}
 
address@hidden track-mouse
address@hidden Tracking}
-
 @item unwind-protect
 @pxref{Nonlocal Exits}
 
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 6678644..ba4b931 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -3373,10 +3373,10 @@ occur.  That is useful, because normally you don't want 
to track the
 mouse forever---only until some other event, such as the release of a
 button.
 
address@hidden track-mouse address@hidden
-This special form executes @var{body}, with generation of mouse motion
-events enabled.  Typically, @var{body} would use @code{read-event} to
-read the motion events and modify the display accordingly.  @xref{Motion
address@hidden track-mouse address@hidden
+This macro executes @var{body}, with generation of mouse motion events
+enabled.  Typically, @var{body} would use @code{read-event} to read
+the motion events and modify the display accordingly.  @xref{Motion
 Events}, for the format of mouse motion events.
 
 The value of @code{track-mouse} is that of the last form in @var{body}.
@@ -3396,7 +3396,7 @@ on (@pxref{Pointer Shape}).  Therefore, Lisp programs 
that need the
 mouse pointer to retain its original shape during dragging should bind
 @code{track-mouse} to the value @code{dragging} at the beginning of
 their @var{body}.
address@hidden defspec
address@hidden defmac
 
 The usual purpose of tracking mouse motion is to indicate on the screen
 the consequences of pushing or releasing a button at the current
diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index 889b64a..d091787 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -2199,7 +2199,7 @@ function @code{read-passwd}.
 @defun read-passwd prompt &optional confirm default
 This function reads a password, prompting with @var{prompt}.  It does
 not echo the password as the user types it; instead, it echoes
address@hidden  for each character in the password.  If you want to apply
address@hidden  for each character in the password.  If you want to apply
 another character to hide the password, let-bind the variable
 @code{read-hide-char} with that character.
 
diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi
index 2fed2b6..14d5059 100644
--- a/doc/lispref/numbers.texi
+++ b/doc/lispref/numbers.texi
@@ -223,7 +223,7 @@ least one digit after any decimal point in a floating-point 
number;
 @samp{1500.} is an integer, not a floating-point number.
 
   Emacs Lisp treats @code{-0.0} as numerically equal to ordinary zero
-with respect to @code{equal} and @code{=}.  This follows the
+with respect to numeric comparisons like @code{=}.  This follows the
 @acronym{IEEE} floating-point standard, which says @code{-0.0} and
 @code{0.0} are numerically equal even though other operations can
 distinguish them.
@@ -237,8 +237,20 @@ infinity and negative infinity as floating-point values.  
It also
 provides for a class of values called NaN, or ``not a number'';
 numerical functions return such values in cases where there is no
 correct answer.  For example, @code{(/ 0.0 0.0)} returns a address@hidden
-Although NaN values carry a sign, for practical purposes there is no other
-significant difference between different NaN values in Emacs Lisp.
+A NaN is never numerically equal to any value, not even to itself.
+NaNs carry a sign and a significand, and non-numeric functions treat
+two NaNs as equal when their
+signs and significands agree.  Significands of NaNs are
+machine-dependent and are not directly visible to Emacs Lisp.
+
+  When NaNs and signed zeros are involved, non-numeric functions like
address@hidden, @code{equal}, @code{sxhash-eql}, @code{sxhash-equal} and
address@hidden determine whether values are indistinguishable, not
+whether they are numerically equal.  For example, when @var{x} and
address@hidden are the same NaN, @code{(equal x y)} returns @code{t} whereas
address@hidden(= x y)} uses numeric comparison and returns @code{nil};
+conversely, @code{(equal 0.0 -0.0)} returns @code{nil} whereas
address@hidden(= 0.0 -0.0)} returns @code{t}.
 
 Here are read syntaxes for these special floating-point values:
 
@@ -354,11 +366,15 @@ if so, @code{nil} otherwise.  The argument must be a 
number.
 @cindex comparing numbers
 
   To test numbers for numerical equality, you should normally use
address@hidden, not @code{eq}.  There can be many distinct floating-point
-objects with the same numeric value.  If you use @code{eq} to
-compare them, then you test whether two values are the same
address@hidden  By contrast, @code{=} compares only the numeric values
-of the objects.
address@hidden instead of non-numeric comparison predicates like @code{eq},
address@hidden and @code{equal}.  Distinct floating-point objects can be
+numerically equal.  If you use @code{eq} to compare them, you test
+whether they are the same @emph{object}; if you use @code{eql} or
address@hidden, you test whether their values are
address@hidden  In contrast, @code{=} uses numeric
+comparison, and sometimes returns @code{t} when a non-numeric
+comparison would return @code{nil} and vice versa.  @xref{Float
+Basics}.
 
   In Emacs Lisp, each integer is a unique Lisp object.
 Therefore, @code{eq} is equivalent to @code{=} where integers are
@@ -837,7 +853,7 @@ reproducing the same pattern moved over.
 bits in @var{integer1} to the left @var{count} places, or to the right
 if @var{count} is negative, bringing zeros into the vacated bits.  If
 @var{count} is negative, @code{lsh} shifts zeros into the leftmost
-(most-significant) bit, producing a positive result even if
+(most-significant) bit, producing a nonnegative result even if
 @var{integer1} is negative.  Contrast this with @code{ash}, below.
 
 Here are two examples of @code{lsh}, shifting a pattern of bits one
@@ -1217,7 +1233,7 @@ returns a NaN.
 
 @defun expt x y
 This function returns @var{x} raised to power @var{y}.  If both
-arguments are integers and @var{y} is positive, the result is an
+arguments are integers and @var{y} is nonnegative, the result is an
 integer; in this case, overflow causes truncation, so watch out.
 If @var{x} is a finite negative number and @var{y} is a finite
 non-integer, @code{expt} returns a NaN.
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi
index be7a402..6a6f4d5 100644
--- a/doc/lispref/sequences.texi
+++ b/doc/lispref/sequences.texi
@@ -63,7 +63,8 @@ But it is possible to add elements to the list, or remove 
elements.
 
 @defun sequencep object
 This function returns @code{t} if @var{object} is a list, vector,
-string, bool-vector, or char-table, @code{nil} otherwise.
+string, bool-vector, or char-table, @code{nil} otherwise.  See also
address@hidden below.
 @end defun
 
 @defun length sequence
@@ -479,7 +480,8 @@ built-in sequence types, @code{seq-length} behaves like 
@code{length}.
 @defun seqp object
   This function returns address@hidden if @var{object} is a sequence
 (a list or array), or any additional type of sequence defined via
address@hidden generic functions.
address@hidden generic functions.  This is an extensible variant of
address@hidden
 
 @example
 @group
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index 026ba74..3558f17 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -922,7 +922,8 @@ Functions}).  Thus, strings are enclosed in @samp{"} 
characters, and
 @item %o
 @cindex integer to octal
 Replace the specification with the base-eight representation of an
-unsigned integer.  The object can also be a nonnegative floating-point
+integer.  Negative integers are formatted in a platform-dependent
+way.  The object can also be a nonnegative floating-point
 number that is formatted as an integer, dropping any fraction, if the
 integer does not exceed machine limits.
 
@@ -935,7 +936,8 @@ formatted as an integer, dropping any fraction.
 @itemx %X
 @cindex integer to hexadecimal
 Replace the specification with the base-sixteen representation of an
-unsigned integer.  @samp{%x} uses lower case and @samp{%X} uses upper
+integer.  Negative integers are formatted in a platform-dependent
+way.  @samp{%x} uses lower case and @samp{%X} uses upper
 case.  The object can also be a nonnegative floating-point number that
 is formatted as an integer, dropping any fraction, if the integer does
 not exceed machine limits.
@@ -1015,17 +1017,17 @@ numbered or unnumbered format specifications but not 
both, except that
   After the @samp{%} and any field number, you can put certain
 @dfn{flag characters}.
 
-  The flag @samp{+} inserts a plus sign before a positive number, so
+  The flag @samp{+} inserts a plus sign before a nonnegative number, so
 that it always has a sign.  A space character as flag inserts a space
-before a positive number.  (Otherwise, positive numbers start with the
-first digit.)  These flags are useful for ensuring that positive
-numbers and negative numbers use the same number of columns.  They are
+before a nonnegative number.  (Otherwise, nonnegative numbers start with the
+first digit.)  These flags are useful for ensuring that nonnegative
+and negative numbers use the same number of columns.  They are
 ignored except for @samp{%d}, @samp{%e}, @samp{%f}, @samp{%g}, and if
 both flags are used, @samp{+} takes precedence.
 
   The flag @samp{#} specifies an alternate form which depends on
 the format in use.  For @samp{%o}, it ensures that the result begins
-with a @samp{0}.  For @samp{%x} and @samp{%X}, it prefixes the result
+with a @samp{0}.  For @samp{%x} and @samp{%X}, it prefixes nonzero results
 with @samp{0x} or @samp{0X}.  For @samp{%e} and @samp{%f}, the
 @samp{#} flag means include a decimal point even if the precision is
 zero.  For @samp{%g}, it always includes a decimal point, and also
@@ -1108,6 +1110,17 @@ shows only the first three characters of the 
representation for
 precision is what the local library functions of the @code{printf}
 family produce.
 
address@hidden formatting numbers for rereading later
+  If you plan to use @code{read} later on the formatted string to
+retrieve a copy of the formatted value, use a specification that lets
address@hidden reconstruct the value.  To format numbers in this
+reversible way you can use @samp{%s} and @samp{%S}, to format just
+integers you can also use @samp{%d}, and to format just nonnegative
+integers you can also use @samp{#x%x} and @samp{#o%o}.  Other formats
+may be problematic; for example, @samp{%d} and @samp{%g} can mishandle
+NaNs and can lose precision and type, and @samp{#x%x} and @samp{#o%o}
+can mishandle negative integers.  @xref{Input Functions}.
+
 @node Case Conversion
 @section Case Conversion in Lisp
 @cindex upper case
diff --git a/doc/lispref/threads.texi b/doc/lispref/threads.texi
index f05af49..58a3a91 100644
--- a/doc/lispref/threads.texi
+++ b/doc/lispref/threads.texi
@@ -75,8 +75,8 @@ thread, @code{nil} otherwise.
 
 @defun thread-join thread
 Block until @var{thread} exits, or until the current thread is
-signaled.  If @var{thread} has already exited, this returns
-immediately.
+signaled.  It returns the result of the @var{thread} function.  If
address@hidden has already exited, this returns immediately.
 @end defun
 
 @defun thread-signal thread error-symbol data
@@ -87,6 +87,15 @@ thread, then this just calls @code{signal} immediately.  
Otherwise,
 If @var{thread} was blocked by a call to @code{mutex-lock},
 @code{condition-wait}, or @code{thread-join}; @code{thread-signal}
 will unblock it.
+
+Since signal handlers in Emacs are located in the main thread, a
+signal must be propagated there in order to become visible.  The
+second @code{signal} call let the thread die:
+
address@hidden
+(thread-signal main-thread 'error data)
+(signal 'error data)
address@hidden example
 @end defun
 
 @defun thread-yield
@@ -127,15 +136,21 @@ Return a list of all the live thread objects.  A new list 
is returned
 by each invocation.
 @end defun
 
address@hidden main-thread
+This variable keeps the main thread Emacs is running, or @code{nil} if
+Emacs is compiled without thread support.
address@hidden defvar
+
 When code run by a thread signals an error that is unhandled, the
 thread exits.  Other threads can access the error form which caused
 the thread to exit using the following function.
 
address@hidden thread-last-error
address@hidden thread-last-error &optional cleanup
 This function returns the last error form recorded when a thread
 exited due to an error.  Each thread that exits abnormally overwrites
 the form stored by the previous thread's error with a new value, so
-only the last one can be accessed.
+only the last one can be accessed.  If @var{cleanup} is
address@hidden, the stored form is reset to @code{nil}.
 @end defun
 
 @node Mutexes
diff --git a/doc/misc/efaq.texi b/doc/misc/efaq.texi
index 903c56c..5b432d5 100644
--- a/doc/misc/efaq.texi
+++ b/doc/misc/efaq.texi
@@ -2988,7 +2988,7 @@ Emacs compiled on a 64-bit machine can handle much larger 
buffers.
 @cindex Shell buffer, echoed commands and @samp{^M} in
 @cindex Echoed commands in @code{shell-mode}
 
-Try typing @kbd{M-x shell-strip-ctrl-m @key{RET}} while in @code{shell-mode} to
+Try typing @kbd{M-x comint-strip-ctrl-m @key{RET}} while in @code{shell-mode} 
to
 make them go away.  If that doesn't work, you have several options:
 
 For @code{tcsh}, put this in your @file{.cshrc} (or @file{.tcshrc})
@@ -3041,7 +3041,7 @@ characters from the buffer by adding this to your 
@file{.emacs} init
 file:
 
 @smalllisp
-(add-hook 'comint-output-filter-functions 'shell-strip-ctrl-m)
+(add-hook 'comint-output-filter-functions #'comint-strip-ctrl-m)
 @end smalllisp
 
 On a related note: if your shell is echoing your input line in the shell
diff --git a/doc/misc/flymake.texi b/doc/misc/flymake.texi
index bdefd40..bda7e14 100644
--- a/doc/misc/flymake.texi
+++ b/doc/misc/flymake.texi
@@ -4,7 +4,7 @@
 @set VERSION 1.0
 @set UPDATED June 2018
 @settitle GNU Flymake @value{VERSION}
address@hidden ../emacs/docstyle.texi
address@hidden docstyle.texi
 @syncodeindex pg cp
 @syncodeindex vr cp
 @syncodeindex fn cp
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi
index a96f4dd..463f10e 100644
--- a/doc/misc/tramp.texi
+++ b/doc/misc/tramp.texi
@@ -1242,7 +1242,7 @@ improvement is not always true.
 @cindex default user
 
 @defopt tramp-default-user
address@hidden file name can omit the user name part since
+A @value{tramp} file name can omit the user name part since
 @value{tramp} substitutes the currently logged-in user name.  However
 this substitution can be overridden with @code{tramp-default-user}.
 For example:
@@ -1457,7 +1457,7 @@ support this command.
 
 @subsection Tunneling with ssh
 
-With ssh, you could use the @code{ProxyCommand} entry in the
+With ssh, you could use the @code{ProxyCommand} entry in
 @file{~/.ssh/config}:
 
 @example
@@ -1593,12 +1593,12 @@ A function dedicated to @file{/etc/hosts} for host 
names.
 @item @code{tramp-parse-passwd}
 @findex tramp-parse-passwd
 
-A function which parses @file{/etc/passwd} files for user names.
+A function which parses @file{/etc/passwd} for user names.
 
 @item @code{tramp-parse-etc-group}
 @findex tramp-parse-etc-group
 
-A function which parses @file{/etc/group} files for group names.
+A function which parses @file{/etc/group} for group names.
 
 @item @code{tramp-parse-netrc}
 @findex tramp-parse-netrc
@@ -2198,7 +2198,7 @@ of the secretfile is now owned by the user logged in from
 When @code{backup-directory-alist} is @code{nil} (the default), such
 problems do not occur.
 
-To ``turn off'' the backup feature for @value{tramp} files and stop
+To ``turn off'' the backup feature for remote files and stop
 @value{tramp} from saving to the backup directory, use this:
 
 @lisp
@@ -2260,12 +2260,11 @@ The backup file name of
 
 @vindex auto-save-file-name-transforms
 Just as for backup files, similar issues of file naming affect
-auto-saving @value{tramp} files.  Auto-saved files are saved in the
-directory specified by the user option
address@hidden  By default this is set to
-the local temporary directory.  But in some versions of Debian
-GNU/Linux, this points to the source directory where the Emacs was
-compiled.  Reset such values to a valid directory.
+auto-saving remote files.  Auto-saved files are saved in the directory
+specified by the user option @code{auto-save-file-name-transforms}.
+By default this is set to the local temporary directory.  But in some
+versions of Debian GNU/Linux, this points to the source directory
+where the Emacs was compiled.  Reset such values to a valid directory.
 
 Set @code{auto-save-file-name-transforms} to @code{nil} to save
 auto-saved files to the same directory as the original file.
@@ -2769,8 +2768,8 @@ hard-coded, fixed name.  Note that using @code{:0} for 
X11 display name
 here will not work as expected.
 
 An alternate approach is specify @code{ForwardX11 yes} or
address@hidden yes} in the file @file{~/.ssh/config} on the
-local host.
address@hidden yes} in @file{~/.ssh/config} on the local
+host.
 
 
 @subsection Running @code{shell} on a remote host
@@ -3450,6 +3449,19 @@ source "address@hidden@}/.iterm2_shell_integration.bash"
 @end group
 @end example
 
+And finally, bash's readline should not use key bindings like
address@hidden to commands.  Disable this in your @file{~/.inputrc}:
+
address@hidden
address@hidden
+$if term=dumb
+# Don't bind Control-J or it messes up @value{tramp}.
+$else
+"\C-j": next-history
+$endif
address@hidden group
address@hidden example
+
 @item
 Echoed characters after login
 
@@ -3586,13 +3598,13 @@ When testing, ensure the remote shell is the same shell
 How to get notified after @value{tramp} completes file transfers?
 
 Make Emacs beep after reading from or writing to the remote host with
-the following code in @file{~/.emacs} file.
+the following code in @file{~/.emacs}.
 
 @lisp
 @group
 (defadvice tramp-handle-write-region
   (after tramp-write-beep-advice activate)
-  "Make tramp beep after writing a file."
+  "Make @value{tramp} beep after writing a file."
   (interactive)
   (beep))
 @end group
@@ -3600,7 +3612,7 @@ the following code in @file{~/.emacs} file.
 @group
 (defadvice tramp-handle-do-copy-or-rename-file
   (after tramp-copy-beep-advice activate)
-  "Make tramp beep after copying a file."
+  "Make @value{tramp} beep after copying a file."
   (interactive)
   (beep))
 @end group
@@ -3608,7 +3620,7 @@ the following code in @file{~/.emacs} file.
 @group
 (defadvice tramp-handle-insert-file-contents
   (after tramp-insert-beep-advice activate)
-  "Make tramp beep after inserting a file."
+  "Make @value{tramp} beep after inserting a file."
   (interactive)
   (beep))
 @end group
@@ -3646,7 +3658,7 @@ then set them with a hook as follows:
 
 
 @item
-Why is @file{~/.sh_history} file on the remote host growing?
+Why is @file{~/.sh_history} on the remote host growing?
 
 @vindex tramp-histfile-override
 @vindex address@hidden, environment variable}
@@ -3667,7 +3679,7 @@ undesired results when using @command{bash} as remote 
shell.
 Another approach is to disable @value{tramp}'s handling of the
 @env{HISTFILE} at all by setting @code{tramp-histfile-override} to
 @code{nil}.  In this case, saving history could be turned off by
-putting this shell code in the @file{.bashrc} or @file{.kshrc} file:
+putting this shell code in @file{.bashrc} or @file{.kshrc}:
 
 @example
 @group
@@ -3684,7 +3696,7 @@ fi
 @end example
 
 For @option{ssh}-based method, add the following line to your
address@hidden/.ssh/environment} file:
address@hidden/.ssh/environment}:
 
 @example
 HISTFILE=/dev/null
diff --git a/etc/NEWS b/etc/NEWS
index c69bbe9..f1ea835 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -81,14 +81,24 @@ work right without some adjustment:
 - you can use the new 'package-quickstart' so activation of packages does not
   need to pay attention to 'package-load-list' or 'package-user-dir' any more.
 
+---
+** Emacs now notifies systemd when startup finishes or shutdown begins.
+Units that are ordered after 'emacs.service' will only be started
+after Emacs has finished initialization and is ready for use.
+(If your Emacs is installed in a non-standard location and you copied the
+emacs.service file to eg ~/.config/systemd/user/, you will need to copy
+the new version of the file again.)
+
 
 * Changes in Emacs 27.1
 
++++
+** The function 'read-passwd' uses '*' as default character to hide passwords.
+
 ---
 ** New variable 'xft-ignore-color-fonts'.
 Default t means don't try to load color fonts when using Xft, as they
 often cause crashes.  Set it to nil if you really need those fonts.
-(Bug#30874)
 
 ---
 ** The new option 'tooltip-resize-echo-area' avoids truncating tooltip text
@@ -212,6 +222,17 @@ navigation and editing of large files.
 
 * Changes in Specialized Modes and Packages in Emacs 27.1
 
+** Change Logs and VC
+
+*** Recording ChangeLog entries doesn't require an actual file.
+If a ChangeLog file doesn't exist, and if the new variable
+'add-log-dont-create-changelog-file' is non-nil (which is the
+default), commands such as 'C-x 4 a' will add log entries to a
+suitable named temporary buffer.  (An existing ChangeLog file will
+still be used if it exists.)  Set the variable to nil to get the
+previous behavior of always creating a buffer that visits a ChangeLog
+file.
+
 ** diff-mode
 *** Hunks are now automatically refined by default
 To disable it, set the new defcustom 'diff-font-lock-refine' to nil.
@@ -228,6 +249,10 @@ shown in the currently selected window.
 ** Comint
 
 +++
+*** 'send-invisible' is now an obsolete alias for `comint-send-invisible'
+Also, 'shell-strip-ctrl-m' is declared obsolete.
+
++++
 *** 'C-c .' (comint-insert-previous-argument) no longer interprets '&'.
 This feature caused problems when '&&' was present in the previous
 command.  Since this command emulates 'M-.' in Bash and zsh, neither
@@ -244,6 +269,11 @@ better emulate 'M-.' in both Bash and zsh, since the 
former counts
 from the beginning of the arguments, while the latter counts from the
 end.
 
+** Term
+
+---
+*** 'term-read-noecho' is now obsolete, use 'read-passwd' instead.
+
 ** Flymake
 
 +++
@@ -375,6 +405,13 @@ bound to 'C-c C-f'.
 when escaping text and in addition all numeric entities when
 unescaping text.
 
+** Python mode
+
+---
+*** Python mode supports three different font lock decoration levels.
+The maximum level is used by default; customize
+'font-lock-maximum-decoration' to tone down the decoration.
+
 ** Dired
 
 +++
@@ -538,6 +575,11 @@ are obsoleted in GVFS.
 *** The user option 'tramp-ignored-file-name-regexp' allows to disable
 Tramp for some look-alike remote file names.
 
+** Register
+---
+*** The return value of method 'register-val-describe' includes the
+names of buffers shown by the windows of a window configuration.
+
 ---
 ** The options.el library has been removed.
 It was obsolete since Emacs 22.1, replaced by customize.
@@ -546,7 +588,6 @@ It was obsolete since Emacs 22.1, replaced by customize.
 Use of built-in libgnutls based functionality (described in the Emacs
 GnuTLS manual) is recommended instead.
 
-
 ** Message
 
 +++
@@ -592,6 +633,17 @@ If this option is non-nil, messages appended to an output 
file by the
 selects the messages to summarize with a regexp that matches the
 sender of the current message.
 
+** Threads
+
++++
+*** New variable 'main-thread' holds Emacs's main thread.
+This is handy in Lisp programs that run on a non-main thread and want
+to signal the main thread, e.g., when they encounter an error.
+
++++
+*** 'thread-join' returns the result of the finished thread now.
+
+
 * New Modes and Packages in Emacs 27.1
 
 +++
@@ -649,7 +701,7 @@ as new-style, bind the new variable 
'force-new-style-backquotes' to t.
 
 ** When formatting a floating-point number as an octal or hexadecimal
 integer, Emacs now signals an error if the number is too large for the
-implementation to format (Bug#30408).
+implementation to format.
 
 +++
 ** The Lisp reader now signals an overflow for plain decimal integers
@@ -658,7 +710,7 @@ reader silently converted them to floating-point numbers, 
and signaled
 overflow only for integers with a radix that are outside machine range.
 To get the old behavior, set the new, experimental variable
 read-integer-overflow-as-float to t and please email
address@hidden if you need that.  (Bug#30408).
address@hidden if you need that.
 
 ---
 ** Some functions and variables obsolete since Emacs 22 have been removed:
@@ -707,13 +759,15 @@ however applications should instead call 
'display-buffer-in-side-window'
 is backwards-compatible with versions of Emacs in which the old function
 exists.  See the node "Displaying Buffers in Side Windows" in the ELisp
 manual for more details.
+
 
 * Lisp Changes in Emacs 27.1
 
 +++
 ** New function 'proper-list-p'.
 Given a proper list as argument, this predicate returns its length;
-otherwise, it returns nil.
+otherwise, it returns nil.  'format-proper-list-p' is now an obsolete
+alias for the new function.
 
 ** define-minor-mode automatically documents the meaning of ARG
 
@@ -766,6 +820,15 @@ between two strings.
 ** 'print-quoted' now defaults to t, so if you want to see
 (quote x) instead of 'x you will have to bind it to nil where applicable.
 
++++
+** Numbers formatted via %o or %x may now be formatted as signed integers.
+This avoids problems in calls like (read (format "#x%x" -1)), and is
+more compatible with bignums, a planned feature.  To get this
+behavior, set the experimental variable binary-as-unsigned to nil,
+and if the new behavior breaks your code please email
address@hidden  Because %o and %x can now format signed
+integers, they now support the + and space flags.
+
 ** To avoid confusion caused by "smart quotes", the reader signals an
 error when reading Lisp symbols which begin with one of the following
 quotation characters: ‘’‛“”‟〞"'.  A symbol beginning with such a
@@ -790,12 +853,12 @@ The new variable 'comment-use-syntax-ppss' can be set to 
nil to recover the old
 behavior if needed.
 
 ** The 'server-name' and 'server-socket-dir' variables are set when a
-socket has been passed to Emacs (Bug#24218).
+socket has been passed to Emacs.
 
 ---
 ** The 'file-system-info' function is now available on all platforms.
 instead of just Microsoft platforms.  This fixes a 'get-free-disk-space'
-bug on OS X 10.8 and later (Bug#28639).
+bug on OS X 10.8 and later.
 
 +++
 ** 'memory-limit' now returns a better estimate of memory consumption.
@@ -812,12 +875,19 @@ changes and the change hooks are time consuming.
 remote systems, which support this check.
 
 +++
+** 'eql', 'make-hash-table', etc. now treat NaNs consistently.
+Formerly, some of these functions ignored signs and significands of
+NaNs.  Now, all these functions treat NaN signs and significands as
+significant.  For example, (eql 0.0e+NaN -0.0e+NaN) now returns nil
+because the two NaNs have different signs; formerly it returned t.
+
++++
 ** The function 'make-string' accepts an additional optional argument.
 If the optional third argument is non-nil, 'make-string' will produce
 a multibyte string even if its second argument is an ASCII character.
 
 ** (format "%d" X) no longer mishandles a floating-point number X that
-does not fit in a machine integer (Bug#30408).
+does not fit in a machine integer.
 
 ** New JSON parsing and serialization functions 'json-serialize',
 'json-insert', 'json-parse-string', and 'json-parse-buffer'.  These
diff --git a/etc/NEWS.26 b/etc/NEWS.26
index 58b4c4a..a766e96 100644
--- a/etc/NEWS.26
+++ b/etc/NEWS.26
@@ -85,12 +85,20 @@ it now shows the global revision number, in the form of its 
changeset
 hash value.  To get back the previous behavior, customize the new
 option 'vc-hg-symbolic-revision-styles' to the value '("{rev}")'.
 
+---
+** shadowfile.el has been rewritten to support Tramp file names.
+
 
 * New Modes and Packages in Emacs 26.2
 
 
 * Incompatible Lisp Changes in Emacs 26.2
 
+---
+** shadowfile config files have changed their syntax.
+Existing files "~/.emacs.d/shadows" and "~/.emacs.d/shadow_todo" must
+be removed prior using the changed 'shadow-*' commands.
+
 
 * Lisp Changes in Emacs 26.2
 
diff --git a/etc/emacs.service b/etc/emacs.service
index b29177b..dbcb6bc 100644
--- a/etc/emacs.service
+++ b/etc/emacs.service
@@ -7,7 +7,7 @@ Description=Emacs text editor
 Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
 
 [Service]
-Type=simple
+Type=notify
 ExecStart=emacs --fg-daemon
 ExecStop=emacsclient --eval "(kill-emacs)"
 Environment=SSH_AUTH_SOCK=%t/keyring/ssh
diff --git a/lib-src/pop.c b/lib-src/pop.c
index 10aac95..731f951 100644
--- a/lib-src/pop.c
+++ b/lib-src/pop.c
@@ -30,8 +30,12 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "ntlib.h"
 #undef _WIN32_WINNT
 #define _WIN32_WINNT 0x0501    /* for getaddrinfo stuff */
-#include <winsock2.h>
-#include <ws2tcpip.h>
+#if defined __MINGW32_VERSION && __MINGW32_VERSION >= 5000002L
+# include <windows.h>
+#else
+# include <winsock2.h>
+#endif
+# include <ws2tcpip.h>
 #undef getaddrinfo
 #define getaddrinfo  sys_getaddrinfo
 #undef freeaddrinfo
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 3e91738..e623921 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -20,7 +20,123 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib 
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux 
--avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix 
--avoid=msvc-inval --avoid=msvc-nothrow --avoid=openat-die --avoid=opendir 
--avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv 
--avoid=sigprocmask --avoid=stat --avoid=stdarg --avoid=stdbool 
--avoid=threadlib --avoid=tzset --avoid=unsetenv --avoid=utime --avoid=utime-h 
-- [...]
+# Reproduce by:
+# gnulib-tool --import \
+#  --lib=libgnu \
+#  --source-base=lib \
+#  --m4-base=m4 \
+#  --doc-base=doc \
+#  --tests-base=tests \
+#  --aux-dir=build-aux \
+#  --gnu-make \
+#  --makefile-name=gnulib.mk.in \
+#  --conditional-dependencies \
+#  --no-libtool \
+#  --macro-prefix=gl \
+#  --no-vc-files \
+#  --avoid=close \
+#  --avoid=dup \
+#  --avoid=fchdir \
+#  --avoid=fstat \
+#  --avoid=malloc-posix \
+#  --avoid=msvc-inval \
+#  --avoid=msvc-nothrow \
+#  --avoid=openat-die \
+#  --avoid=opendir \
+#  --avoid=raise \
+#  --avoid=save-cwd \
+#  --avoid=select \
+#  --avoid=setenv \
+#  --avoid=sigprocmask \
+#  --avoid=stat \
+#  --avoid=stdarg \
+#  --avoid=stdbool \
+#  --avoid=threadlib \
+#  --avoid=tzset \
+#  --avoid=unsetenv \
+#  --avoid=utime \
+#  --avoid=utime-h \
+#  alloca-opt \
+#  binary-io \
+#  byteswap \
+#  c-ctype \
+#  c-strcase \
+#  careadlinkat \
+#  close-stream \
+#  count-leading-zeros \
+#  count-one-bits \
+#  count-trailing-zeros \
+#  crypto/md5-buffer \
+#  crypto/sha1-buffer \
+#  crypto/sha256-buffer \
+#  crypto/sha512-buffer \
+#  d-type \
+#  diffseq \
+#  dtoastr \
+#  dtotimespec \
+#  dup2 \
+#  environ \
+#  execinfo \
+#  explicit_bzero \
+#  faccessat \
+#  fcntl \
+#  fcntl-h \
+#  fdatasync \
+#  fdopendir \
+#  filemode \
+#  filevercmp \
+#  flexmember \
+#  fpieee \
+#  fstatat \
+#  fsusage \
+#  fsync \
+#  getloadavg \
+#  getopt-gnu \
+#  gettime \
+#  gettimeofday \
+#  gitlog-to-changelog \
+#  ignore-value \
+#  intprops \
+#  largefile \
+#  lstat \
+#  manywarnings \
+#  memrchr \
+#  minmax \
+#  mkostemp \
+#  mktime \
+#  nstrftime \
+#  pipe2 \
+#  pselect \
+#  pthread_sigmask \
+#  putenv \
+#  qcopy-acl \
+#  readlink \
+#  readlinkat \
+#  sig2str \
+#  socklen \
+#  stat-time \
+#  std-gnu11 \
+#  stdalign \
+#  stddef \
+#  stdio \
+#  stpcpy \
+#  strtoimax \
+#  symlink \
+#  sys_stat \
+#  sys_time \
+#  tempname \
+#  time \
+#  time_r \
+#  time_rz \
+#  timegm \
+#  timer-time \
+#  timespec-add \
+#  timespec-sub \
+#  unlocked-io \
+#  update-copyright \
+#  utimens \
+#  vla \
+#  warnings
 
 
 MOSTLYCLEANFILES += core *.stackdump
diff --git a/lisp/auth-source.el b/lisp/auth-source.el
index abff0de..261e972 100644
--- a/lisp/auth-source.el
+++ b/lisp/auth-source.el
@@ -779,7 +779,7 @@ Calls `auth-source-search' with the :delete property in 
SPEC set to t.
 The backend may not actually delete the entries.
 
 Returns the deleted entries."
-  (auth-source-search (plist-put spec :delete t)))
+  (apply #'auth-source-search (plist-put spec :delete t)))
 
 (defun auth-source-search-collection (collection value)
   "Returns t is VALUE is t or COLLECTION is t or COLLECTION contains VALUE."
diff --git a/lisp/bookmark.el b/lisp/bookmark.el
index 78f3e32..58a2794 100644
--- a/lisp/bookmark.el
+++ b/lisp/bookmark.el
@@ -1102,7 +1102,7 @@ BOOKMARK is usually a bookmark name (a string).  It can 
also be a
 bookmark record, but this is usually only done by programmatic callers.
 
 If DISPLAY-FUNC is non-nil, it is a function to invoke to display the
-bookmark.  It defaults to `switch-to-buffer'.  A typical value for
+bookmark.  It defaults to `pop-to-buffer-same-window'.  A typical value for
 DISPLAY-FUNC would be `switch-to-buffer-other-window'."
   (interactive
    (list (bookmark-completing-read "Jump to bookmark"
@@ -1110,7 +1110,10 @@ DISPLAY-FUNC would be `switch-to-buffer-other-window'."
   (unless bookmark
     (error "No bookmark specified"))
   (bookmark-maybe-historicize-string bookmark)
-  (bookmark--jump-via bookmark (or display-func 'switch-to-buffer)))
+  ;; Don't use `switch-to-buffer' because it would let the
+  ;; window-point override the bookmark's point when
+  ;; `switch-to-buffer-preserve-window-point' is non-nil.
+  (bookmark--jump-via bookmark (or display-func 'pop-to-buffer-same-window)))
 
 
 ;;;###autoload
diff --git a/lisp/comint.el b/lisp/comint.el
index 71a2b5e..a9c3e47 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -78,7 +78,7 @@
 ;;
 ;; Not bound by default in comint-mode (some are in shell mode)
 ;; comint-run                          Run a program under comint-mode
-;; send-invisible                      Read a line w/o echo, and send to proc
+;; comint-send-invisible               Read a line w/o echo, and send to proc
 ;; comint-dynamic-complete-filename    Complete filename at point.
 ;; comint-dynamic-list-filename-completions List completions in help buffer.
 ;; comint-replace-by-expanded-filename Expand and complete filename at point;
@@ -632,7 +632,7 @@ Input ring history expansion can be achieved with the 
commands
 Input ring expansion is controlled by the variable `comint-input-autoexpand',
 and addition is controlled by the variable `comint-input-ignoredups'.
 
-Commands with no default key bindings include `send-invisible',
+Commands with no default key bindings include `comint-send-invisible',
 `completion-at-point', `comint-dynamic-list-filename-completions', and
 `comint-magic-space'.
 
@@ -2247,7 +2247,7 @@ This function could be on 
`comint-output-filter-functions' or bound to a key."
        (error nil))
       (while (re-search-forward "\r+$" pmark t)
        (replace-match "" t t)))))
-(defalias 'shell-strip-ctrl-m 'comint-strip-ctrl-m)
+(define-obsolete-function-alias 'shell-strip-ctrl-m #'comint-strip-ctrl-m 
"27.1")
 
 (defun comint-show-maximum-output ()
   "Put the end of the buffer at the bottom of the window."
@@ -2357,9 +2357,9 @@ a buffer local variable."
 
 ;; These three functions are for entering text you don't want echoed or
 ;; saved -- typically passwords to ftp, telnet, or somesuch.
-;; Just enter m-x send-invisible and type in your line.
+;; Just enter m-x comint-send-invisible and type in your line.
 
-(defun send-invisible (&optional prompt)
+(defun comint-send-invisible (&optional prompt)
   "Read a string without echoing.
 Then send it to the process running in the current buffer.
 The string is sent using `comint-input-sender'.
@@ -2382,18 +2382,19 @@ Security bug: your string can still be temporarily 
recovered with
            (message "Warning: text will be echoed")))
       (error "Buffer %s has no process" (current-buffer)))))
 
+(define-obsolete-function-alias 'send-invisible #'comint-send-invisible "27.1")
+
 (defun comint-watch-for-password-prompt (string)
   "Prompt in the minibuffer for password and send without echoing.
-This function uses `send-invisible' to read and send a password to the buffer's
-process if STRING contains a password prompt defined by
-`comint-password-prompt-regexp'.
+Looks for a match to `comint-password-prompt-regexp' in order
+to detect the need to (prompt and) send a password.
 
 This function could be in the list `comint-output-filter-functions'."
   (when (let ((case-fold-search t))
          (string-match comint-password-prompt-regexp string))
     (when (string-match "^[ \n\r\t\v\f\b\a]+" string)
       (setq string (replace-match "" t t string)))
-    (send-invisible string)))
+    (comint-send-invisible string)))
 
 ;; Low-level process communication
 
diff --git a/lisp/emacs-lisp/cl-print.el b/lisp/emacs-lisp/cl-print.el
index 1eae8fa..bf5b1e8 100644
--- a/lisp/emacs-lisp/cl-print.el
+++ b/lisp/emacs-lisp/cl-print.el
@@ -109,7 +109,7 @@ call other entry points instead, such as `cl-prin1'."
   (princ (hash-table-count object) stream)
   (princ "/" stream)
   (princ (hash-table-size object) stream)
-  (princ (format " 0x%x" (sxhash object)) stream)
+  (princ (format " %#x" (sxhash object)) stream)
   (princ ">" stream))
 
 (define-button-type 'help-byte-code
@@ -166,7 +166,7 @@ into a button whose action shows the function's 
disassembly.")
     (let ((button-start (and cl-print-compiled-button
                              (bufferp stream)
                              (with-current-buffer stream (point)))))
-      (princ (format "#<bytecode 0x%x>" (sxhash object)) stream)
+      (princ (format "#<bytecode %#x>" (sxhash object)) stream)
       (when (eq cl-print-compiled 'static)
         (princ " " stream)
         (cl-print-object (aref object 2) stream))
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index 4e5b1a7..6313c63 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -1196,7 +1196,21 @@ ENDPOS is encountered."
                   (if endpos endpos
                     ;; Get error now if we don't have a complete sexp
                     ;; after point.
-                    (save-excursion (forward-sexp 1) (point)))))
+                    (save-excursion
+                      (let ((eol (line-end-position)))
+                        (forward-sexp 1)
+                        ;; We actually look for a sexp which ends
+                        ;; after the current line so that we properly
+                        ;; indent things like #s(...).  This might not
+                        ;; be needed if Bug#15998 is fixed.
+                        (condition-case ()
+                            (while (and (< (point) eol) (not (eobp)))
+                              (forward-sexp 1))
+                          ;; But don't signal an error for incomplete
+                          ;; sexps following the first complete sexp
+                          ;; after point.
+                          (scan-error nil)))
+                      (point)))))
     (save-excursion
       (while (let ((indent (lisp-indent-calc-next parse-state))
                    (ppss (lisp-indent-state-ppss parse-state)))
diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el
index 85e74f2..bb75901 100644
--- a/lisp/emacs-lisp/rx.el
+++ b/lisp/emacs-lisp/rx.el
@@ -1183,24 +1183,28 @@ enclosed in `(and ...)'.
 
 
 (pcase-defmacro rx (&rest regexps)
-  "Build a `pcase' pattern matching `rx' regexps.
-The REGEXPS are interpreted as by `rx'.  The pattern matches if
-the regular expression so constructed matches EXPVAL, as if
-by `string-match'.
+  "Build a `pcase' pattern matching `rx' REGEXPS in sexp form.
+The REGEXPS are interpreted as in `rx'.  The pattern matches any
+string that is a match for the regular expression so constructed,
+as if by `string-match'.
 
 In addition to the usual `rx' constructs, REGEXPS can contain the
 following constructs:
 
-  (let VAR FORM...)  creates a new explicitly numbered submatch
-                     that matches FORM and binds the match to
-                     VAR.
-  (backref VAR)      creates a backreference to the submatch
-                     introduced by a previous (let VAR ...)
-                     construct.
-
-The VARs are associated with explicitly numbered submatches
-starting from 1.  Multiple occurrences of the same VAR refer to
-the same submatch.
+  (let REF SEXP...)  creates a new explicitly named reference to
+                     a submatch that matches regular expressions
+                     SEXP, and binds the match to REF.
+  (backref REF)      creates a backreference to the submatch
+                     introduced by a previous (let REF ...)
+                     construct.  REF can be the same symbol
+                     in the first argument of the corresponding
+                     (let REF ...) construct, or it can be a
+                     submatch number.  It matches the referenced
+                     submatch.
+
+The REFs are associated with explicitly named submatches starting
+from 1.  Multiple occurrences of the same REF refer to the same
+submatch.
 
 If a case matches, the match data is modified as usual so you can
 use it in the case body, but you still have to pass the correct
diff --git a/lisp/env.el b/lisp/env.el
index e47eb57..7007ba3 100644
--- a/lisp/env.el
+++ b/lisp/env.el
@@ -113,11 +113,11 @@ Changes ENV by side-effect, and returns its new value."
             (not keep-empty)
             env
             (stringp (car env))
-            (string-match pattern (car env)))
+             (string-match-p pattern (car env)))
        (cdr env)
       ;; Try to find existing entry for VARIABLE in ENV.
       (while (and scan (stringp (car scan)))
-       (when (string-match pattern (car scan))
+        (when (string-match-p pattern (car scan))
          (if value
              (setcar scan (concat variable "=" value))
            (if keep-empty
@@ -184,7 +184,7 @@ a side-effect."
       (setq variable (encode-coding-string variable locale-coding-system)))
   (if (and value (multibyte-string-p value))
       (setq value (encode-coding-string value locale-coding-system)))
-  (if (string-match "=" variable)
+  (if (string-match-p "=" variable)
       (error "Environment variable name `%s' contains `='" variable))
   (if (string-equal "TZ" variable)
       (set-time-zone-rule value))
diff --git a/lisp/epg-config.el b/lisp/epg-config.el
index 8543498..fb866df 100644
--- a/lisp/epg-config.el
+++ b/lisp/epg-config.el
@@ -98,11 +98,14 @@ Note that the buffer name starts with a space."
   :type 'boolean)
 
 (defconst epg-gpg-minimum-version "1.4.3")
+(defconst epg-gpg2-minimum-version "2.1.6")
 
 (defconst epg-config--program-alist
   `((OpenPGP
      epg-gpg-program
-     ("gpg2" . "2.1.6") ("gpg" . ,epg-gpg-minimum-version))
+     ("gpg2" . ,epg-gpg2-minimum-version)
+     ("gpg" . ((,epg-gpg-minimum-version . "2.0")
+               ,epg-gpg2-minimum-version)))
     (CMS
      epg-gpgsm-program
      ("gpgsm" . "2.0.4")))
@@ -171,13 +174,10 @@ version requirement is met."
 (defun epg-config--make-gpg-configuration (program)
   (let (config groups type args)
     (with-temp-buffer
-      (apply #'call-process program nil
-             (list t (and (boundp 'trace-level) (> trace-level 0))) nil
+      (apply #'call-process program nil (list t nil) nil
             (append (if epg-gpg-home-directory
                         (list "--homedir" epg-gpg-home-directory))
                     '("--with-colons" "--list-config")))
-      (when (and (boundp 'trace-level) (> trace-level 0))
-        (trace-values (concat "gpg output:\n" (buffer-string))))
       (goto-char (point-min))
       (while (re-search-forward "^cfg:\\([^:]+\\):\\(.*\\)" nil t)
        (setq type (intern (match-string 1))
@@ -231,14 +231,26 @@ version requirement is met."
   (epg-config--make-gpg-configuration epg-gpg-program))
 
 ;;;###autoload
-(defun epg-check-configuration (config &optional minimum-version)
-  "Verify that a sufficient version of GnuPG is installed."
+(defun epg-check-configuration (config &optional req-versions)
+  "Verify that a sufficient version of GnuPG is installed.
+CONFIG should be a `epg-configuration' object (a plist).
+REQ-VERSIONS should be a list with elements of the form (MIN
+. MAX) where MIN and MAX are version strings indicating a
+semi-open range of acceptable versions.  REQ-VERSIONS may also be
+a single minimum version string."
   (let ((version (alist-get 'version config)))
     (unless (stringp version)
       (error "Undetermined version: %S" version))
-    (unless (version<= (or minimum-version
-                           epg-gpg-minimum-version)
-                       version)
+    (catch 'version-ok
+      (pcase-dolist ((or `(,min . ,max)
+                         (and min (let max nil)))
+                     (if (listp req-versions) req-versions
+                       (list req-versions)))
+        (when (and (version<= (or min epg-gpg-minimum-version)
+                              version)
+                   (or (null max)
+                       (version< version max)))
+          (throw 'version-ok t)))
       (error "Unsupported version: %s" version))))
 
 ;;;###autoload
diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el
index ec380e6..5180a07 100644
--- a/lisp/eshell/em-dirs.el
+++ b/lisp/eshell/em-dirs.el
@@ -407,6 +407,7 @@ in the minibuffer:
        nil))))
 
 (put 'eshell/cd 'eshell-no-numeric-conversions t)
+(put 'eshell/cd 'eshell-filename-arguments t)
 
 (defun eshell-add-to-dir-ring (path)
   "Add PATH to the last-dir-ring, if applicable."
@@ -470,6 +471,7 @@ in the minibuffer:
   nil)
 
 (put 'eshell/pushd 'eshell-no-numeric-conversions t)
+(put 'eshell/pushd 'eshell-filename-arguments t)
 
 ;;; popd [+n]
 (defun eshell/popd (&rest args)
@@ -500,6 +502,7 @@ in the minibuffer:
   nil)
 
 (put 'eshell/popd 'eshell-no-numeric-conversions t)
+(put 'eshell/pop 'eshell-filename-arguments t)
 
 (defun eshell/dirs (&optional if-verbose)
   "Implementation of dirs in Lisp."
diff --git a/lisp/eshell/em-ls.el b/lisp/eshell/em-ls.el
index 900b289..2b568a9 100644
--- a/lisp/eshell/em-ls.el
+++ b/lisp/eshell/em-ls.el
@@ -334,6 +334,7 @@ instead."
     (apply 'eshell-do-ls args)))
 
 (put 'eshell/ls 'eshell-no-numeric-conversions t)
+(put 'eshell/ls 'eshell-filename-arguments t)
 
 (declare-function eshell-glob-regexp "em-glob" (pattern))
 
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index a18fb85..c912c15 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -307,6 +307,7 @@ Remove (unlink) the FILE(s).")
    nil))
 
 (put 'eshell/rm 'eshell-no-numeric-conversions t)
+(put 'eshell/rm 'eshell-filename-arguments t)
 
 (defun eshell/mkdir (&rest args)
   "Implementation of mkdir in Lisp."
@@ -324,6 +325,7 @@ Create the DIRECTORY(ies), if they do not already exist.")
    nil))
 
 (put 'eshell/mkdir 'eshell-no-numeric-conversions t)
+(put 'eshell/mkdir 'eshell-filename-arguments t)
 
 (defun eshell/rmdir (&rest args)
   "Implementation of rmdir in Lisp."
@@ -340,6 +342,7 @@ Remove the DIRECTORY(ies), if they are empty.")
    nil))
 
 (put 'eshell/rmdir 'eshell-no-numeric-conversions t)
+(put 'eshell/rmdir 'eshell-filename-arguments t)
 
 (defvar no-dereference)
 
@@ -524,6 +527,7 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
                             eshell-mv-overwrite-files))))
 
 (put 'eshell/mv 'eshell-no-numeric-conversions t)
+(put 'eshell/mv 'eshell-filename-arguments t)
 
 (defun eshell/cp (&rest args)
   "Implementation of cp in Lisp."
@@ -561,6 +565,7 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
                           eshell-cp-overwrite-files preserve)))
 
 (put 'eshell/cp 'eshell-no-numeric-conversions t)
+(put 'eshell/cp 'eshell-filename-arguments t)
 
 (defun eshell/ln (&rest args)
   "Implementation of ln in Lisp."
@@ -593,6 +598,7 @@ with `--symbolic'.  When creating hard links, each TARGET 
must exist.")
                             eshell-ln-overwrite-files))))
 
 (put 'eshell/ln 'eshell-no-numeric-conversions t)
+(put 'eshell/ln 'eshell-filename-arguments t)
 
 (defun eshell/cat (&rest args)
   "Implementation of cat in Lisp.
@@ -645,6 +651,7 @@ Concatenate FILE(s), or standard input, to standard 
output.")
      (setq eshell-ensure-newline-p nil))))
 
 (put 'eshell/cat 'eshell-no-numeric-conversions t)
+(put 'eshell/cat 'eshell-filename-arguments t)
 
 ;; special front-end functions for compilation-mode buffers
 
@@ -927,6 +934,8 @@ Summarize disk usage of each FILE, recursively for 
directories.")
             (eshell-print (concat (eshell-du-size-string size)
                                   "total\n"))))))))
 
+(put 'eshell/du 'eshell-filename-arguments t)
+
 (defvar eshell-time-start nil)
 
 (defun eshell-show-elapsed-time ()
@@ -1029,6 +1038,7 @@ Show wall-clock time elapsed during execution of 
COMMAND.")
   nil)
 
 (put 'eshell/diff 'eshell-no-numeric-conversions t)
+(put 'eshell/diff 'eshell-filename-arguments t)
 
 (defvar locate-history-list)
 
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 61c0ebc..92cac61 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -1304,27 +1304,36 @@ messages, and errors."
   "Insert Lisp OBJECT, using ARGS if a function."
   (catch 'eshell-external               ; deferred to an external command
     (let* ((eshell-ensure-newline-p (eshell-interactive-output-p))
-          (result
-           (if (functionp object)
-               (progn
-                 (setq eshell-last-arguments args
-                       eshell-last-command-name
-                       (concat "#<function " (symbol-name object) ">"))
-                 ;; if any of the arguments are flagged as numbers
-                 ;; waiting for conversion, convert them now
-                 (unless (get object 'eshell-no-numeric-conversions)
-                   (while args
-                     (let ((arg (car args)))
-                       (if (and (stringp arg)
-                                (> (length arg) 0)
-                                (not (text-property-not-all
-                                      0 (length arg) 'number t arg)))
-                           (setcar args (string-to-number arg))))
-                     (setq args (cdr args))))
-                 (eshell-apply object eshell-last-arguments))
-             (setq eshell-last-arguments args
-                   eshell-last-command-name "#<Lisp object>")
-             (eshell-eval object))))
+           (result
+            (if (functionp object)
+                (progn
+                  (setq eshell-last-arguments args
+                        eshell-last-command-name
+                        (concat "#<function " (symbol-name object) ">"))
+                  (let ((numeric (not (get object
+                                           'eshell-no-numeric-conversions)))
+                        (fname-args (get object 'eshell-filename-arguments)))
+                    (when (or numeric fname-args)
+                      (while args
+                        (let ((arg (car args)))
+                          (cond ((and numeric (stringp arg) (> (length arg) 0)
+                                      (text-property-any 0 (length arg)
+                                                         'number t arg))
+                                 ;; If any of the arguments are
+                                 ;; flagged as numbers waiting for
+                                 ;; conversion, convert them now.
+                                 (setcar args (string-to-number arg)))
+                                ((and fname-args (stringp arg)
+                                      (string-equal arg "~"))
+                                 ;; If any of the arguments match "~",
+                                 ;; prepend "./" to treat it as a
+                                 ;; regular file name.
+                                 (setcar args (concat "./" arg)))))
+                        (setq args (cdr args)))))
+                  (eshell-apply object eshell-last-arguments))
+              (setq eshell-last-arguments args
+                    eshell-last-command-name "#<Lisp object>")
+              (eshell-eval object))))
       (if (and eshell-ensure-newline-p
               (save-excursion
                 (goto-char eshell-last-output-end)
diff --git a/lisp/eshell/esh-ext.el b/lisp/eshell/esh-ext.el
index ba5182d..244cc7f 100644
--- a/lisp/eshell/esh-ext.el
+++ b/lisp/eshell/esh-ext.el
@@ -259,6 +259,7 @@ Adds the given PATH to $PATH.")
        (eshell-printn dir)))))
 
 (put 'eshell/addpath 'eshell-no-numeric-conversions t)
+(put 'eshell/addpath 'eshell-filename-arguments t)
 
 (defun eshell-script-interpreter (file)
   "Extract the script to run from FILE, if it has #!<interp> in it.
diff --git a/lisp/files.el b/lisp/files.el
index eabb3c0..6e4f6ca 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1830,7 +1830,7 @@ killed."
           ;; Don't use `find-file' because it may end up using another window
           ;; in some corner cases, e.g. when the selected window is
           ;; softly-dedicated.
-         (let ((newbuf (find-file-noselect filename wildcards)))
+         (let ((newbuf (find-file-noselect filename nil nil wildcards)))
             (switch-to-buffer newbuf)))
       (when (eq obuf (current-buffer))
        ;; This executes if find-file gets an error
@@ -1954,7 +1954,7 @@ started Emacs, set `abbreviated-home-dir' to nil so it 
will be recalculated)."
                         (save-match-data
                           (string-match "^[a-zA-`]:/$" filename))))
                (equal (get 'abbreviated-home-dir 'home)
-                      (expand-file-name "~")))
+                      (save-match-data (expand-file-name "~"))))
          (setq filename
                (concat "~"
                        (match-string 1 filename)
diff --git a/lisp/format.el b/lisp/format.el
index 5bf1be3..49d3c71 100644
--- a/lisp/format.el
+++ b/lisp/format.el
@@ -539,6 +539,8 @@ Compare using `equal'."
        (setq tail next)))
     (cons acopy bcopy)))
 
+(define-obsolete-function-alias 'format-proper-list-p 'proper-list-p "27.1")
+
 (defun format-reorder (items order)
   "Arrange ITEMS to follow partial ORDER.
 Elements of ITEMS equal to elements of ORDER will be rearranged
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index 055f02f..1b0dde9 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -1626,6 +1626,12 @@ resources when reading email groups (and therefore stops
 tracking), but allows loading external resources when reading
 from NNTP newsgroups and the like.
 
+People controlling these external resources won't be able to tell
+that any one person in particular has read the message (since
+it's in a public venue, many people will end up loading that
+resource), but they'll be able to tell that somebody from your IP
+address has accessed the resource.
+
 This can also be a function to be evaluated.  If so, it will be
 called with the group name as the parameter, and should return a
 regexp."
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el
index e562b30..ceb9842 100644
--- a/lisp/gnus/gnus-sum.el
+++ b/lisp/gnus/gnus-sum.el
@@ -4310,10 +4310,10 @@ If SELECT-ARTICLES, only select those articles from 
GROUP."
 If FORCE-NEW is not nil, enter HEADER into the DEPENDENCIES table even
 if it was already present.
 
-If `gnus-summary-ignore-duplicates' is nil then duplicate Message-IDs
-will not be entered in the DEPENDENCIES table.  Otherwise duplicate
-Message-IDs will be renamed to a unique Message-ID before being
-entered.
+If `gnus-summary-ignore-duplicates' is non-nil then duplicate
+Message-IDs will not be entered in the DEPENDENCIES table.
+Otherwise duplicate Message-IDs will be renamed to a unique
+Message-ID before being entered.
 
 Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
   (let* ((id (mail-header-id header))
diff --git a/lisp/ielm.el b/lisp/ielm.el
index b4ad69e..8d1efcd 100644
--- a/lisp/ielm.el
+++ b/lisp/ielm.el
@@ -612,17 +612,19 @@ Customized bindings may be defined in `ielm-map', which 
currently contains:
 ;;; User command
 
 ;;;###autoload
-(defun ielm nil
+(defun ielm (&optional buf-name)
   "Interactively evaluate Emacs Lisp expressions.
-Switches to the buffer `*ielm*', or creates it if it does not exist.
+Switches to the buffer named BUF-NAME if provided (`*ielm*' by default),
+or creates it if it does not exist.
 See `inferior-emacs-lisp-mode' for details."
   (interactive)
-  (let (old-point)
-    (unless (comint-check-proc "*ielm*")
-      (with-current-buffer (get-buffer-create "*ielm*")
+  (let (old-point
+        (buf-name (or buf-name "*ielm*")))
+    (unless (comint-check-proc buf-name)
+      (with-current-buffer (get-buffer-create buf-name)
         (unless (zerop (buffer-size)) (setq old-point (point)))
         (inferior-emacs-lisp-mode)))
-    (pop-to-buffer-same-window "*ielm*")
+    (pop-to-buffer-same-window buf-name)
     (when old-point (push-mark old-point))))
 
 (provide 'ielm)
diff --git a/lisp/imenu.el b/lisp/imenu.el
index edca51e..7285b10 100644
--- a/lisp/imenu.el
+++ b/lisp/imenu.el
@@ -832,15 +832,14 @@ depending on PATTERNS."
     (dolist (item index-alist)
       (when (listp item)
        (setcdr item (sort (cdr item) 'imenu--sort-by-position))))
-    (let ((main-element (assq nil index-alist)))
-      (nconc (delq main-element (delq 'dummy index-alist))
-             (cdr main-element)))
     ;; Remove any empty menus.  That can happen because of skipping
     ;; things inside comments or strings.
-    (when (consp (car index-alist))
-      (setq index-alist  (cl-delete-if-not
-                          (lambda (it) (cdr it))
-                          index-alist)))))
+    (setq index-alist (cl-delete-if
+                       (lambda (it) (and (consp it) (null (cdr it))))
+                       index-alist))
+    (let ((main-element (assq nil index-alist)))
+      (nconc (delq main-element (delq 'dummy index-alist))
+             (cdr main-element)))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
diff --git a/lisp/indent.el b/lisp/indent.el
index 4506321..73a7d0e 100644
--- a/lisp/indent.el
+++ b/lisp/indent.el
@@ -292,7 +292,8 @@ indentation by specifying a large negative ARG."
   "Indent current line to COLUMN.
 This function removes or adds spaces and tabs at beginning of line
 only if necessary.  It leaves point at end of indentation."
-  (back-to-indentation)
+  (beginning-of-line 1)
+  (skip-chars-forward " \t")
   (let ((cur-col (current-column)))
     (cond ((< cur-col column)
           (if (>= (- column (* (/ cur-col tab-width) tab-width)) tab-width)
@@ -303,8 +304,10 @@ only if necessary.  It leaves point at end of indentation."
            (delete-region (progn (move-to-column column t) (point))
                           ;; The `move-to-column' call may replace
                           ;; tabs with spaces, so we can't reuse the
-                          ;; previous `back-to-indentation' point.
-                          (progn (back-to-indentation) (point)))))))
+                          ;; previous start point.
+                          (progn (beginning-of-line 1)
+                                 (skip-chars-forward " \t")
+                                 (point)))))))
 
 (defun current-left-margin ()
   "Return the left margin to use for this line.
diff --git a/lisp/international/fontset.el b/lisp/international/fontset.el
index a023d4f..d4ade3c 100644
--- a/lisp/international/fontset.el
+++ b/lisp/international/fontset.el
@@ -79,7 +79,7 @@
        ("cns11643.92p7-0" . chinese-cns11643-7)
        ("big5" . big5)
        ("viscii" . viscii)
-       ("tis620" . tis620-2533)
+       ("tis620" . thai-iso8859-11)
        ("microsoft-cp1251" . windows-1251)
        ("koi8-r" . koi8-r)
        ("jisx0213.2000-1" . japanese-jisx0213-1)
@@ -139,7 +139,7 @@
        (cyrillic-iso8859-5 . iso-8859-5)
        (greek-iso8859-7 . iso-8859-7)
        (arabic-iso8859-6 . iso-8859-6)
-       (thai-tis620 . tis620-2533)
+       (thai-tis620 . thai-iso8859-11)
        (latin-jisx0201 . jisx0201)
        (katakana-jisx0201 . jisx0201)
        (chinese-big5-1 . big5)
@@ -1233,11 +1233,12 @@ Done when `mouse-set-font' is called."
     (latin-iso8859-15 . latin)
     (latin-iso8859-16 . latin)
     (latin-jisx0201 . latin)
+    (thai-iso8859-11 . thai)
     (thai-tis620 . thai)
     (cyrillic-iso8859-5 . cyrillic)
     (arabic-iso8859-6 . arabic)
-    (greek-iso8859-7 . latin)
-    (hebrew-iso8859-8 . latin)
+    (greek-iso8859-7 . greek)
+    (hebrew-iso8859-8 . hebrew)
     (katakana-jisx0201 . kana)
     (chinese-gb2312 . han)
     (chinese-gbk . han)
diff --git a/lisp/international/mule-conf.el b/lisp/international/mule-conf.el
index dc09570..a635c67 100644
--- a/lisp/international/mule-conf.el
+++ b/lisp/international/mule-conf.el
@@ -201,6 +201,7 @@
 ;; plus nbsp
 (define-iso-single-byte-charset 'iso-8859-11 'thai-iso8859-11
   "ISO/IEC 8859/11" "Latin/Thai" 166 ?T nil "8859-11")
+(define-charset-alias 'tis620-2533 'thai-iso8859-11)
 
 ;; 8859-12 doesn't (yet?) exist.
 
@@ -229,14 +230,6 @@
   :code-space [32 127]
   :code-offset #x0E00)
 
-;; Fixme: doc for this, c.f. above
-(define-charset 'tis620-2533
-  "TIS620.2533"
-  :short-name "TIS620.2533"
-  :ascii-compatible-p t
-  :code-space [0 255]
-  :superset '(ascii eight-bit-control (thai-tis620 . 128)))
-
 (define-charset 'jisx0201
   "JISX0201"
   :short-name "JISX0201"
diff --git a/lisp/international/mule-diag.el b/lisp/international/mule-diag.el
index 87a2e99..c9829e3 100644
--- a/lisp/international/mule-diag.el
+++ b/lisp/international/mule-diag.el
@@ -355,7 +355,8 @@ meanings of these arguments."
                     (:iso-revision-number "ISO revision number: "
                                           number-to-string)
                     (:supplementary-p
-                     "Used only as a parent of some other charset." nil)))
+                     "Used only as a parent or a subset of some other charset,
+or provided just for backward compatibility." nil)))
        (let ((val (get-charset-property charset (car elt))))
          (when val
            (if (cadr elt) (insert (cadr elt)))
diff --git a/lisp/international/quail.el b/lisp/international/quail.el
index eece836..ec15cca 100644
--- a/lisp/international/quail.el
+++ b/lisp/international/quail.el
@@ -1394,12 +1394,13 @@ Return the input string."
             (generated-events nil)     ;FIXME: What is this?
             (input-method-function nil)
             (modified-p (buffer-modified-p))
-            last-command-event last-command this-command)
+            last-command-event last-command this-command inhibit-record)
        (setq quail-current-key ""
              quail-current-str ""
              quail-translating t)
        (if key
-           (setq unread-command-events (cons key unread-command-events)))
+           (setq unread-command-events (cons key unread-command-events)
+                  inhibit-record t))
        (while quail-translating
          (set-buffer-modified-p modified-p)
          (quail-show-guidance)
@@ -1408,8 +1409,13 @@ Return the input string."
                                     (or input-method-previous-message "")
                                     quail-current-str
                                     quail-guidance-str)))
+                 ;; We inhibit record_char only for the first key,
+                 ;; because it was already recorded before read_char
+                 ;; called quail-input-method.
+                 (inhibit--record-char inhibit-record)
                 (keyseq (read-key-sequence prompt nil nil t))
                 (cmd (lookup-key (quail-translation-keymap) keyseq)))
+            (setq inhibit-record nil)
            (if (if key
                    (and (commandp cmd) (not (eq cmd 'quail-other-command)))
                  (eq cmd 'quail-self-insert-command))
@@ -1453,14 +1459,15 @@ Return the input string."
             (generated-events nil)     ;FIXME: What is this?
             (input-method-function nil)
             (modified-p (buffer-modified-p))
-            last-command-event last-command this-command)
+            last-command-event last-command this-command inhibit-record)
        (setq quail-current-key ""
              quail-current-str ""
              quail-translating t
              quail-converting t
              quail-conversion-str "")
        (if key
-           (setq unread-command-events (cons key unread-command-events)))
+           (setq unread-command-events (cons key unread-command-events)
+                  inhibit-record t))
        (while quail-converting
          (set-buffer-modified-p modified-p)
          (or quail-translating
@@ -1476,8 +1483,13 @@ Return the input string."
                                     quail-conversion-str
                                     quail-current-str
                                     quail-guidance-str)))
+                 ;; We inhibit record_char only for the first key,
+                 ;; because it was already recorded before read_char
+                 ;; called quail-input-method.
+                 (inhibit--record-char inhibit-record)
                 (keyseq (read-key-sequence prompt nil nil t))
                 (cmd (lookup-key (quail-conversion-keymap) keyseq)))
+            (setq inhibit-record nil)
            (if (if key (commandp cmd) (eq cmd 'quail-self-insert-command))
                (progn
                  (setq last-command-event (aref keyseq (1- (length keyseq)))
diff --git a/lisp/language/thai.el b/lisp/language/thai.el
index a896fe5..c655845 100644
--- a/lisp/language/thai.el
+++ b/lisp/language/thai.el
@@ -36,7 +36,7 @@
   "8-bit encoding for ASCII (MSB=0) and Thai TIS620 (MSB=1)."
   :coding-type 'charset
   :mnemonic ?T
-  :charset-list '(tis620-2533))
+  :charset-list '(thai-iso8859-11))
 
 (define-coding-system-alias 'th-tis620 'thai-tis620)
 (define-coding-system-alias 'tis620 'thai-tis620)
@@ -47,7 +47,7 @@
          (charset thai-tis620)
          (coding-system thai-tis620 iso-8859-11 cp874)
          (coding-priority thai-tis620)
-         (nonascii-translation . tis620-2533)
+         (nonascii-translation . iso-8859-11)
          (input-method . "thai-kesmanee")
          (unibyte-display . thai-tis620)
          (features thai-util)
diff --git a/lisp/net/rlogin.el b/lisp/net/rlogin.el
index 3bfc4d7..015e04f 100644
--- a/lisp/net/rlogin.el
+++ b/lisp/net/rlogin.el
@@ -1,4 +1,4 @@
-;;; rlogin.el --- remote login interface
+;;; rlogin.el --- remote login interface  -*- lexical-binding:t -*-
 
 ;; Copyright (C) 1992-1995, 1997-1998, 2001-2018 Free Software
 ;; Foundation, Inc.
@@ -30,9 +30,9 @@
 ;; tracking and the sending of some special characters.
 
 ;; If you wish for rlogin mode to prompt you in the minibuffer for
-;; passwords when a password prompt appears, just enter m-x send-invisible
-;; and type in your line, or add `comint-watch-for-password-prompt' to
-;; `comint-output-filter-functions'.
+;; passwords when a password prompt appears, just enter
+;; M-x comint-send-invisible and type in your line (or tweak
+;; `comint-password-prompt-regexp' to match your password prompt).
 
 ;;; Code:
 
diff --git a/lisp/net/soap-client.el b/lisp/net/soap-client.el
index 17f8308..f5de05d 100644
--- a/lisp/net/soap-client.el
+++ b/lisp/net/soap-client.el
@@ -685,14 +685,17 @@ This is a specialization of `soap-decode-type' for
         (anyType (soap-decode-any-type node))
         (Array (soap-decode-array node))))))
 
-(defun soap-type-of (element)
-  "Return the type of ELEMENT."
-  ;; Support Emacs < 26 byte-code running in Emacs >= 26 sessions
-  ;; (Bug#31742).
-  (let ((type (type-of element)))
-    (if (eq type 'vector)
-        (aref element 0) ; For Emacs 25 and earlier.
-      type)))
+(defalias 'soap-type-of
+  (if (eq 'soap-xs-basic-type (type-of (make-soap-xs-basic-type)))
+      ;; `type-of' in Emacs ≥ 26 already does what we need.
+      #'type-of
+    ;; For Emacs < 26, use our own function.
+    (lambda (element)
+      "Return the type of ELEMENT."
+      (if (vectorp element)
+          (aref element 0)            ;Assume this vector is actually a struct!
+        ;; This should never happen.
+        (type-of element)))))
 
 ;; Register methods for `soap-xs-basic-type'
 (let ((tag (soap-type-of (make-soap-xs-basic-type))))
@@ -2881,6 +2884,8 @@ reference multiRef parts which are external to 
RESPONSE-NODE."
 
 ;;;; SOAP type encoding
 
+;; FIXME: Use `cl-defmethod' (but this requires Emacs-25).
+
 (defun soap-encode-attributes (value type)
   "Encode XML attributes for VALUE according to TYPE.
 This is a generic function which determines the attribute encoder
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index d56b09a..1af2def 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -3567,16 +3567,20 @@ support symbolic links."
     ;; First, we must replace environment variables.
     (setq filename (tramp-replace-environment-variables filename))
     (with-parsed-tramp-file-name filename nil
-      ;; We do not want to replace environment variables, again.
+      ;; We do not want to replace environment variables, again.  "//"
+      ;; has a special meaning at the beginning of a file name on
+      ;; Cygwin and MS-Windows, we must remove it.
       (let (process-environment)
        ;; Ignore in LOCALNAME everything before "//" or "/~".
        (when (stringp localname)
          (if (string-match "//\\(/\\|~\\)" localname)
-             (setq filename (substitute-in-file-name localname))
+             (setq filename
+                    (replace-regexp-in-string
+                     "\\`/+" "/" (substitute-in-file-name localname)))
            (setq filename
                  (concat (file-remote-p filename)
-                         (tramp-run-real-handler
-                          'substitute-in-file-name (list localname)))))))
+                         (replace-regexp-in-string
+                           "\\`/+" "/" (substitute-in-file-name 
localname)))))))
       ;; "/m:h:~" does not work for completion.  We use "/m:h:~/".
       (if (and (stringp localname) (string-equal "~" localname))
          (concat filename "/")
diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el
index 0b83afc..9bc8768 100644
--- a/lisp/net/trampver.el
+++ b/lisp/net/trampver.el
@@ -69,7 +69,7 @@
         ("2.2.9-24.4" . "24.4") ("2.2.11-24.5" . "24.5")
         ("2.2.13.25.1" . "25.1") ("2.2.13.25.2" . "25.2")
         ("2.2.13.25.2" . "25.3")
-        ("2.3.3.26.1" . "26.1")))
+        ("2.3.3.26.1" . "26.1") ("2.3.4.26.2" . "26.2")))
 
 (add-hook 'tramp-unload-hook
          (lambda ()
diff --git a/lisp/profiler.el b/lisp/profiler.el
index eaeb697..41dea68 100644
--- a/lisp/profiler.el
+++ b/lisp/profiler.el
@@ -105,13 +105,13 @@
   "Format ENTRY in human readable string.  ENTRY would be a
 function name of a function itself."
   (cond ((memq (car-safe entry) '(closure lambda))
-        (format "#<lambda 0x%x>" (sxhash entry)))
+        (format "#<lambda %#x>" (sxhash entry)))
        ((byte-code-function-p entry)
-        (format "#<compiled 0x%x>" (sxhash entry)))
+        (format "#<compiled %#x>" (sxhash entry)))
        ((or (subrp entry) (symbolp entry) (stringp entry))
         (format "%s" entry))
        (t
-        (format "#<unknown 0x%x>" (sxhash entry)))))
+        (format "#<unknown %#x>" (sxhash entry)))))
 
 (defun profiler-fixup-entry (entry)
   (if (symbolp entry)
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 3961ea6..d1eb3c3 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -12607,7 +12607,11 @@ comment at the start of cc-engine.el for more info."
                 (= (point) containing-sexp)))
          (if (eq (point) (c-point 'boi))
              (c-add-syntax 'brace-list-close (point))
-           (setq lim (c-most-enclosing-brace state-cache (point)))
+           (setq lim (or (save-excursion
+                           (and
+                            (c-back-over-member-initializers)
+                            (point)))
+                         (c-most-enclosing-brace state-cache (point))))
            (c-beginning-of-statement-1 lim nil nil t)
            (c-add-stmt-syntax 'brace-list-close nil t lim paren-state)))
 
@@ -12636,7 +12640,11 @@ comment at the start of cc-engine.el for more info."
              (goto-char containing-sexp))
            (if (eq (point) (c-point 'boi))
                (c-add-syntax 'brace-list-intro (point))
-             (setq lim (c-most-enclosing-brace state-cache (point)))
+             (setq lim (or (save-excursion
+                             (and
+                              (c-back-over-member-initializers)
+                              (point)))
+                           (c-most-enclosing-brace state-cache (point))))
              (c-beginning-of-statement-1 lim)
              (c-add-stmt-syntax 'brace-list-intro nil t lim paren-state)))
 
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 58a58b4..f694252 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -45,7 +45,7 @@ It has `lisp-mode-abbrev-table' as its parent."
   "Syntax table used in `emacs-lisp-mode'.")
 
 (defvar emacs-lisp-mode-map
-  (let ((map (make-sparse-keymap "Emacs-Lisp"))
+  (let ((map (make-sparse-keymap))
        (menu-map (make-sparse-keymap "Emacs-Lisp"))
        (lint-map (make-sparse-keymap))
        (prof-map (make-sparse-keymap))
diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el
index ce7127a..24ad2ff 100644
--- a/lisp/progmodes/hideif.el
+++ b/lisp/progmodes/hideif.el
@@ -1625,7 +1625,7 @@ not be expanded."
          ((integerp result)
           (if (or (= 0 result) (= 1 result))
               (message "%S <= `%s'" result exprstring)
-            (message "%S (0x%x) <= `%s'" result result exprstring)))
+            (message "%S (%#x) <= `%s'" result result exprstring)))
          ((null result) (message "%S <= `%s'" 'false exprstring))
          ((eq t result) (message "%S <= `%s'" 'true exprstring))
          (t (message "%S <= `%s'" result exprstring)))
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index e39ff08..c55b69e 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -526,9 +526,19 @@ The type returned can be `comment', `string' or `paren'."
         font-lock-string-face)
     font-lock-comment-face))
 
-(defvar python-font-lock-keywords
-  ;; Keywords
-  `(,(rx symbol-start
+(defvar python-font-lock-keywords-level-1
+  `((,(rx symbol-start "def" (1+ space) (group (1+ (or word ?_))))
+     (1 font-lock-function-name-face))
+    (,(rx symbol-start "class" (1+ space) (group (1+ (or word ?_))))
+     (1 font-lock-type-face)))
+  "Font lock keywords to use in python-mode for level 1 decoration.
+
+This is the minimum decoration level, including function and
+class declarations.")
+
+(defvar python-font-lock-keywords-level-2
+  `(,@python-font-lock-keywords-level-1
+    ,(rx symbol-start
          (or
           "and" "del" "from" "not" "while" "as" "elif" "global" "or" "with"
           "assert" "else" "if" "pass" "yield" "break" "except" "import" "class"
@@ -548,12 +558,35 @@ The type returned can be `comment', `string' or `paren'."
           ;; Extra:
           "self")
          symbol-end)
-    ;; functions
-    (,(rx symbol-start "def" (1+ space) (group (1+ (or word ?_))))
-     (1 font-lock-function-name-face))
-    ;; classes
-    (,(rx symbol-start "class" (1+ space) (group (1+ (or word ?_))))
-     (1 font-lock-type-face))
+    ;; Builtins
+    (,(rx symbol-start
+          (or
+           "abs" "all" "any" "bin" "bool" "callable" "chr" "classmethod"
+           "compile" "complex" "delattr" "dict" "dir" "divmod" "enumerate"
+           "eval" "filter" "float" "format" "frozenset" "getattr" "globals"
+           "hasattr" "hash" "help" "hex" "id" "input" "int" "isinstance"
+           "issubclass" "iter" "len" "list" "locals" "map" "max" "memoryview"
+           "min" "next" "object" "oct" "open" "ord" "pow" "print" "property"
+           "range" "repr" "reversed" "round" "set" "setattr" "slice" "sorted"
+           "staticmethod" "str" "sum" "super" "tuple" "type" "vars" "zip"
+           "__import__"
+           ;; Python 2:
+           "basestring" "cmp" "execfile" "file" "long" "raw_input" "reduce"
+           "reload" "unichr" "unicode" "xrange" "apply" "buffer" "coerce"
+           "intern"
+           ;; Python 3:
+           "ascii" "bytearray" "bytes" "exec"
+           ;; Extra:
+           "__all__" "__doc__" "__name__" "__package__")
+          symbol-end) . font-lock-builtin-face))
+  "Font lock keywords to use in python-mode for level 2 decoration.
+
+This is the medium decoration level, including everything in
+`python-font-lock-keywords-level-1', as well as keywords and
+builtins.")
+
+(defvar python-font-lock-keywords-maximum-decoration
+  `(,@python-font-lock-keywords-level-2
     ;; Constants
     (,(rx symbol-start
           (or
@@ -596,27 +629,6 @@ The type returned can be `comment', `string' or `paren'."
            "VMSError" "WindowsError"
            )
           symbol-end) . font-lock-type-face)
-    ;; Builtins
-    (,(rx symbol-start
-          (or
-           "abs" "all" "any" "bin" "bool" "callable" "chr" "classmethod"
-           "compile" "complex" "delattr" "dict" "dir" "divmod" "enumerate"
-           "eval" "filter" "float" "format" "frozenset" "getattr" "globals"
-           "hasattr" "hash" "help" "hex" "id" "input" "int" "isinstance"
-           "issubclass" "iter" "len" "list" "locals" "map" "max" "memoryview"
-           "min" "next" "object" "oct" "open" "ord" "pow" "print" "property"
-           "range" "repr" "reversed" "round" "set" "setattr" "slice" "sorted"
-           "staticmethod" "str" "sum" "super" "tuple" "type" "vars" "zip"
-           "__import__"
-           ;; Python 2:
-           "basestring" "cmp" "execfile" "file" "long" "raw_input" "reduce"
-           "reload" "unichr" "unicode" "xrange" "apply" "buffer" "coerce"
-           "intern"
-           ;; Python 3:
-           "ascii" "bytearray" "bytes" "exec"
-           ;; Extra:
-           "__all__" "__doc__" "__name__" "__package__")
-          symbol-end) . font-lock-builtin-face)
     ;; assignments
     ;; support for a = b = c = 5
     (,(lambda (limit)
@@ -640,7 +652,26 @@ The type returned can be `comment', `string' or `paren'."
                       (goto-char (match-end 1))
                       (python-syntax-context 'paren)))
           res))
-     (1 font-lock-variable-name-face nil nil))))
+     (1 font-lock-variable-name-face nil nil)))
+  "Font lock keywords to use in python-mode for maximum decoration.
+
+This decoration level includes everything in
+`python-font-lock-keywords-level-2', as well as constants,
+decorators, exceptions, and assignments.")
+
+(defvar python-font-lock-keywords
+  '(python-font-lock-keywords-level-1   ; When `font-lock-maximum-decoration' 
is nil.
+    python-font-lock-keywords-level-1   ; When `font-lock-maximum-decoration' 
is 1.
+    python-font-lock-keywords-level-2   ; When `font-lock-maximum-decoration' 
is 2.
+    python-font-lock-keywords-maximum-decoration ; When 
`font-lock-maximum-decoration'
+                                                 ; is more than 1, or t (which 
it is,
+                                                 ; by default).
+    )
+  "List of font lock keyword specifications to use in python-mode.
+
+Which one will be chosen depends on the value of
+`font-lock-maximum-decoration'.")
+
 
 (defconst python-syntax-propertize-function
   (syntax-propertize-rules
@@ -5325,7 +5356,7 @@ REPORT-FN is Flymake's callback function."
        'python-nav-forward-sexp)
 
   (set (make-local-variable 'font-lock-defaults)
-       '(python-font-lock-keywords
+       `(,python-font-lock-keywords
          nil nil nil nil
          (font-lock-syntactic-face-function
           . python-font-lock-syntactic-face-function)))
diff --git a/lisp/progmodes/subword.el b/lisp/progmodes/subword.el
index ed71b86..685e171 100644
--- a/lisp/progmodes/subword.el
+++ b/lisp/progmodes/subword.el
@@ -110,9 +110,7 @@ called a `subword'.  Here are some examples:
   NSGraphicsContext  =>  \"NS\", \"Graphics\" and \"Context\"
 
 This mode changes the definition of a word so that word commands
-treat nomenclature boundaries as word boundaries.
-
-\\{subword-mode-map}"
+treat nomenclature boundaries as word boundaries."
     :lighter " ,"
     (when subword-mode (superword-mode -1))
     (subword-setup-buffer))
diff --git a/lisp/register.el b/lisp/register.el
index 3d61044..e25f9fd 100644
--- a/lisp/register.el
+++ b/lisp/register.el
@@ -391,7 +391,20 @@ Interactively, reads the register using 
`register-read-with-preview'."
 (cl-defmethod register-val-describe ((val cons) verbose)
   (cond
    ((window-configuration-p (car val))
-    (princ "a window configuration."))
+    (let* ((stored-window-config (car val))
+           (window-config-frame (window-configuration-frame 
stored-window-config))
+           (current-frame (selected-frame)))
+      (princ (format "a window configuration: %s."
+                     (if (frame-live-p window-config-frame)
+                         (with-selected-frame window-config-frame
+                           (save-window-excursion
+                             (set-window-configuration stored-window-config)
+                             (concat
+                              (mapconcat (lambda (w) (buffer-name 
(window-buffer w)))
+                                         (window-list (selected-frame)) ", ")
+                              (unless (eq current-frame window-config-frame)
+                                " in another frame"))))
+                       "dead frame")))))
 
    ((frame-configuration-p (car val))
     (princ "a frame configuration."))
diff --git a/lisp/scroll-bar.el b/lisp/scroll-bar.el
index 4d1ad03..7efbfc7 100644
--- a/lisp/scroll-bar.el
+++ b/lisp/scroll-bar.el
@@ -254,14 +254,22 @@ EVENT should be a scroll bar click or drag event."
   (let* ((start-position (event-start event))
         (window (nth 0 start-position))
         (portion-whole (nth 2 start-position)))
-    (save-excursion
-      (with-current-buffer (window-buffer window)
-       ;; Calculate position relative to the accessible part of the buffer.
-       (goto-char (+ (point-min)
-                     (scroll-bar-scale portion-whole
-                                       (- (point-max) (point-min)))))
-       (vertical-motion 0 window)
-       (set-window-start window (point))))))
+    ;; With 'scroll-bar-adjust-thumb-portion' nil and 'portion-whole'
+    ;; indicating that the buffer is fully visible, do not scroll the
+    ;; window since that might make it impossible to scroll it back
+    ;; with GTK's thumb (Bug#32002).
+    (when (or scroll-bar-adjust-thumb-portion
+              (not (numberp (car portion-whole)))
+              (not (numberp (cdr portion-whole)))
+              (/= (car portion-whole) (cdr portion-whole)))
+      (save-excursion
+        (with-current-buffer (window-buffer window)
+         ;; Calculate position relative to the accessible part of the buffer.
+         (goto-char (+ (point-min)
+                       (scroll-bar-scale portion-whole
+                                         (- (point-max) (point-min)))))
+         (vertical-motion 0 window)
+         (set-window-start window (point)))))))
 
 (defun scroll-bar-drag (event)
   "Scroll the window by dragging the scroll bar slider.
diff --git a/lisp/shadowfile.el b/lisp/shadowfile.el
index 0095d69..86280c3 100644
--- a/lisp/shadowfile.el
+++ b/lisp/shadowfile.el
@@ -25,37 +25,38 @@
 ;;  This package helps you to keep identical copies of files in more than one
 ;;  place - possibly on different machines.  When you save a file, it checks
 ;;  whether it is on the list of files with "shadows", and if so, it tries to
-;;  copy it when you exit Emacs (or use the shadow-copy-files command).
+;;  copy it when you exit Emacs (or use the `shadow-copy-files' command).
 
 ;; Installation & Use:
 
-;;  Add clusters (if necessary) and file groups with shadow-define-cluster,
-;;  shadow-define-literal-group, and shadow-define-regexp-group (see the
+;;  Add clusters (if necessary) and file groups with `shadow-define-cluster',
+;;  `shadow-define-literal-group', and `shadow-define-regexp-group' (see the
 ;;  documentation for these functions for information on how and when to use
 ;;  them).  After doing this once, everything should be automatic.
 
-;;  The lists of clusters and shadows are saved in a ~/.emacs.d/shadows
-;;  (`shadow-info-file') file, so that they can be remembered from one
-;;  Emacs session to another, even (as much as possible) if the Emacs
-;;  session terminates abnormally.  The files needing to be copied are
-;;  stored in `shadow-todo-file'; if a file cannot be copied for any
-;;  reason, it will stay on the list to be tried again next time.  The
-;;  `shadow-info-file' file should itself have shadows on all your accounts
-;;  so that the information in it is consistent everywhere, but
-;;  `shadow-todo-file' is local information and should have no shadows.
+;;  The lists of clusters and shadows are saved in `shadow-info-file',
+;;  so that they can be remembered from one Emacs session to another,
+;;  even (as much as possible) if the Emacs session terminates
+;;  abnormally.  The files needing to be copied are stored in
+;;  `shadow-todo-file'; if a file cannot be copied for any reason, it
+;;  will stay on the list to be tried again next time.  The
+;;  `shadow-info-file' file should itself have shadows on all your
+;;  accounts so that the information in it is consistent everywhere,
+;;  but `shadow-todo-file' is local information and should have no
+;;  shadows.
 
 ;;  If you do not want to copy a particular file, you can answer "no" and
-;;  be asked again next time you hit C-x 4 s or exit Emacs.  If you do not
-;;  want to be asked again, use shadow-cancel, and you will not be asked
+;;  be asked again next time you hit "C-x 4 s" or exit Emacs.  If you do not
+;;  want to be asked again, use "M-x shadow-cancel", and you will not be asked
 ;;  until you change the file and save it again.  If you do not want to
 ;;  shadow that file ever again, you can edit it out of the shadows
-;;  buffer.  Anytime you edit the shadows buffer, you must type M-x
-;;  shadow-read-files to load in the new information, or your changes will
+;;  buffer.  Anytime you edit the shadows buffer, you must type "M-x
+;;  shadow-read-files" to load in the new information, or your changes will
 ;;  be overwritten!
 
 ;; Bugs & Warnings:
 ;;
-;;  - It is bad to have two emacses both running shadowfile at the same
+;;  - It is bad to have two Emacsen both running shadowfile at the same
 ;;  time.  It tries to detect this condition, but is not always successful.
 ;;
 ;;  - You have to be careful not to edit a file in two locations
@@ -64,19 +65,16 @@
 ;;
 ;;  - It ought to check modification times of both files to make sure
 ;;  it is doing the right thing.  This will have to wait until
-;;  file-newer-than-file-p works between machines.
+;;  `file-newer-than-file-p' works between machines.
 ;;
 ;;  - It will not make directories for you, it just fails to copy files
 ;;  that belong in non-existent directories.
-;;
-;;  Please report any bugs to me (address@hidden).  Also let me know
-;;  if you have suggestions or would like to be informed of updates.
 
 
 ;;; Code:
 
 (require 'cl-lib)
-(require 'ange-ftp)
+(require 'tramp)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Variables
@@ -107,35 +105,35 @@ files that have been changed and need to be copied to 
other systems."
   :type 'boolean
   :group 'shadow)
 
-;; FIXME in a sense, this changed in 24.4 (addition of locate-user-emacs-file),
-;; but due to the weird way this variable is initialized to nil, it didn't
-;; literally change.  Same for shadow-todo-file.
-(defcustom shadow-info-file nil
+(defcustom shadow-info-file (locate-user-emacs-file "shadows" ".shadows")
   "File to keep shadow information in.
 The `shadow-info-file' should be shadowed to all your accounts to
 ensure consistency.  Default: ~/.emacs.d/shadows"
-  :type '(choice (const nil) file)
-  :group 'shadow)
+  :type 'file
+  :group 'shadow
+  :version "26.2")
 
-(defcustom shadow-todo-file nil
+(defcustom shadow-todo-file
+  (locate-user-emacs-file "shadow_todo" ".shadow_todo")
   "File to store the list of uncopied shadows in.
 This means that if a remote system is down, or for any reason you cannot or
 decide not to copy your shadow files at the end of one Emacs session, it will
 remember and ask you again in your next Emacs session.
 This file must NOT be shadowed to any other system, it is host-specific.
 Default: ~/.emacs.d/shadow_todo"
-  :type '(choice (const nil) file)
-  :group 'shadow)
+  :type 'file
+  :group 'shadow
+  :version "26.2")
 
 
 ;;; The following two variables should in most cases initialize themselves
 ;;; correctly.  They are provided as variables in case the defaults are wrong
 ;;; on your machine (and for efficiency).
 
-(defvar shadow-system-name (system-name)
-  "The complete hostname of this machine.")
+(defvar shadow-system-name (concat "/" (system-name) ":")
+  "The identification for local files on this machine.")
 
-(defvar shadow-homedir nil
+(defvar shadow-homedir "~"
   "Your home directory on this machine.")
 
 ;;;
@@ -186,12 +184,12 @@ created by `shadow-define-regexp-group'.")
   (car list))
 
 (defun shadow-regexp-superquote (string)
-  "Like `regexp-quote', but includes the ^ and $.
+  "Like `regexp-quote', but includes the \\` and \\'.
 This makes sure regexp matches nothing but STRING."
-  (concat "^" (regexp-quote string) "$"))
+  (concat "\\`" (regexp-quote string) "\\'"))
 
 (defun shadow-suffix (prefix string)
-  "If PREFIX begins STRING, return the rest.
+  "If PREFIX begins with STRING, return the rest.
 Return value is non-nil if PREFIX and STRING are `string=' up to the length of
 PREFIX."
   (let ((lp (length prefix))
@@ -204,70 +202,66 @@ PREFIX."
 ;;; Clusters and sites
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;;; I use the term `site' to refer to a string which may be the name of a
-;;; cluster or a literal hostname.  All user-level commands should accept
-;;; either.
-
-(defun shadow-make-cluster (name primary regexp)
-  "Create a shadow cluster.
-It is called NAME, uses the PRIMARY hostname and REGEXP matching all
-hosts in the cluster.  The variable `shadow-clusters' associates the
-names of clusters to these structures.  This function is for program
-use: to create clusters interactively, use `shadow-define-cluster'
-instead."
-  (list name primary regexp))
-
-(defmacro shadow-cluster-name (cluster)
-  "Return the name of the CLUSTER."
-  (list 'elt cluster 0))
+;;; I use the term `site' to refer to a string which may be the
+;;; cluster identification "/name:", a remote identification
+;;; "/method:address@hidden:", or "/system-name:' (the value of
+;;; `shadow-system-name') for the location of local files.  All
+;;; user-level commands should accept either.
 
-(defmacro shadow-cluster-primary (cluster)
-  "Return the primary hostname of a CLUSTER."
-  (list 'elt cluster 1))
-
-(defmacro shadow-cluster-regexp (cluster)
-  "Return the regexp matching hosts in a CLUSTER."
-  (list 'elt cluster 2))
+(cl-defstruct (shadow-cluster (:type list) :named) name primary regexp)
 
 (defun shadow-set-cluster (name primary regexp)
   "Put cluster NAME on the list of clusters.
 Replace old definition, if any.  PRIMARY and REGEXP are the
 information defining the cluster.  For interactive use, call
 `shadow-define-cluster' instead."
-  (let ((rest (cl-remove-if (lambda (x) (equal name (car x)))
+  (let ((rest (cl-remove-if (lambda (x) (equal name (shadow-cluster-name x)))
                            shadow-clusters)))
     (setq shadow-clusters
-         (cons (shadow-make-cluster name primary regexp)
+         (cons (make-shadow-cluster :name name :primary primary :regexp regexp)
                rest))))
 
-(defmacro shadow-get-cluster (name)
+(defun shadow-get-cluster (name)
   "Return cluster named NAME, or nil."
-  (list 'assoc name 'shadow-clusters))
+  (shadow-find
+   (lambda (x) (string-equal (shadow-cluster-name x) name))
+   shadow-clusters))
+
+;;; SITES
+
+(defun shadow-site-name (site)
+  "Return name if SITE has the form \"/name:\", otherwise SITE."
+  (if (string-match "\\`/\\([-.[:word:]]+\\):\\'" site)
+      (match-string 1 site) site))
+
+(defun shadow-name-site (name)
+  "Return \"/name:\" if NAME has word syntax, otherwise NAME."
+  (if (string-match "\\`[-.[:word:]]+\\'" name)
+      (format "/%s:"name) name))
 
 (defun shadow-site-primary (site)
-  "If SITE is a cluster, return primary host, otherwise return SITE."
-  (let ((c (shadow-get-cluster site)))
-    (if c
-       (shadow-cluster-primary c)
+  "If SITE is a cluster, return primary identification, otherwise return SITE."
+  (let ((cluster (shadow-get-cluster (shadow-site-name site))))
+    (if cluster
+       (shadow-cluster-primary cluster)
       site)))
 
-;;; SITES
-
 (defun shadow-site-cluster (site)
-  "Given a SITE (hostname or cluster name), return cluster it is in, or nil."
-  (or (assoc site shadow-clusters)
+  "Given a SITE, return cluster it is in, or nil."
+  (or (shadow-get-cluster (shadow-site-name site))
       (shadow-find
-       (function (lambda (x)
-                  (string-match (shadow-cluster-regexp x)
-                                site)))
+       (lambda (x)
+         (string-match (shadow-cluster-regexp x) (shadow-name-site site)))
        shadow-clusters)))
 
 (defun shadow-read-site ()
-  "Read a cluster name or hostname from the minibuffer."
-  (let ((ans (completing-read "Host or cluster name [RET when done]: "
+  "Read a cluster name or host identification from the minibuffer."
+  (let ((ans (completing-read "Host identification or cluster name: "
                              shadow-clusters)))
-    (if (equal "" ans)
-       nil
+    (when (or (shadow-get-cluster (shadow-site-name ans))
+             (string-equal ans shadow-system-name)
+             (string-equal ans (shadow-site-name shadow-system-name))
+             (setq ans (file-remote-p ans)))
       ans)))
 
 (defun shadow-site-match (site1 site2)
@@ -281,63 +275,88 @@ be matched against the primary of SITE2."
            (string-match (shadow-cluster-regexp cluster1) primary2)
          (string-equal site1 primary2)))))
 
-(defun shadow-get-user (site)
-  "Return the default username for a SITE."
-  (ange-ftp-get-user (shadow-site-primary site)))
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Filename manipulation
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defun shadow-parse-fullname (fullname)
-  "Parse FULLNAME into (site user path) list.
-Leave it alone if it already is one.  Return nil if the argument is
-not a full ange-ftp pathname."
-  (if (listp fullname)
-      fullname
-    (ange-ftp-ftp-name fullname)))
-
 (defun shadow-parse-name (name)
-  "Parse any NAME into (site user name) list.
-Argument can be a simple name, full ange-ftp name, or already a hup list."
-  (or (shadow-parse-fullname name)
-      (list shadow-system-name
-           (user-login-name)
-           name)))
-
-(defsubst shadow-make-fullname (host user name)
-  "Make an ange-ftp style fullname out of HOST, USER (optional), and NAME.
-This is probably not as general as it ought to be."
-  (concat "/"
-         (if user (concat user "@"))
-         host ":"
-         name))
+  "Parse any NAME into a `tramp-file-name' structure.
+Argument can be a simple name, remote file name, or already a
+`tramp-file-name' structure."
+  (cond
+   ((null name) nil)
+   ((tramp-file-name-p name) name)
+   ((file-remote-p name) (tramp-dissect-file-name name))
+   ((shadow-local-file name)
+    (make-tramp-file-name
+     :host (shadow-site-name shadow-system-name)
+     :localname (shadow-local-file name)))
+   ;; Cluster name.
+   ((string-match "^/\\([^:/]+\\):\\([^:]*\\)$" name)
+    (let ((name (match-string 1 name))
+          (file (match-string 2 name)))
+      (when (shadow-get-cluster name)
+        (make-tramp-file-name :host name :localname file))))))
+
+(defsubst shadow-make-fullname (hup &optional host name)
+  "Make a Tramp style fullname out of HUP, a `tramp-file-name' structure.
+Replace HOST, and NAME when non-nil."
+  (let ((hup (copy-tramp-file-name hup)))
+    (when host (setf (tramp-file-name-host hup) host))
+    (when name (setf (tramp-file-name-localname hup) name))
+    (if (null (tramp-file-name-method hup))
+       (format
+        "/%s:%s" (tramp-file-name-host hup) (tramp-file-name-localname hup))
+      (tramp-make-tramp-file-name hup))))
 
 (defun shadow-replace-name-component (fullname newname)
   "Return FULLNAME with the name component changed to NEWNAME."
-  (let ((hup (shadow-parse-fullname fullname)))
-    (shadow-make-fullname (nth 0 hup) (nth 1 hup) newname)))
+  (concat (file-remote-p fullname) newname))
 
 (defun shadow-local-file (file)
-  "If FILE is at this site, remove /address@hidden part.
-If refers to a different system or a different user on this system,
-return nil."
-  (let ((hup (shadow-parse-fullname file)))
-    (cond ((null hup) file)
-         ((and (shadow-site-match (nth 0 hup) shadow-system-name)
-               (string-equal (nth 1 hup) (user-login-name)))
-          (nth 2 hup))
-         (t nil))))
+  "If FILE is not remote, return it.
+If it refers to a different system, return nil."
+  (cond
+   ((null file) nil)
+   ;; `tramp-file-name' structure.
+   ((and (tramp-file-name-p file) (null (tramp-file-name-method file)))
+    (tramp-file-name-localname file))
+   ((tramp-file-name-p file) nil)
+   ;; Local host name.
+   ((string-match
+     (format "^%s\\([^:]*\\)$" (regexp-quote shadow-system-name)) file)
+    (match-string 1 file))
+   ;; Cluster name.
+   ((and (string-match "^/\\([^:/]+\\):\\([^:]*\\)$" file)
+         (shadow-get-cluster (match-string 1 file)))
+    (let ((file (match-string 2 file))
+         (primary
+          (shadow-cluster-primary
+           (shadow-get-cluster (match-string 1 file)))))
+      (when (string-equal primary shadow-system-name) (setq primary nil))
+      (shadow-local-file (concat primary file))))
+   ;; Local name.
+   ((null (file-remote-p file)) file)))
 
 (defun shadow-expand-cluster-in-file-name (file)
   "If hostname part of FILE is a cluster, expand it to cluster's primary 
hostname.
 Will return the name bare if it is a local file."
-  (let ((hup (shadow-parse-name file)))
-    (cond ((null hup) file)
-         ((shadow-local-file hup))
-         ((shadow-make-fullname (shadow-site-primary (nth 0 hup))
-                                (nth 1 hup)
-                                (nth 2 hup))))))
+  (when (stringp file)
+    (cond
+     ;; Local file.
+     ((shadow-local-file file))
+     ;; Cluster name.
+     ((string-match "^\\(/[^:/]+:\\)[^:]*$" file)
+      (let ((primary
+             (save-match-data
+              (shadow-cluster-primary
+               (shadow-get-cluster
+                 (shadow-site-name (match-string 1 file)))))))
+       (if (not primary)
+            file
+          (setq file (replace-match primary nil nil file 1))
+          (or (shadow-local-file file) file))))
+     (t file))))
 
 (defun shadow-expand-file-name (file &optional default)
   "Expand file name and get FILE's true name."
@@ -352,46 +371,50 @@ true."
         (homedir (if (shadow-local-file hup)
                      shadow-homedir
                    (file-name-as-directory
-                    (nth 2 (shadow-parse-fullname
-                            (expand-file-name
-                             (shadow-make-fullname
-                              (nth 0 hup) (nth 1 hup) "~")))))))
-        (suffix (shadow-suffix homedir (nth 2 hup)))
-        (cluster (shadow-site-cluster (nth 0 hup))))
+                    (file-local-name
+                      (expand-file-name (shadow-make-fullname hup nil "~"))))))
+        (suffix (shadow-suffix homedir (tramp-file-name-localname hup)))
+        (cluster (shadow-site-cluster (shadow-make-fullname hup nil ""))))
+    (when cluster
+      (setf (tramp-file-name-method hup) nil
+           (tramp-file-name-host hup) (shadow-cluster-name cluster)))
     (shadow-make-fullname
-     (if cluster
-        (shadow-cluster-name cluster)
-       (nth 0 hup))
-     (nth 1 hup)
+     hup nil
      (if suffix
-        (concat "~/" suffix)
-       (nth 2 hup)))))
+         (concat "~/" suffix)
+       (tramp-file-name-localname hup)))))
 
 (defun shadow-same-site (pattern file)
   "True if the site of PATTERN and of FILE are on the same site.
-If usernames are supplied, they must also match exactly.  PATTERN and FILE may
-be lists of host, user, name, or ange-ftp file names.  FILE may also be just a
-local filename."
-  (let ((pattern-sup (shadow-parse-fullname pattern))
+PATTERN and FILE may be Tramp vectors, or remote file names.
+FILE may also be just a local filename."
+  (let ((pattern-sup (shadow-parse-name pattern))
        (file-sup    (shadow-parse-name file)))
     (and
-     (shadow-site-match (nth 0 pattern-sup) (nth 0 file-sup))
-     (or (null (nth 1 pattern-sup))
-        (string-equal (nth 1 pattern-sup) (nth 1 file-sup))))))
+     (shadow-site-match
+      (tramp-file-name-host pattern-sup) (tramp-file-name-host file-sup))
+     (or (null (tramp-file-name-user pattern-sup))
+        (string-equal
+          (tramp-file-name-user pattern-sup)
+          (tramp-file-name-user file-sup))))))
 
 (defun shadow-file-match (pattern file &optional regexp)
  "Return t if PATTERN matches FILE.
 If REGEXP is supplied and non-nil, the file part of the pattern is a regular
-expression, otherwise it must match exactly.  The sites and usernames must
-match---see `shadow-same-site'.  The pattern must be in full ange-ftp format,
+expression, otherwise it must match exactly.  The sites must
+match---see `shadow-same-site'.  The pattern must be in full Tramp format,
 but the file can be any valid filename.  This function does not do any
 filename expansion or contraction, you must do that yourself first."
- (let* ((pattern-sup (shadow-parse-fullname pattern))
+ (let* ((pattern-sup (shadow-parse-name pattern))
        (file-sup (shadow-parse-name file)))
    (and (shadow-same-site pattern-sup file-sup)
        (if regexp
-           (string-match (nth 2 pattern-sup) (nth 2 file-sup))
-         (string-equal (nth 2 pattern-sup) (nth 2 file-sup))))))
+           (string-match
+             (tramp-file-name-localname pattern-sup)
+             (tramp-file-name-localname file-sup))
+         (string-equal
+           (tramp-file-name-localname pattern-sup)
+           (tramp-file-name-localname file-sup))))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; User-level Commands
@@ -405,30 +428,34 @@ one of them is sufficient to update the file on all of 
them.  Clusters are
 defined by a name, the network address of a primary host (the one we copy
 files to), and a regular expression that matches the hostnames of all the
 sites in the cluster."
-  (interactive (list (completing-read "Cluster name: " shadow-clusters () ())))
+  (interactive (list (completing-read "Cluster name: " shadow-clusters)))
   (let* ((old (shadow-get-cluster name))
-        (primary (read-string "Primary host: "
-                              (if old (shadow-cluster-primary old)
-                                name)))
-        (regexp   (let (try-regexp)
-                    (while (not
-                            (string-match
-                             (setq try-regexp
+        (primary (let (try-primary)
+                   (while (not
+                           (or
+                            (string-equal
+                             (setq try-primary
                                    (read-string
-                                    "Regexp matching all host names: "
-                                    (if old (shadow-cluster-regexp old)
-                                      (shadow-regexp-superquote primary))))
-                             primary))
-                      (message "Regexp doesn't include the primary host!")
-                      (sit-for 2))
-                    try-regexp))
-;       (username (read-no-blanks-input
-;                  (format "Username (default %s): "
-;                          (shadow-get-user primary))
-;                  (if old (or (shadow-cluster-username old) "")
-;                    (user-login-name))))
-        )
-;    (if (string-equal "" username) (setq username nil))
+                                    "Primary host: "
+                                    (if old (shadow-cluster-primary old)
+                                      name)))
+                             shadow-system-name)
+                            (file-remote-p try-primary)))
+                     (message "Not a valid primary!")
+                     (sit-for 2))
+                   try-primary))
+        (regexp  (let (try-regexp)
+                   (while (not
+                           (string-match
+                            (setq try-regexp
+                                  (read-string
+                                   "Regexp matching all host names: "
+                                   (if old (shadow-cluster-regexp old)
+                                     (shadow-regexp-superquote primary))))
+                            primary))
+                     (message "Regexp doesn't include the primary host!")
+                     (sit-for 2))
+                   try-regexp)))
     (shadow-set-cluster name primary regexp)))
 
 ;;;###autoload
@@ -438,20 +465,14 @@ It may have different filenames on each site.  When this 
file is edited, the
 new version will be copied to each of the other locations.  Sites can be
 specific hostnames, or names of clusters (see `shadow-define-cluster')."
   (interactive)
-  (let* ((hup (shadow-parse-fullname
+  (let* ((hup (shadow-parse-name
               (shadow-contract-file-name (buffer-file-name))))
-        (name (nth 2 hup))
-        user site group)
+        (name (tramp-file-name-localname hup))
+        site group)
     (while (setq site (shadow-read-site))
-      (setq user (read-string (format "Username (default %s): "
-                                     (shadow-get-user site)))
-           name (read-string "Filename: " name))
-      (setq group (cons (shadow-make-fullname site
-                                             (if (string-equal "" user)
-                                                 (shadow-get-user site)
-                                               user)
-                                             name)
-                       group)))
+      (setq name (read-string "Filename: " name)
+            hup (shadow-parse-name (shadow-contract-file-name name))
+           group (cons (shadow-make-fullname hup site) group)))
     (setq shadow-literal-groups (cons group shadow-literal-groups)))
   (shadow-write-info-file))
 
@@ -468,19 +489,12 @@ function).  Each site can be either a hostname or the 
name of a cluster (see
                 "Filename regexp: "
                 (if (buffer-file-name)
                     (shadow-regexp-superquote
-                     (nth 2
-                          (shadow-parse-name
-                           (shadow-contract-file-name
-                            (buffer-file-name))))))))
-       site sites usernames)
+                      (file-local-name (buffer-file-name))))))
+       site sites)
     (while (setq site (shadow-read-site))
-      (setq sites (cons site sites))
-      (setq usernames
-           (cons (read-string (format "Username for %s: " site)
-                              (shadow-get-user site))
-                 usernames)))
+      (setq sites (cons site sites)))
     (setq shadow-regexp-groups
-         (cons (shadow-make-group regexp sites usernames)
+         (cons (shadow-make-group regexp sites)
                shadow-regexp-groups))
     (shadow-write-info-file)))
 
@@ -537,14 +551,14 @@ permanently, remove the group from 
`shadow-literal-groups' or
 ;;; Internal functions
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defun shadow-make-group (regexp sites usernames)
+(defun shadow-make-group (regexp sites)
   "Make a description of a file group---
-actually a list of regexp ange-ftp file names---from REGEXP (name of file to
-be shadowed), list of SITES, and corresponding list of USERNAMES for each
-site."
+actually a list of regexp Tramp file names---from REGEXP (name of file to
+be shadowed), and list of SITES"
   (if sites
-      (cons (shadow-make-fullname (car sites) (car usernames) regexp)
-           (shadow-make-group regexp (cdr sites) (cdr usernames)))
+      (cons (shadow-make-fullname
+             (shadow-parse-name (shadow-site-primary (car sites))) nil regexp)
+           (shadow-make-group regexp (cdr sites)))
     nil))
 
 (defun shadow-copy-file (s)
@@ -601,7 +615,9 @@ Consider them as regular expressions if third arg REGEXP is 
true."
                           (car groups))))
        (append (cond ((equal nonmatching (car groups)) nil)
                      (regexp
-                      (let ((realname (nth 2 (shadow-parse-fullname file))))
+                      (let ((realname
+                              (tramp-file-name-localname
+                               (shadow-parse-name file))))
                         (mapcar
                          (function
                           (lambda (x)
@@ -612,17 +628,26 @@ Consider them as regular expressions if third arg REGEXP 
is true."
 
 (defun shadow-add-to-todo ()
   "If current buffer has shadows, add them to the list needing to be copied."
+  (message "shadow-add-to-todo 1 %s" (current-buffer))
+  (message "shadow-add-to-todo 2 %s" (buffer-file-name))
+  (message "shadow-add-to-todo 3 %s" (shadow-expand-file-name 
(buffer-file-name  (current-buffer))))
+  (message "shadow-add-to-todo 4 %s" (shadow-shadows-of 
(shadow-expand-file-name (buffer-file-name (current-buffer)))))
   (let ((shadows (shadow-shadows-of
                  (shadow-expand-file-name
                   (buffer-file-name (current-buffer))))))
     (when shadows
+      (message "shadow-add-to-todo 5 %s" shadows)
+      (message "shadow-add-to-todo 6 %s" shadow-files-to-copy)
+      (message "shadow-add-to-todo 7 %s" (shadow-union shadows 
shadow-files-to-copy))
       (setq shadow-files-to-copy
            (shadow-union shadows shadow-files-to-copy))
       (when (not shadow-inhibit-message)
        (message "%s" (substitute-command-keys
                       "Use \\[shadow-copy-files] to update shadows."))
        (sit-for 1))
-      (shadow-write-todo-file)))
+      (message "shadow-add-to-todo 8")
+      (shadow-write-todo-file)
+      (message "shadow-add-to-todo 9")))
   nil)     ; Return nil for write-file-functions
 
 (defun shadow-remove-from-todo (pair)
@@ -636,9 +661,8 @@ PAIR must be `eq' to one of the elements of that list."
 Thus restores shadowfile's state from your last Emacs session.
 Return t unless files were locked; then return nil."
   (interactive)
-  (if (and (fboundp 'file-locked-p)
-          (or (stringp (file-locked-p shadow-info-file))
-              (stringp (file-locked-p shadow-todo-file))))
+  (if (or (stringp (file-locked-p shadow-info-file))
+          (stringp (file-locked-p shadow-todo-file)))
       (progn
        (message "Shadowfile is running in another Emacs; can't have two.")
        (beep)
@@ -647,7 +671,7 @@ Return t unless files were locked; then return nil."
     (save-current-buffer
       (when shadow-info-file
        (set-buffer (setq shadow-info-buffer
-                         (find-file-noselect shadow-info-file)))
+                         (find-file-noselect shadow-info-file 'nowarn)))
        (when (and (not (buffer-modified-p))
                   (file-newer-than-file-p (make-auto-save-file-name)
                                           shadow-info-file))
@@ -680,6 +704,7 @@ defined, the old hashtable info is invalid."
        (if (not shadow-info-buffer)
            (setq shadow-info-buffer (find-file-noselect shadow-info-file)))
        (set-buffer shadow-info-buffer)
+        (setq buffer-read-only nil)
        (delete-region (point-min) (point-max))
        (shadow-insert-var 'shadow-clusters)
        (shadow-insert-var 'shadow-literal-groups)
@@ -689,17 +714,26 @@ defined, the old hashtable info is invalid."
   "Write out information to `shadow-todo-file'.
 With non-nil argument also saves the buffer."
   (save-excursion
+    (message "shadow-write-todo-file 1 %s" shadow-todo-buffer)
     (if (not shadow-todo-buffer)
        (setq shadow-todo-buffer (find-file-noselect shadow-todo-file)))
+    (message "shadow-write-todo-file 2 %s" shadow-todo-buffer)
     (set-buffer shadow-todo-buffer)
+    (message "shadow-write-todo-file 3 %s" shadow-todo-buffer)
+    (setq buffer-read-only nil)
     (delete-region (point-min) (point-max))
+    (message "shadow-write-todo-file 4 %s" shadow-todo-buffer)
     (shadow-insert-var 'shadow-files-to-copy)
-    (if save (shadow-save-todo-file))))
+    (message "shadow-write-todo-file 5 %s" save)
+    (if save (shadow-save-todo-file))
+    (message "shadow-write-todo-file 6 %s" save)))
 
 (defun shadow-save-todo-file ()
+  (message "shadow-save-todo-file 1 %s" shadow-todo-buffer)
   (if (and shadow-todo-buffer (buffer-modified-p shadow-todo-buffer))
       (with-current-buffer shadow-todo-buffer
-       (condition-case nil             ; have to continue even in case of
+        (message "shadow-save-todo-file 2 %s" shadow-todo-buffer)
+        (condition-case nil            ; have to continue even in case of
            (basic-save-buffer)         ; error, otherwise kill-emacs might
          (error                        ; not work!
           (message "WARNING: Can't save shadow todo file; it is locked!")
@@ -765,24 +799,6 @@ look for files that have been changed and need to be 
copied to other systems."
        (kill-emacs)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Lucid Emacs compatibility
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-;; This is on hold until someone tells me about a working version of
-;; map-ynp for Lucid Emacs.
-
-;(when (string-match "Lucid" emacs-version)
-;  (require 'symlink-fix)
-;  (require 'ange-ftp)
-;  (require 'map-ynp)
-;  (if (not (fboundp 'file-truename))
-;      (fset 'shadow-expand-file-name
-;          (symbol-function 'symlink-expand-file-name)))
-;  (if (not (fboundp 'ange-ftp-ftp-name))
-;      (fset 'ange-ftp-ftp-name
-;          (symbol-function 'ange-ftp-ftp-name))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Hook us up
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -790,18 +806,10 @@ look for files that have been changed and need to be 
copied to other systems."
 (defun shadow-initialize ()
   "Set up file shadowing."
   (interactive)
-  (if (null shadow-homedir)
-      (setq shadow-homedir
-           (file-name-as-directory (shadow-expand-file-name "~"))))
-  (if (null shadow-info-file)
-      (setq shadow-info-file
-            ;; FIXME: Move defaults to their defcustom.
-           (shadow-expand-file-name
-             (locate-user-emacs-file "shadows" ".shadows"))))
-  (if (null shadow-todo-file)
-      (setq shadow-todo-file
-           (shadow-expand-file-name
-            (locate-user-emacs-file "shadow_todo" ".shadow_todo"))))
+  (setq shadow-homedir
+        (file-name-as-directory (shadow-expand-file-name shadow-homedir))
+        shadow-info-file (shadow-expand-file-name shadow-info-file)
+        shadow-todo-file (shadow-expand-file-name shadow-todo-file))
   (if (not (shadow-read-files))
       (progn
        (message "Shadowfile information files not found - aborting")
diff --git a/lisp/shell.el b/lisp/shell.el
index fa6eee0..ac6f11a 100644
--- a/lisp/shell.el
+++ b/lisp/shell.el
@@ -73,7 +73,7 @@
 ;; c-c c-o comint-delete-output                   Delete last batch of process 
output
 ;; c-c c-r comint-show-output             Show last batch of process output
 ;; c-c c-l comint-dynamic-list-input-ring  List input history
-;;         send-invisible                  Read line w/o echo & send to proc
+;;         comint-send-invisible           Read line w/o echo & send to proc
 ;;         comint-continue-subjob         Useful if you accidentally suspend
 ;;                                             top-level job
 ;; comint-mode-hook is the comint mode hook.
@@ -500,7 +500,7 @@ Shell buffers.  It implements `shell-completion-execonly' 
for
     the end of process to the end of the current line.
 \\[comint-send-input] before end of process output copies the current line 
minus the prompt to
     the end of the buffer and sends it (\\[comint-copy-old-input] just copies 
the current line).
-\\[send-invisible] reads a line of text without echoing it, and sends it to
+\\[comint-send-invisible] reads a line of text without echoing it, and sends 
it to
     the shell.  This is useful for entering passwords.  Or, add the function
     `comint-watch-for-password-prompt' to `comint-output-filter-functions'.
 
diff --git a/lisp/simple.el b/lisp/simple.el
index 6459531..8d77047 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -8346,14 +8346,12 @@ LSHIFTBY is the numeric value of this modifier, in 
keyboard events.
 PREFIX is the string that represents this modifier in an event type symbol."
   (if (numberp event)
       (cond ((eq symbol 'control)
-            (if (and (<= (downcase event) ?z)
-                     (>= (downcase event) ?a))
-                (- (downcase event) ?a -1)
-              (if (and (<= (downcase event) ?Z)
-                       (>= (downcase event) ?A))
-                  (- (downcase event) ?A -1)
-                (logior (lsh 1 lshiftby) event))))
+            (if (<= 64 (upcase event) 95)
+                (- (upcase event) 64)
+              (logior (lsh 1 lshiftby) event)))
            ((eq symbol 'shift)
+             ;; FIXME: Should we also apply this "upcase" behavior of shift
+             ;; to non-ascii letters?
             (if (and (<= (downcase event) ?z)
                      (>= (downcase event) ?a))
                 (upcase event)
diff --git a/lisp/subr.el b/lisp/subr.el
index 10343e6..f8c19ef 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -555,12 +555,6 @@ If N is omitted or nil, remove the last element."
           (if (> n 0) (setcdr (nthcdr (- (1- m) n) list) nil))
           list))))
 
-(defun proper-list-p (object)
-  "Return OBJECT's length if it is a proper list, nil otherwise.
-A proper list is neither circular nor dotted (i.e., its last cdr
-is nil)."
-  (and (listp object) (ignore-errors (length object))))
-
 (defun delete-dups (list)
   "Destructively remove `equal' duplicates from LIST.
 Store the result in LIST and return it.  LIST must be a proper list.
@@ -2305,7 +2299,7 @@ some sort of escape sequence, the ambiguity is resolved 
via `read-key-delay'."
 If optional CONFIRM is non-nil, read the password twice to make sure.
 Optional DEFAULT is a default password to use instead of empty input.
 
-This function echoes `.' for each character that the user types.
+This function echoes `*' for each character that the user types.
 You could let-bind `read-hide-char' to another hiding character, though.
 
 Once the caller uses the password, it can erase the password
@@ -2331,7 +2325,7 @@ by doing (clear-string STRING)."
                                      beg)))
              (dotimes (i (- end beg))
                (put-text-property (+ i beg) (+ 1 i beg)
-                                  'display (string (or read-hide-char ?.))))))
+                                  'display (string (or read-hide-char ?*))))))
           minibuf)
       (minibuffer-with-setup-hook
           (lambda ()
@@ -2346,7 +2340,7 @@ by doing (clear-string STRING)."
             (add-hook 'after-change-functions hide-chars-fun nil 'local))
         (unwind-protect
             (let ((enable-recursive-minibuffers t)
-                 (read-hide-char (or read-hide-char ?.)))
+                 (read-hide-char (or read-hide-char ?*)))
               (read-string prompt nil t default)) ; t = "no history"
           (when (buffer-live-p minibuf)
             (with-current-buffer minibuf
diff --git a/lisp/term.el b/lisp/term.el
index 121a22e..9f8f1f7 100644
--- a/lisp/term.el
+++ b/lisp/term.el
@@ -343,6 +343,7 @@
 (eval-when-compile (require 'cl-lib))
 (require 'ring)
 (require 'ehelp)
+(require 'comint) ; Password regexp.
 
 (declare-function ring-empty-p "ring" (ring))
 (declare-function ring-ref "ring" (ring index))
@@ -2215,6 +2216,7 @@ filter and C-g is pressed, this function returns nil 
rather than a string).
 Note that the keystrokes comprising the text can still be recovered
 \(temporarily) with \\[view-lossage].  This may be a security bug for some
 applications."
+  (declare (obsolete read-passwd "27.1"))
   (let ((ans "")
        (c 0)
        (echo-keystrokes 0)
@@ -2255,12 +2257,10 @@ applications."
 (defun term-send-invisible (str &optional proc)
   "Read a string without echoing.
 Then send it to the process running in the current buffer.  A new-line
-is additionally sent.  String is not saved on term input history list.
-Security bug: your string can still be temporarily recovered with
-\\[view-lossage]."
+is additionally sent.  String is not saved on term input history list."
   (interactive "P") ; Defeat snooping via C-x esc
   (when (not (stringp str))
-    (setq str (term-read-noecho "Non-echoed text: " t)))
+    (setq str (read-passwd "Non-echoed text: ")))
   (when (not proc)
     (setq proc (get-buffer-process (current-buffer))))
   (if (not proc) (error "Current buffer has no process")
@@ -2269,6 +2269,16 @@ Security bug: your string can still be temporarily 
recovered with
     (term-send-string proc str)
     (term-send-string proc "\n")))
 
+;; TODO: Maybe combine this with `comint-watch-for-password-prompt'.
+(defun term-watch-for-password-prompt (string)
+  "Prompt in the minibuffer for password and send without echoing.
+Checks if STRING contains a password prompt as defined by
+`comint-password-prompt-regexp'."
+  (when (term-in-line-mode)
+    (when (let ((case-fold-search t))
+            (string-match comint-password-prompt-regexp string))
+      (term-send-invisible (read-passwd string)))))
+
 
 ;;; Low-level process communication
 
@@ -3054,6 +3064,8 @@ See `term-prompt-regexp'."
          (term-handle-deferred-scroll))
 
        (set-marker (process-mark proc) (point))
+        (when (stringp decoded-substring)
+          (term-watch-for-password-prompt decoded-substring))
        (when save-point
          (goto-char save-point)
          (set-marker save-point nil))
diff --git a/lisp/term/tty-colors.el b/lisp/term/tty-colors.el
index ab9149e..a776c83 100644
--- a/lisp/term/tty-colors.el
+++ b/lisp/term/tty-colors.el
@@ -824,10 +824,12 @@ A canonicalized color name is all-lower case, with any 
blanks removed."
        (replace-regexp-in-string " +" "" (downcase color))
       color)))
 
-(defun tty-color-24bit (rgb)
-  "Return pixel value on 24-bit terminals. Return nil if RGB is
-nil or not on 24-bit terminal."
-  (when (and rgb (= (display-color-cells) 16777216))
+(defun tty-color-24bit (rgb &optional display)
+  "Return 24-bit color pixel value for RGB value on DISPLAY.
+DISPLAY can be a display name or a frame, and defaults to the
+selected frame's display.
+If DISPLAY is not on a 24-but TTY terminal, return nil."
+  (when (and rgb (= (display-color-cells display) 16777216))
     (let ((r (lsh (car rgb) -8))
          (g (lsh (cadr rgb) -8))
          (b (lsh (nth 2 rgb) -8)))
@@ -850,7 +852,7 @@ If FRAME is not specified or is nil, it defaults to the 
selected frame."
       (error "Invalid specification for tty color \"%s\"" name))
   (tty-modify-color-alist
    (append (list (tty-color-canonicalize name)
-                (or (tty-color-24bit rgb) index))
+                (or (tty-color-24bit rgb frame) index))
           rgb)
    frame))
 
@@ -1026,7 +1028,7 @@ might need to be approximated if it is not supported 
directly."
          (or (assoc color (tty-color-alist frame))
              (let ((rgb (tty-color-standard-values color)))
                (and rgb
-                    (let ((pixel (tty-color-24bit rgb)))
+                    (let ((pixel (tty-color-24bit rgb frame)))
                       (or (and pixel (cons color (cons pixel rgb)))
                           (tty-color-approximate rgb frame)))))))))
 
diff --git a/lisp/textmodes/flyspell.el b/lisp/textmodes/flyspell.el
index 4d5b11c..69bba10 100644
--- a/lisp/textmodes/flyspell.el
+++ b/lisp/textmodes/flyspell.el
@@ -138,7 +138,9 @@ This variable specifies how far to search to find such a 
duplicate.
   "Non-nil means misspelled words remain highlighted until corrected.
 If this variable is nil, only the most recently detected misspelled word
 is highlighted, and the highlight is turned off as soon as point moves
-off the misspelled word."
+off the misspelled word.
+
+Make sure this variable is non-nil if you use `flyspell-region'."
   :group 'flyspell
   :type 'boolean)
 
@@ -1372,7 +1374,10 @@ language."
 ;;*    flyspell-small-region ...                                        */
 ;;*---------------------------------------------------------------------*/
 (defun flyspell-small-region (beg end)
-  "Flyspell text between BEG and END."
+  "Flyspell text between BEG and END.
+
+This function is intended to work on small regions, as
+determined by `flyspell-large-region'."
   (save-excursion
     (if (> beg end)
        (let ((old beg))
@@ -1643,7 +1648,10 @@ The buffer to mark them in is 
`flyspell-large-region-buffer'."
 ;;*---------------------------------------------------------------------*/
 ;;;###autoload
 (defun flyspell-region (beg end)
-  "Flyspell text between BEG and END."
+  "Flyspell text between BEG and END.
+
+Make sure `flyspell-mode' is turned on if you want the highlight
+of a misspelled word removed when you've corrected it."
   (interactive "r")
   (ispell-set-spellchecker-params)  ; Initialize variables and dicts alists
   (if (= beg end)
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index d80447e..e6f436f 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -2262,8 +2262,9 @@ Global `ispell-quit' set to start location to continue 
spell session."
                    (ispell-pdict-save ispell-silently-savep)
                    (message "%s"
                     (substitute-command-keys
-                     (concat "Spell-checking suspended;"
-                             " use C-u \\[ispell-word] to resume")))
+                     (concat
+                       "Spell-checking suspended; use "
+                      "\\[universal-argument] \\[ispell-word] to resume")))
                    (setq ispell-quit start)
                    nil)
                   ((= char ?q)
diff --git a/lisp/textmodes/reftex-vars.el b/lisp/textmodes/reftex-vars.el
index 11dbb8d..e7fe8ff 100644
--- a/lisp/textmodes/reftex-vars.el
+++ b/lisp/textmodes/reftex-vars.el
@@ -1030,7 +1030,9 @@ This is used to string together whole reference sets, like
     ("Hyperref" "hyperref"
      (("\\autoref" ?a) ("\\autopageref" ?u)))
     ("Cleveref" "cleveref"
-     (("\\cref" ?c) ("\\Cref" ?C) ("\\cpageref" ?d) ("\\Cpageref" ?D))))
+     (("\\cref" ?c) ("\\Cref" ?C) ("\\cpageref" ?d) ("\\Cpageref" ?D)))
+    ("AMSmath" "amsmath"
+     (("\\eqref" ?e))))
   "Alist of reference styles.
 Each element is a list of the style name, the name of the LaTeX
 package associated with the style or t for any package, and an
@@ -1040,7 +1042,7 @@ the macro type is being prompted for.  (See also
 `reftex-ref-macro-prompt'.)  The keys, represented as characters,
 have to be unique."
   :group 'reftex-referencing-labels
-  :version "24.3"
+  :version "27.1"
   :type '(alist :key-type (string :tag "Style name")
                :value-type (group (choice :tag "Package"
                                           (const :tag "Any package" t)
diff --git a/lisp/vc/add-log.el b/lisp/vc/add-log.el
index 4d69aac..d6e8540 100644
--- a/lisp/vc/add-log.el
+++ b/lisp/vc/add-log.el
@@ -744,6 +744,7 @@ Optional arg BUFFER-FILE overrides `buffer-file-name'."
   file-name)
 
 (defun add-log-file-name (buffer-file log-file)
+  "Compute file-name of BUFFER-FILE to be used in entries in LOG-FILE."
   ;; Never want to add a change log entry for the ChangeLog file itself.
   (unless (or (null buffer-file) (string= buffer-file log-file))
     (if add-log-file-name-function
@@ -767,15 +768,57 @@ Optional arg BUFFER-FILE overrides `buffer-file-name'."
          (file-name-sans-versions buffer-file)
        buffer-file))))
 
+(defcustom add-log-dont-create-changelog-file t
+  "If non-nil, don't create ChangeLog files for log entries.
+If a ChangeLog file does not already exist, a non-nil value
+means to put log entries in a suitably named buffer."
+  :type :boolean
+  :version "27.1")
+
+(put 'add-log-dont-create-changelog-file 'safe-local-variable 'booleanp)
+
+(defun add-log--pseudo-changelog-buffer-name (changelog-file-name)
+  "Compute a suitable name for a non-file visiting ChangeLog buffer.
+CHANGELOG-FILE-NAME is the file name of the actual ChangeLog file
+if it were to exist."
+  (format "*changes to %s*"
+          (abbreviate-file-name
+           (file-name-directory changelog-file-name))))
+
+(defun add-log--changelog-buffer-p (changelog-file-name buffer)
+  "Return non-nil if BUFFER holds a change log for CHANGELOG-FILE-NAME."
+  (with-current-buffer buffer
+    (if buffer-file-name
+        (equal buffer-file-name changelog-file-name)
+      (equal (add-log--pseudo-changelog-buffer-name changelog-file-name)
+             (buffer-name)))))
+
+(defun add-log-find-changelog-buffer (changelog-file-name)
+  "Find a ChangeLog buffer for CHANGELOG-FILE-NAME.
+Respect `add-log-use-pseudo-changelog', which see."
+  (if (or (file-exists-p changelog-file-name)
+          (not add-log-dont-create-changelog-file))
+      (find-file-noselect changelog-file-name)
+    (get-buffer-create
+     (add-log--pseudo-changelog-buffer-name changelog-file-name))))
+
 ;;;###autoload
-(defun add-change-log-entry (&optional whoami file-name other-window new-entry
+(defun add-change-log-entry (&optional whoami
+                                       changelog-file-name
+                                       other-window new-entry
                                       put-new-entry-on-new-line)
-  "Find change log file, and add an entry for today and an item for this file.
-Optional arg WHOAMI (interactive prefix) non-nil means prompt for user
-name and email (stored in `add-log-full-name' and `add-log-mailing-address').
-
-Second arg FILE-NAME is file name of the change log.
-If nil, use the value of `change-log-default-name'.
+  "Find ChangeLog buffer, add an entry for today and an item for this file.
+Optional arg WHOAMI (interactive prefix) non-nil means prompt for
+user name and email (stored in `add-log-full-name'
+and `add-log-mailing-address').
+
+Second arg CHANGELOG-FILE-NAME is the file name of the change log.
+If nil, use the value of `change-log-default-name'.  If the file
+thus named exists, it is used for the new entry.  If it doesn't
+exist, it is created, unless `add-log-dont-create-changelog-file' is t,
+in which case a suitably named buffer that doesn't visit any file
+is used for keeping entries pertaining to CHANGELOG-FILE-NAME's
+directory.
 
 Third arg OTHER-WINDOW non-nil means visit in other window.
 
@@ -804,20 +847,28 @@ non-nil, otherwise in local time."
                       (change-log-version-number-search)))
         (buf-file-name (funcall add-log-buffer-file-name-function))
         (buffer-file (if buf-file-name (expand-file-name buf-file-name)))
-        (file-name (expand-file-name (find-change-log file-name buffer-file)))
+        (changelog-file-name (expand-file-name (find-change-log
+                                                 changelog-file-name
+                                                 buffer-file)))
         ;; Set ITEM to the file name to use in the new item.
-        (item (add-log-file-name buffer-file file-name)))
+        (item (add-log-file-name buffer-file changelog-file-name)))
 
-    (unless (equal file-name buffer-file-name)
+    ;; don't add entries from the ChangeLog file/buffer to itself.
+    (unless (equal changelog-file-name buffer-file-name)
       (cond
-       ((equal file-name (buffer-file-name (window-buffer)))
+       ((add-log--changelog-buffer-p
+         changelog-file-name
+         (window-buffer))
         ;; If the selected window already shows the desired buffer don't show
         ;; it again (particularly important if other-window is true).
         ;; This is important for diff-add-change-log-entries-other-window.
         (set-buffer (window-buffer)))
        ((or other-window (window-dedicated-p))
-        (find-file-other-window file-name))
-       (t (find-file file-name))))
+        (switch-to-buffer-other-window
+         (add-log-find-changelog-buffer changelog-file-name)))
+       (t
+        (switch-to-buffer
+         (add-log-find-changelog-buffer changelog-file-name)))))
     (or (derived-mode-p 'change-log-mode)
        (change-log-mode))
     (undo-boundary)
diff --git a/lisp/vc/diff.el b/lisp/vc/diff.el
index b850350..ac94586 100644
--- a/lisp/vc/diff.el
+++ b/lisp/vc/diff.el
@@ -226,8 +226,9 @@ With prefix arg, prompt for diff switches."
   "View the differences between BUFFER and its associated file.
 This requires the external program `diff' to be in your `exec-path'."
   (interactive "bBuffer: ")
-  (with-current-buffer (get-buffer (or buffer (current-buffer)))
-    (diff buffer-file-name (current-buffer) nil 'noasync)))
+  (let ((buf (get-buffer (or buffer (current-buffer)))))
+    (with-current-buffer (or (buffer-base-buffer buf) buf)
+      (diff buffer-file-name (current-buffer) nil 'noasync))))
 
 (provide 'diff)
 
diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el
index 6ff782a..90860fb 100644
--- a/lisp/vc/log-edit.el
+++ b/lisp/vc/log-edit.el
@@ -913,8 +913,10 @@ where LOGBUFFER is the name of the ChangeLog buffer, and 
each
              (setq change-log-default-name nil)
              (find-change-log)))))
     (when (or (find-buffer-visiting changelog-file-name)
-              (file-exists-p changelog-file-name))
-      (with-current-buffer (find-file-noselect changelog-file-name)
+              (file-exists-p changelog-file-name)
+              add-log-dont-create-changelog-file)
+      (with-current-buffer
+          (add-log-find-changelog-buffer changelog-file-name)
         (unless (eq major-mode 'change-log-mode) (change-log-mode))
         (goto-char (point-min))
         (if (looking-at "\\s-*\n") (goto-char (match-end 0)))
diff --git a/lisp/w32-fns.el b/lisp/w32-fns.el
index 825420c..bdba32c 100644
--- a/lisp/w32-fns.el
+++ b/lisp/w32-fns.el
@@ -280,7 +280,7 @@ bit output with no translation."
   (w32-add-charset-info "iso8859-13" 'w32-charset-baltic 1257)
   (w32-add-charset-info "koi8-r" 'w32-charset-russian 20866)
   (w32-add-charset-info "iso8859-5" 'w32-charset-russian 28595)
-  (w32-add-charset-info "tis620-2533" 'w32-charset-thai 874)
+  (w32-add-charset-info "iso8859-11" 'w32-charset-thai 874)
   (w32-add-charset-info "windows-1258" 'w32-charset-vietnamese 1258)
   (w32-add-charset-info "ksc5601.1992" 'w32-charset-johab 1361)
   (w32-add-charset-info "mac-roman" 'w32-charset-mac 10000)
diff --git a/lisp/wdired.el b/lisp/wdired.el
index bb60e77..be0bde2 100644
--- a/lisp/wdired.el
+++ b/lisp/wdired.el
@@ -255,6 +255,7 @@ See `wdired-mode'."
   (setq buffer-read-only nil)
   (dired-unadvertise default-directory)
   (add-hook 'kill-buffer-hook 'wdired-check-kill-buffer nil t)
+  (add-hook 'after-change-functions 'wdired--restore-dired-filename-prop nil t)
   (setq major-mode 'wdired-mode)
   (setq mode-name "Editable Dired")
   (setq revert-buffer-function 'wdired-revert)
@@ -363,6 +364,7 @@ non-nil means return old filename."
   (setq mode-name "Dired")
   (dired-advertise)
   (remove-hook 'kill-buffer-hook 'wdired-check-kill-buffer t)
+  (remove-hook 'after-change-functions 'wdired--restore-dired-filename-prop t)
   (set (make-local-variable 'revert-buffer-function) 'dired-revert))
 
 
@@ -381,7 +383,6 @@ non-nil means return old filename."
 (defun wdired-finish-edit ()
   "Actually rename files based on your editing in the Dired buffer."
   (interactive)
-  (wdired-change-to-dired-mode)
   (let ((changes nil)
        (errors 0)
        files-deleted
@@ -423,6 +424,11 @@ non-nil means return old filename."
        (forward-line -1)))
     (when files-renamed
       (setq errors (+ errors (wdired-do-renames files-renamed))))
+    ;; We have to be in wdired-mode when wdired-do-renames is executed
+    ;; so that wdired--restore-dired-filename-prop runs, but we have
+    ;; to change back to dired-mode before reverting the buffer to
+    ;; avoid using wdired-revert, which changes back to wdired-mode.
+    (wdired-change-to-dired-mode)
     (if changes
        (progn
          ;; If we are displaying a single file (rather than the
@@ -543,19 +549,25 @@ and proceed depending on the answer."
     (goto-char (point-max))
     (forward-line -1)
     (let ((done nil)
+          (failed t)
          curr-filename)
       (while (and (not done) (not (bobp)))
         (setq curr-filename (wdired-get-filename nil t))
         (if (equal curr-filename filename-ori)
-            (progn
-              (setq done t)
-              (let ((inhibit-read-only t))
-                (dired-move-to-filename)
-                (search-forward (wdired-get-filename t) nil t)
-                (replace-match (file-name-nondirectory filename-ori) t t))
-              (dired-do-create-files-regexp
-               (function dired-rename-file)
-               "Move" 1 ".*" filename-new nil t))
+            (unwind-protect
+                (progn
+                  (setq done t)
+                  (let ((inhibit-read-only t))
+                    (dired-move-to-filename)
+                    (search-forward (wdired-get-filename t) nil t)
+                    (replace-match (file-name-nondirectory filename-ori) t t))
+                  (dired-do-create-files-regexp
+                   (function dired-rename-file)
+                   "Move" 1 ".*" filename-new nil t)
+                  (setq failed nil))
+              ;; If user types C-g when prompted to change the file
+              ;; name, make sure we return to dired-mode.
+              (when failed (wdired-change-to-dired-mode)))
          (forward-line -1))))))
 
 ;; marks a list of files for deletion
@@ -586,6 +598,25 @@ Optional arguments are ignored."
        (not (y-or-n-p "Buffer changed. Discard changes and kill buffer? ")))
       (error "Error")))
 
+;; Added to after-change-functions in wdired-change-to-wdired-mode to
+;; ensure that, on editing a file name, new characters get the
+;; dired-filename text property, which allows functions that look for
+;; this property (e.g. dired-isearch-filenames) to work in wdired-mode
+;; and also avoids an error with non-nil wdired-use-interactive-rename
+;; (bug#32173).
+(defun wdired--restore-dired-filename-prop (beg end _len)
+  (save-match-data
+    (save-excursion
+      (beginning-of-line)
+      (when (re-search-forward directory-listing-before-filename-regexp
+                               (line-end-position) t)
+        (setq beg (point)
+              end (if (and (file-symlink-p (dired-get-filename))
+                           (search-forward " -> " (line-end-position) t))
+                      (goto-char (match-beginning 0))
+                    (line-end-position)))
+        (put-text-property beg end 'dired-filename t)))))
+
 (defun wdired-next-line (arg)
   "Move down lines then position at filename or the current column.
 See `wdired-use-dired-vertical-movement'.  Optional prefix ARG
diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h
index ff43178..e4dec04 100644
--- a/nt/inc/ms-w32.h
+++ b/nt/inc/ms-w32.h
@@ -34,6 +34,11 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 # ifdef __MINGW64_VERSION_MAJOR
 #  define MINGW_W64
 # endif
+# if defined __MINGW32_VERSION && __MINGW32_VERSION >= 5001000L
+/* Avoid warnings about gettimeofday being deprecated.  */
+#  undef __POSIX_2008_DEPRECATED
+#  define __POSIX_2008_DEPRECATED
+# endif
 #endif
 
 /* #undef const */
@@ -455,7 +460,12 @@ extern char *get_emacs_configuration_options (void);
    windows.h.  For this to have proper effect, config.h must always be
    included before windows.h.  */
 #define _WINSOCKAPI_    1
-#define _WINSOCK_H
+#if !(defined __MINGW32_VERSION && __MINGW32_VERSION >= 5000002L)
+/* mingw.org's MinGW 5.x changed how it includes winsock.h and time.h,
+   and now defining _WINSOCK_H skips the definition of struct timeval,
+   which we don't want.  */
+# define _WINSOCK_H
+#endif
 
 /* Defines size_t and alloca ().  */
 #include <stdlib.h>
diff --git a/nt/inc/sys/socket.h b/nt/inc/sys/socket.h
index 2582cbd..de282c4 100644
--- a/nt/inc/sys/socket.h
+++ b/nt/inc/sys/socket.h
@@ -49,6 +49,11 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #define timeval ws_timeval
 #endif
 
+#if defined __MINGW32_VERSION && __MINGW32_VERSION >= 5000002L
+/* Need winerror.h before winsock2.h with mingw.org's MinGW 5.x,
+   otherwise some error codes are not defined.  */
+# include <winerror.h>
+#endif
 #include <winsock2.h>
 #include <ws2tcpip.h>
 /* process.c uses uint16_t (from C99) for IPv6, but
diff --git a/src/alloc.c b/src/alloc.c
index 8764591..ad716f5 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6585,7 +6585,7 @@ mark_object (Lisp_Object arg)
        CHECK_ALLOCATED_AND_LIVE (live_cons_p);
        CONS_MARK (ptr);
        /* If the cdr is nil, avoid recursion for the car.  */
-       if (EQ (ptr->u.s.u.cdr, Qnil))
+       if (NILP (ptr->u.s.u.cdr))
          {
            obj = ptr->u.s.car;
            cdr_count = 0;
diff --git a/src/callint.c b/src/callint.c
index c6e003e..807e1cc 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -200,7 +200,7 @@ fix_command (Lisp_Object input, Lisp_Object values)
                  carelt = XCAR (elt);
                  /* If it is (if X Y), look at Y.  */
                  if (EQ (carelt, Qif)
-                     && EQ (Fnthcdr (make_number (3), elt), Qnil))
+                     && NILP (Fnthcdr (make_number (3), elt)))
                    elt = Fnth (make_number (2), elt);
                  /* If it is (when ... Y), look at Y.  */
                  else if (EQ (carelt, Qwhen))
diff --git a/src/character.c b/src/character.c
index 6a68980..8920da2 100644
--- a/src/character.c
+++ b/src/character.c
@@ -34,6 +34,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "lisp.h"
 #include "character.h"
 #include "buffer.h"
+#include "dispextern.h"
 #include "composite.h"
 #include "disptab.h"
 
@@ -288,10 +289,15 @@ char_width (int c, struct Lisp_Char_Table *dp)
       if (VECTORP (disp))
        for (i = 0, width = 0; i < ASIZE (disp); i++)
          {
+           int c = -1;
            ch = AREF (disp, i);
-           if (CHARACTERP (ch))
+           if (GLYPH_CODE_P (ch))
+             c = GLYPH_CODE_CHAR (ch);
+           else if (CHARACTERP (ch))
+             c = XFASTINT (ch);
+           if (c >= 0)
              {
-               int w = CHARACTER_WIDTH (XFASTINT (ch));
+               int w = CHARACTER_WIDTH (c);
                if (INT_ADD_WRAPV (width, w, &width))
                  string_overflow ();
              }
diff --git a/src/chartab.c b/src/chartab.c
index 065ae4f..8998350 100644
--- a/src/chartab.c
+++ b/src/chartab.c
@@ -605,7 +605,7 @@ a cons of character codes (for characters in the range), or 
a character code.  *
   Lisp_Object val;
   CHECK_CHAR_TABLE (char_table);
 
-  if (EQ (range, Qnil))
+  if (NILP (range))
     val = XCHAR_TABLE (char_table)->defalt;
   else if (CHARACTERP (range))
     val = CHAR_TABLE_REF (char_table, XFASTINT (range));
@@ -642,7 +642,7 @@ or a character code.  Return VALUE.  */)
       for (i = 0; i < chartab_size[0]; i++)
        set_char_table_contents (char_table, i, value);
     }
-  else if (EQ (range, Qnil))
+  else if (NILP (range))
     set_char_table_defalt (char_table, value);
   else if (CHARACTERP (range))
     char_table_set (char_table, XINT (range), value);
diff --git a/src/dbusbind.c b/src/dbusbind.c
index 4ebea57..9642981 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -200,7 +200,7 @@ xd_symbol_to_dbus_type (Lisp_Object object)
    `dbus-send-signal', into corresponding C values appended as
    arguments to a D-Bus message.  */
 #define XD_OBJECT_TO_DBUS_TYPE(object)                                 \
-  ((EQ (object, Qt) || EQ (object, Qnil)) ? DBUS_TYPE_BOOLEAN          \
+  ((EQ (object, Qt) || NILP (object)) ? DBUS_TYPE_BOOLEAN              \
    : (NATNUMP (object)) ? DBUS_TYPE_UINT32                             \
    : (INTEGERP (object)) ? DBUS_TYPE_INT32                             \
    : (FLOATP (object)) ? DBUS_TYPE_DOUBLE                              \
@@ -360,7 +360,7 @@ xd_signature (char *signature, int dtype, int parent_type, 
Lisp_Object object)
       break;
 
     case DBUS_TYPE_BOOLEAN:
-      if (!EQ (object, Qt) && !EQ (object, Qnil))
+      if (!EQ (object, Qt) && !NILP (object))
        wrong_type_argument (intern ("booleanp"), object);
       sprintf (signature, "%c", dtype);
       break;
diff --git a/src/dired.c b/src/dired.c
index 5812c56..472ec11 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -1058,7 +1058,7 @@ return a list with one element, taken from 
`user-real-login-name'.  */)
 
   endpwent ();
 #endif
-  if (EQ (users, Qnil))
+  if (NILP (users))
     /* At least current user is always known. */
     users = list1 (Vuser_real_login_name);
   return users;
diff --git a/src/editfns.c b/src/editfns.c
index 4dbf480..0fbc5aa 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3256,21 +3256,9 @@ differences between the two buffers.  */)
      Instead, we announce a single modification for the entire
      modified region.  But don't do that if the caller inhibited
      modification hooks, because then they don't want that.  */
-  ptrdiff_t from, to;
   if (!inhibit_modification_hooks)
     {
-      ptrdiff_t k, l;
-
-      /* Find the first character position to be changed.  */
-      for (k = 0; k < size_a && !bit_is_set (ctx.deletions, k); k++)
-       ;
-      from = BEGV + k;
-
-      /* Find the last character position to be changed.  */
-      for (l = size_a; l > 0 && !bit_is_set (ctx.deletions, l - 1); l--)
-       ;
-      to = BEGV + l;
-      prepare_to_modify_buffer (from, to, NULL);
+      prepare_to_modify_buffer (BEGV, ZV, NULL);
       specbind (Qinhibit_modification_hooks, Qt);
       modification_hooks_inhibited = true;
     }
@@ -3322,9 +3310,8 @@ differences between the two buffers.  */)
 
   if (modification_hooks_inhibited)
     {
-      ptrdiff_t updated_to = to + ZV - BEGV - size_a;
-      signal_after_change (from, to - from, updated_to - from);
-      update_compositions (from, updated_to, CHECK_INSIDE);
+      signal_after_change (BEGV, size_a, ZV - BEGV);
+      update_compositions (BEGV, ZV, CHECK_INSIDE);
     }
 
   return Qnil;
@@ -4195,14 +4182,14 @@ Nth argument is substituted instead of the next one.  A 
format can
 contain either numbered or unnumbered %-sequences but not both, except
 that %% can be mixed with numbered %-sequences.
 
-The + flag character inserts a + before any positive number, while a
-space inserts a space before any positive number; these flags only
-affect %d, %e, %f, and %g sequences, and the + flag takes precedence.
+The + flag character inserts a + before any nonnegative number, while a
+space inserts a space before any nonnegative number; these flags
+affect only numeric %-sequences, and the + flag takes precedence.
 The - and 0 flags affect the width specifier, as described below.
 
 The # flag means to use an alternate display form for %o, %x, %X, %e,
 %f, and %g sequences: for %o, it ensures that the result begins with
-\"0\"; for %x and %X, it prefixes the result with \"0x\" or \"0X\";
+\"0\"; for %x and %X, it prefixes nonzero results with \"0x\" or \"0X\";
 for %e and %f, it causes a decimal point to be included even if the
 precision is zero; for %g, it causes a decimal point to be
 included even if the precision is zero, and also forces trailing
@@ -4736,10 +4723,22 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                }
              else
                {
-                 /* Don't sign-extend for octal or hex printing.  */
                  uprintmax_t x;
+                 bool negative;
                  if (INTEGERP (arg))
-                   x = XUINT (arg);
+                   {
+                     if (binary_as_unsigned)
+                       {
+                         x = XUINT (arg);
+                         negative = false;
+                       }
+                     else
+                       {
+                         EMACS_INT i = XINT (arg);
+                         negative = i < 0;
+                         x = negative ? -i : i;
+                       }
+                   }
                  else
                    {
                      double d = XFLOAT_DATA (arg);
@@ -4747,8 +4746,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool 
message)
                      if (! (0 <= d && d < uprintmax + 1))
                        xsignal1 (Qoverflow_error, arg);
                      x = d;
+                     negative = false;
                    }
-                 sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
+                 sprintf_buf[0] = negative ? '-' : plus_flag ? '+' : ' ';
+                 bool signedp = negative | plus_flag | space_flag;
+                 sprintf_bytes = sprintf (sprintf_buf + signedp,
+                                          convspec, prec, x);
+                 sprintf_bytes += signedp;
                }
 
              /* Now the length of the formatted item is known, except it omits
@@ -5558,6 +5562,22 @@ functions if all the text being accessed has this 
property.  */);
   DEFVAR_LISP ("operating-system-release", Voperating_system_release,
               doc: /* The release of the operating system Emacs is running on. 
 */);
 
+  DEFVAR_BOOL ("binary-as-unsigned",
+              binary_as_unsigned,
+              doc: /* Non-nil means `format' %x and %o treat integers as 
unsigned.
+This has machine-dependent results.  Nil means to treat integers as
+signed, which is portable; for example, if N is a negative integer,
+(read (format "#x%x") N) returns N only when this variable is nil.
+
+This variable is experimental; email address@hidden if you need
+it to be non-nil.  */);
+  /* For now, default to true if bignums exist, false in traditional Emacs.  */
+#ifdef lisp_h_FIXNUMP
+  binary_as_unsigned = false;
+#else
+  binary_as_unsigned = true;
+#endif
+
   defsubr (&Spropertize);
   defsubr (&Schar_equal);
   defsubr (&Sgoto_char);
diff --git a/src/emacs.c b/src/emacs.c
index 861d707..130a9f8 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2019,6 +2019,10 @@ all of which are called before Emacs is actually killed. 
 */
 {
   int exit_code;
 
+#ifdef HAVE_LIBSYSTEMD
+  sd_notify(0, "STOPPING=1");
+#endif /* HAVE_LIBSYSTEMD */
+
   /* Fsignal calls emacs_abort () if it sees that waiting_for_input is
      set.  */
   waiting_for_input = 0;
@@ -2479,6 +2483,13 @@ from the parent process and its tty file descriptors.  
*/)
     error ("This function can only be called after loading the init files");
 #ifndef WINDOWSNT
 
+  if (daemon_type == 1)
+    {
+#ifdef HAVE_LIBSYSTEMD
+      sd_notify(0, "READY=1");
+#endif /* HAVE_LIBSYSTEMD */
+    }
+
   if (daemon_type == 2)
     {
       int nfd;
diff --git a/src/eval.c b/src/eval.c
index 256ca8f..5964dd1 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1732,28 +1732,12 @@ xsignal3 (Lisp_Object error_symbol, Lisp_Object arg1, 
Lisp_Object arg2, Lisp_Obj
 }
 
 /* Signal `error' with message S, and additional arg ARG.
-   If ARG is not a genuine list, make it a one-element list.  */
+   If ARG is not a proper list, make it a one-element list.  */
 
 void
 signal_error (const char *s, Lisp_Object arg)
 {
-  Lisp_Object tortoise, hare;
-
-  hare = tortoise = arg;
-  while (CONSP (hare))
-    {
-      hare = XCDR (hare);
-      if (!CONSP (hare))
-       break;
-
-      hare = XCDR (hare);
-      tortoise = XCDR (tortoise);
-
-      if (EQ (hare, tortoise))
-       break;
-    }
-
-  if (!NILP (hare))
+  if (NILP (Fproper_list_p (arg)))
     arg = list1 (arg);
 
   xsignal (Qerror, Fcons (build_string (s), arg));
diff --git a/src/fileio.c b/src/fileio.c
index 5a1c7ae..2dcfb73 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -196,8 +196,8 @@ check_writable (const char *filename, int amode)
    list before reporting it; this saves report_file_errno's caller the
    trouble of preserving errno before calling list1.  */
 
-void
-report_file_errno (char const *string, Lisp_Object name, int errorno)
+Lisp_Object
+get_file_errno_data (char const *string, Lisp_Object name, int errorno)
 {
   Lisp_Object data = CONSP (name) || NILP (name) ? name : list1 (name);
   char *str = emacs_strerror (errorno);
@@ -207,10 +207,18 @@ report_file_errno (char const *string, Lisp_Object name, 
int errorno)
   Lisp_Object errdata = Fcons (errstring, data);
 
   if (errorno == EEXIST)
-    xsignal (Qfile_already_exists, errdata);
+    return Fcons (Qfile_already_exists, errdata);
   else
-    xsignal (errorno == ENOENT ? Qfile_missing : Qfile_error,
-            Fcons (build_string (string), errdata));
+    return Fcons (errorno == ENOENT ? Qfile_missing : Qfile_error,
+                 Fcons (build_string (string), errdata));
+}
+
+void
+report_file_errno (char const *string, Lisp_Object name, int errorno)
+{
+  Lisp_Object data = get_file_errno_data (string, name, errorno);
+
+  xsignal (Fcar (data), Fcdr (data));
 }
 
 /* Signal a file-access failure that set errno.  STRING describes the
@@ -2288,6 +2296,21 @@ The arg must be a string.  */)
   if (!NILP (handler))
     return call2 (handler, Qfile_name_case_insensitive_p, filename);
 
+  /* If the file doesn't exist, move up the filesystem tree until we
+     reach an existing directory or the root.  */
+  if (NILP (Ffile_exists_p (filename)))
+    {
+      filename = Ffile_name_directory (filename);
+      while (NILP (Ffile_exists_p (filename)))
+       {
+         Lisp_Object newname = expand_and_dir_to_file (filename);
+         /* Avoid infinite loop if the root is reported as non-existing
+            (impossible?).  */
+         if (!NILP (Fstring_equal (newname, filename)))
+           break;
+         filename = newname;
+       }
+    }
   filename = ENCODE_FILE (filename);
   return file_name_case_insensitive_p (SSDATA (filename)) ? Qt : Qnil;
 }
@@ -5714,7 +5737,7 @@ A non-nil CURRENT-ONLY argument means save only current 
buffer.  */)
                   spare the user annoying messages.  */
                && XFASTINT (BVAR (b, save_length)) > 5000
                /* These messages are frequent and annoying for `*mail*'.  */
-               && !EQ (BVAR (b, filename), Qnil)
+               && !NILP (BVAR (b, filename))
                && NILP (no_message))
              {
                /* It has shrunk too much; turn off auto-saving here.  */
diff --git a/src/fns.c b/src/fns.c
index c171784..5247140 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -144,6 +144,28 @@ which is at least the number of distinct elements.  */)
   return make_fixnum_or_float (len);
 }
 
+DEFUN ("proper-list-p", Fproper_list_p, Sproper_list_p, 1, 1, 0,
+       doc: /* Return OBJECT's length if it is a proper list, nil otherwise.
+A proper list is neither circular nor dotted (i.e., its last cdr is nil).  */
+       attributes: const)
+  (Lisp_Object object)
+{
+  intptr_t len = 0;
+  Lisp_Object last_tail = object;
+  Lisp_Object tail = object;
+  FOR_EACH_TAIL_SAFE (tail)
+    {
+      len++;
+      rarely_quit (len);
+      last_tail = XCDR (tail);
+    }
+  if (!NILP (last_tail))
+    return Qnil;
+  if (MOST_POSITIVE_FIXNUM < len)
+    xsignal0 (Qoverflow_error);
+  return make_number (len);
+}
+
 DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0,
        doc: /* Return the number of bytes in STRING.
 If STRING is multibyte, this may be greater than the length of STRING.  */)
@@ -718,7 +740,7 @@ concat (ptrdiff_t nargs, Lisp_Object *args,
     val = make_uninit_string (result_len);
 
   /* In `append', if all but last arg are nil, return last arg.  */
-  if (target_type == Lisp_Cons && EQ (val, Qnil))
+  if (target_type == Lisp_Cons && NILP (val))
     return last_tail;
 
   /* Copy the contents of the args into the result.  */
@@ -1419,6 +1441,29 @@ DEFUN ("elt", Felt, Selt, 2, 2, 0,
   return Faref (sequence, n);
 }
 
+enum { WORDS_PER_DOUBLE = (sizeof (double) / sizeof (EMACS_UINT)
+                          + (sizeof (double) % sizeof (EMACS_UINT) != 0)) };
+union double_and_words
+{
+  double val;
+  EMACS_UINT word[WORDS_PER_DOUBLE];
+};
+
+/* Return true if X and Y are the same floating-point value.
+   This looks at X's and Y's representation, since (unlike '==')
+   it returns true if X and Y are the same NaN.  */
+static bool
+same_float (Lisp_Object x, Lisp_Object y)
+{
+  union double_and_words
+    xu = { .val = XFLOAT_DATA (x) },
+    yu = { .val = XFLOAT_DATA (y) };
+  EMACS_UINT neql = 0;
+  for (int i = 0; i < WORDS_PER_DOUBLE; i++)
+    neql |= xu.word[i] ^ yu.word[i];
+  return !neql;
+}
+
 DEFUN ("member", Fmember, Smember, 2, 2, 0,
        doc: /* Return non-nil if ELT is an element of LIST.  Comparison done 
with `equal'.
 The value is actually the tail of LIST whose car is ELT.  */)
@@ -1457,7 +1502,7 @@ The value is actually the tail of LIST whose car is ELT.  
*/)
   FOR_EACH_TAIL (tail)
     {
       Lisp_Object tem = XCAR (tail);
-      if (FLOATP (tem) && equal_no_quit (elt, tem))
+      if (FLOATP (tem) && same_float (elt, tem))
        return tail;
     }
   CHECK_LIST_END (tail, list);
@@ -2170,12 +2215,14 @@ The PLIST is modified by side effects.  */)
 }
 
 DEFUN ("eql", Feql, Seql, 2, 2, 0,
-       doc: /* Return t if the two args are the same Lisp object.
-Floating-point numbers of equal value are `eql', but they may not be `eq'.  */)
+       doc: /* Return t if the two args are `eq' or are indistinguishable 
numbers.
+Floating-point values with the same sign, exponent and fraction are `eql'.
+This differs from numeric comparison: (eql 0.0 -0.0) returns nil and
+\(eql 0.0e+NaN 0.0e+NaN) returns t, whereas `=' does the opposite.  */)
   (Lisp_Object obj1, Lisp_Object obj2)
 {
   if (FLOATP (obj1))
-    return equal_no_quit (obj1, obj2) ? Qt : Qnil;
+    return FLOATP (obj2) && same_float (obj1, obj2) ? Qt : Qnil;
   else
     return EQ (obj1, obj2) ? Qt : Qnil;
 }
@@ -2185,8 +2232,8 @@ DEFUN ("equal", Fequal, Sequal, 2, 2, 0,
 They must have the same data type.
 Conses are compared by comparing the cars and the cdrs.
 Vectors and strings are compared element by element.
-Numbers are compared by value, but integers cannot equal floats.
- (Use `=' if you want integers and floats to be able to be equal.)
+Numbers are compared via `eql', so integers do not equal floats.
+\(Use `=' if you want integers and floats to be able to be equal.)
 Symbols must match exactly.  */)
   (Lisp_Object o1, Lisp_Object o2)
 {
@@ -2266,13 +2313,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum 
equal_kind equal_kind,
   switch (XTYPE (o1))
     {
     case Lisp_Float:
-      {
-       double d1 = XFLOAT_DATA (o1);
-       double d2 = XFLOAT_DATA (o2);
-       /* If d is a NaN, then d != d. Two NaNs should be `equal' even
-          though they are not =.  */
-       return d1 == d2 || (d1 != d1 && d2 != d2);
-      }
+      return same_float (o1, o2);
 
     case Lisp_Cons:
       if (equal_kind == EQUAL_NO_QUIT)
@@ -3706,24 +3747,20 @@ HASH_INDEX (struct Lisp_Hash_Table *h, ptrdiff_t idx)
   return XINT (AREF (h->index, idx));
 }
 
-/* Compare KEY1 which has hash code HASH1 and KEY2 with hash code
-   HASH2 in hash table H using `eql'.  Value is true if KEY1 and
-   KEY2 are the same.  */
+/* Compare KEY1 and KEY2 in hash table HT using `eql'.  Value is true
+   if KEY1 and KEY2 are the same.  KEY1 and KEY2 must not be eq.  */
 
 static bool
 cmpfn_eql (struct hash_table_test *ht,
           Lisp_Object key1,
           Lisp_Object key2)
 {
-  return (FLOATP (key1)
-         && FLOATP (key2)
-         && XFLOAT_DATA (key1) == XFLOAT_DATA (key2));
+  return FLOATP (key1) && FLOATP (key2) && same_float (key1, key2);
 }
 
 
-/* Compare KEY1 which has hash code HASH1 and KEY2 with hash code
-   HASH2 in hash table H using `equal'.  Value is true if KEY1 and
-   KEY2 are the same.  */
+/* Compare KEY1 and KEY2 in hash table HT using `equal'.  Value is
+   true if KEY1 and KEY2 are the same.  */
 
 static bool
 cmpfn_equal (struct hash_table_test *ht,
@@ -3734,9 +3771,8 @@ cmpfn_equal (struct hash_table_test *ht,
 }
 
 
-/* Compare KEY1 which has hash code HASH1, and KEY2 with hash code
-   HASH2 in hash table H using H->user_cmp_function.  Value is true
-   if KEY1 and KEY2 are the same.  */
+/* Compare KEY1 and KEY2 in hash table HT using HT->user_cmp_function.
+   Value is true if KEY1 and KEY2 are the same.  */
 
 static bool
 cmpfn_user_defined (struct hash_table_test *ht,
@@ -4328,18 +4364,8 @@ static EMACS_UINT
 sxhash_float (double val)
 {
   EMACS_UINT hash = 0;
-  enum {
-    WORDS_PER_DOUBLE = (sizeof val / sizeof hash
-                       + (sizeof val % sizeof hash != 0))
-  };
-  union {
-    double val;
-    EMACS_UINT word[WORDS_PER_DOUBLE];
-  } u;
-  int i;
-  u.val = val;
-  memset (&u.val + 1, 0, sizeof u - sizeof u.val);
-  for (i = 0; i < WORDS_PER_DOUBLE; i++)
+  union double_and_words u = { .val = val };
+  for (int i = 0; i < WORDS_PER_DOUBLE; i++)
     hash = sxhash_combine (hash, u.word[i]);
   return SXHASH_REDUCE (hash);
 }
@@ -5291,6 +5317,7 @@ this variable.  */);
   defsubr (&Srandom);
   defsubr (&Slength);
   defsubr (&Ssafe_length);
+  defsubr (&Sproper_list_p);
   defsubr (&Sstring_bytes);
   defsubr (&Sstring_distance);
   defsubr (&Sstring_equal);
diff --git a/src/frame.c b/src/frame.c
index d477c1a..85ec740 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -139,14 +139,9 @@ check_window_system (struct frame *f)
 /* Return the value of frame parameter PROP in frame FRAME.  */
 
 Lisp_Object
-get_frame_param (register struct frame *frame, Lisp_Object prop)
+get_frame_param (struct frame *frame, Lisp_Object prop)
 {
-  register Lisp_Object tem;
-
-  tem = Fassq (prop, frame->param_alist);
-  if (EQ (tem, Qnil))
-    return tem;
-  return Fcdr (tem);
+  return Fcdr (Fassq (prop, frame->param_alist));
 }
 
 
@@ -189,9 +184,9 @@ frame_inhibit_resize (struct frame *f, bool horizontal, 
Lisp_Object parameter)
          || (CONSP (frame_inhibit_implied_resize)
              && !NILP (Fmemq (parameter, frame_inhibit_implied_resize)))
          || (horizontal
-             && !EQ (fullscreen, Qnil) && !EQ (fullscreen, Qfullheight))
+             && !NILP (fullscreen) && !EQ (fullscreen, Qfullheight))
          || (!horizontal
-             && !EQ (fullscreen, Qnil) && !EQ (fullscreen, Qfullwidth))
+             && !NILP (fullscreen) && !EQ (fullscreen, Qfullwidth))
          || FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))
        : ((horizontal && f->inhibit_horizontal_resize)
          || (!horizontal && f->inhibit_vertical_resize)));
@@ -2808,10 +2803,8 @@ frames_discard_buffer (Lisp_Object buffer)
 void
 store_in_alist (Lisp_Object *alistptr, Lisp_Object prop, Lisp_Object val)
 {
-  register Lisp_Object tem;
-
-  tem = Fassq (prop, *alistptr);
-  if (EQ (tem, Qnil))
+  Lisp_Object tem = Fassq (prop, *alistptr);
+  if (NILP (tem))
     *alistptr = Fcons (Fcons (prop, val), *alistptr);
   else
     Fsetcdr (tem, val);
@@ -2975,7 +2968,7 @@ store_frame_param (struct frame *f, Lisp_Object prop, 
Lisp_Object val)
 
   /* Update the frame parameter alist.  */
   old_alist_elt = Fassq (prop, f->param_alist);
-  if (EQ (old_alist_elt, Qnil))
+  if (NILP (old_alist_elt))
     fset_param_alist (f, Fcons (Fcons (prop, val), f->param_alist));
   else
     Fsetcdr (old_alist_elt, val);
@@ -4516,13 +4509,13 @@ x_set_visibility (struct frame *f, Lisp_Object value, 
Lisp_Object oldval)
 void
 x_set_autoraise (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 {
-  f->auto_raise = !EQ (Qnil, arg);
+  f->auto_raise = !NILP (arg);
 }
 
 void
 x_set_autolower (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 {
-  f->auto_lower = !EQ (Qnil, arg);
+  f->auto_lower = !NILP (arg);
 }
 
 void
@@ -4973,7 +4966,7 @@ x_get_arg (Display_Info *dpyinfo, Lisp_Object alist, 
Lisp_Object param,
 
   /* If it wasn't specified in ALIST or the Lisp-level defaults,
      look in the X resources.  */
-  if (EQ (tem, Qnil))
+  if (NILP (tem))
     {
       if (attribute && dpyinfo)
        {
diff --git a/src/gnutls.c b/src/gnutls.c
index d7a4ee4..4e98f16 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -2071,7 +2071,14 @@ gnutls_symmetric (bool encrypting, Lisp_Object cipher,
     cipher = intern (SSDATA (cipher));
 
   if (SYMBOLP (cipher))
-    info = XCDR (Fassq (cipher, Fgnutls_ciphers ()));
+    {
+      info = Fassq (cipher, Fgnutls_ciphers ());
+      if (!CONSP (info))
+       xsignal2 (Qerror,
+                 build_string ("GnuTLS cipher is invalid or not found"),
+                 cipher);
+      info = XCDR (info);
+    }
   else if (TYPE_RANGED_INTEGERP (gnutls_cipher_algorithm_t, cipher))
     gca = XINT (cipher);
   else
@@ -2086,7 +2093,8 @@ gnutls_symmetric (bool encrypting, Lisp_Object cipher,
 
   ptrdiff_t key_size = gnutls_cipher_get_key_size (gca);
   if (key_size == 0)
-    error ("GnuTLS cipher is invalid or not found");
+    xsignal2 (Qerror,
+             build_string ("GnuTLS cipher is invalid or not found"), cipher);
 
   ptrdiff_t kstart_byte, kend_byte;
   const char *kdata = extract_data_from_object (key, &kstart_byte, &kend_byte);
@@ -2342,7 +2350,14 @@ itself. */)
     hash_method = intern (SSDATA (hash_method));
 
   if (SYMBOLP (hash_method))
-    info = XCDR (Fassq (hash_method, Fgnutls_macs ()));
+    {
+      info = Fassq (hash_method, Fgnutls_macs ());
+      if (!CONSP (info))
+       xsignal2 (Qerror,
+                 build_string ("GnuTLS MAC-method is invalid or not found"),
+                 hash_method);
+      info = XCDR (info);
+    }
   else if (TYPE_RANGED_INTEGERP (gnutls_mac_algorithm_t, hash_method))
     gma = XINT (hash_method);
   else
@@ -2357,7 +2372,9 @@ itself. */)
 
   ptrdiff_t digest_length = gnutls_hmac_get_len (gma);
   if (digest_length == 0)
-    error ("GnuTLS MAC-method is invalid or not found");
+    xsignal2 (Qerror,
+             build_string ("GnuTLS MAC-method is invalid or not found"),
+             hash_method);
 
   ptrdiff_t kstart_byte, kend_byte;
   const char *kdata = extract_data_from_object (key, &kstart_byte, &kend_byte);
@@ -2423,7 +2440,14 @@ the number itself. */)
     digest_method = intern (SSDATA (digest_method));
 
   if (SYMBOLP (digest_method))
-    info = XCDR (Fassq (digest_method, Fgnutls_digests ()));
+    {
+      info = Fassq (digest_method, Fgnutls_digests ());
+      if (!CONSP (info))
+       xsignal2 (Qerror,
+                 build_string ("GnuTLS digest-method is invalid or not found"),
+                 digest_method);
+      info = XCDR (info);
+    }
   else if (TYPE_RANGED_INTEGERP (gnutls_digest_algorithm_t, digest_method))
     gda = XINT (digest_method);
   else
@@ -2438,7 +2462,9 @@ the number itself. */)
 
   ptrdiff_t digest_length = gnutls_hash_get_len (gda);
   if (digest_length == 0)
-    error ("GnuTLS digest-method is invalid or not found");
+    xsignal2 (Qerror,
+             build_string ("GnuTLS digest-method is invalid or not found"),
+             digest_method);
 
   gnutls_hash_hd_t hash;
   int ret = gnutls_hash_init (&hash, gda);
diff --git a/src/image.c b/src/image.c
index 992b225..a83f064 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1610,7 +1610,7 @@ Anything else, means only clear those images which refer 
to FILTER,
 which is then usually a filename.  */)
   (Lisp_Object filter)
 {
-  if (!(EQ (filter, Qnil) || FRAMEP (filter)))
+  if (! (NILP (filter) || FRAMEP (filter)))
     clear_image_caches (filter);
   else
     clear_image_cache (decode_window_system_frame (filter), Qt);
diff --git a/src/intervals.c b/src/intervals.c
index 4c624ea..c3e137c 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -197,7 +197,7 @@ intervals_equal (INTERVAL i0, INTERVAL i1)
        }
 
       /* i0 has something i1 doesn't.  */
-      if (EQ (i1_val, Qnil))
+      if (NILP (i1_val))
        return false;
 
       /* i0 and i1 both have sym, but it has different values in each.  */
diff --git a/src/intervals.h b/src/intervals.h
index 162c4ef..f37372a 100644
--- a/src/intervals.h
+++ b/src/intervals.h
@@ -116,7 +116,7 @@ struct interval
 
 /* True if this is a default interval, which is the same as being null
    or having no properties.  */
-#define DEFAULT_INTERVAL_P(i) (!i || EQ ((i)->plist, Qnil))
+#define DEFAULT_INTERVAL_P(i) (!i || NILP ((i)->plist))
 
 /* Test what type of parent we have.  Three possibilities: another
    interval, a buffer or string object, or NULL.  */
diff --git a/src/json.c b/src/json.c
index ea941d7..afdd9a2 100644
--- a/src/json.c
+++ b/src/json.c
@@ -7,7 +7,7 @@ This file is part of GNU Emacs.
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or (at
-nyour option) any later version.
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/src/keyboard.c b/src/keyboard.c
index aa58e26..7ab9a60 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -3150,6 +3150,10 @@ help_char_p (Lisp_Object c)
 static void
 record_char (Lisp_Object c)
 {
+  /* quail.el binds this to avoid recording keys twice.  */
+  if (inhibit_record_char)
+    return;
+
   int recorded = 0;
 
   if (CONSP (c) && (EQ (XCAR (c), Qhelp_echo) || EQ (XCAR (c), 
Qmouse_movement)))
@@ -3256,7 +3260,7 @@ record_char (Lisp_Object c)
   /* Write c to the dribble file.  If c is a lispy event, write
      the event's symbol to the dribble file, in <brackets>.  Bleaugh.
      If you, dear reader, have a better idea, you've got the source.  :-) */
-  if (dribble)
+  if (dribble && NILP (Vexecuting_kbd_macro))
     {
       block_input ();
       if (INTEGERP (c))
@@ -10110,10 +10114,13 @@ DEFUN ("recursion-depth", Frecursion_depth, 
Srecursion_depth, 0, 0, 0,
 
 DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1,
        "FOpen dribble file: ",
-       doc: /* Start writing all keyboard characters to a dribble file called 
FILE.
+       doc: /* Start writing input events to a dribble file called FILE.
 If FILE is nil, close any open dribble file.
 The file will be closed when Emacs exits.
 
+The events written to the file include keyboard and mouse input
+events, but not events from executing keyboard macros.
+
 Be aware that this records ALL characters you type!
 This may include sensitive information such as passwords.  */)
   (Lisp_Object file)
@@ -11813,10 +11820,10 @@ if the command is in this list, the selection is not 
updated.  */);
 
   DEFVAR_LISP ("debug-on-event",
                Vdebug_on_event,
-               doc: /* Enter debugger on this event.  When Emacs
-receives the special event specified by this variable, it will try to
-break into the debugger as soon as possible instead of processing the
-event normally through `special-event-map'.
+               doc: /* Enter debugger on this event.
+When Emacs receives the special event specified by this variable,
+it will try to break into the debugger as soon as possible instead
+of processing the event normally through `special-event-map'.
 
 Currently, the only supported values for this
 variable are `sigusr1' and `sigusr2'.  */);
@@ -11824,21 +11831,23 @@ variable are `sigusr1' and `sigusr2'.  */);
 
   DEFVAR_BOOL ("attempt-stack-overflow-recovery",
                attempt_stack_overflow_recovery,
-               doc: /* If non-nil, attempt to recover from C stack
-overflow.  This recovery is unsafe and may lead to deadlocks or data
+               doc: /* If non-nil, attempt to recover from C stack overflows.
+This recovery is potentially unsafe and may lead to deadlocks or data
 corruption, but it usually works and may preserve modified buffers
 that would otherwise be lost.  If nil, treat stack overflow like any
-other kind of crash.  */);
+other kind of crash or fatal error.  */);
   attempt_stack_overflow_recovery = true;
 
   DEFVAR_BOOL ("attempt-orderly-shutdown-on-fatal-signal",
                attempt_orderly_shutdown_on_fatal_signal,
-               doc: /* If non-nil, attempt to perform an orderly
-shutdown when Emacs receives a fatal signal (e.g., a crash).
-This cleanup is unsafe and may lead to deadlocks or data corruption,
-but it usually works and may preserve modified buffers that would
-otherwise be lost.  If nil, crash immediately in response to fatal
-signals.  */);
+               doc: /* If non-nil, attempt orderly shutdown on fatal signals.
+By default this variable is non-nil, and Emacs attempts to perform
+an orderly shutdown when it catches a fatal signal (e.g., a crash).
+The orderly shutdown includes an attempt to auto-save your unsaved edits
+and other useful cleanups.  These cleanups are potentially unsafe and may
+lead to deadlocks or data corruption, but it usually works and may
+preserve data in modified buffers that would otherwise be lost.
+If nil, Emacs crashes immediately in response to fatal signals.  */);
   attempt_orderly_shutdown_on_fatal_signal = true;
 
   /* Create the initial keyboard.  Qt means 'unset'.  */
@@ -11848,6 +11857,14 @@ signals.  */);
                Vwhile_no_input_ignore_events,
                doc: /* Ignored events from while-no-input.  */);
   Vwhile_no_input_ignore_events = Qnil;
+
+  DEFVAR_BOOL ("inhibit--record-char",
+              inhibit_record_char,
+              doc: /* If non-nil, don't record input events.
+This inhibits recording input events for the purposes of keyboard
+macros, dribble file, and `recent-keys'.
+Internal use only.  */);
+  inhibit_record_char = false;
 }
 
 void
diff --git a/src/lisp.h b/src/lisp.h
index 731a45d..96de60e 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4015,6 +4015,7 @@ extern Lisp_Object write_region (Lisp_Object, 
Lisp_Object, Lisp_Object,
 extern void close_file_unwind (int);
 extern void fclose_unwind (void *);
 extern void restore_point_unwind (Lisp_Object);
+extern Lisp_Object get_file_errno_data (const char *, Lisp_Object, int);
 extern _Noreturn void report_file_errno (const char *, Lisp_Object, int);
 extern _Noreturn void report_file_error (const char *, Lisp_Object);
 extern _Noreturn void report_file_notify_error (const char *, Lisp_Object);
@@ -4698,7 +4699,7 @@ enum
 #define FOR_EACH_TAIL(tail) \
   FOR_EACH_TAIL_INTERNAL (tail, circular_list (tail), true)
 
-/* Like FOR_EACH_TAIL (LIST), except do not signal or quit.
+/* Like FOR_EACH_TAIL (TAIL), except do not signal or quit.
    If the loop exits due to a cycle, TAIL’s value is undefined.  */
 
 #define FOR_EACH_TAIL_SAFE(tail) \
diff --git a/src/lread.c b/src/lread.c
index 4ce6a44..50fc6ef 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3603,7 +3603,7 @@ substitute_object_recurse (struct subst *subst, 
Lisp_Object subtree)
     return subtree;
 
   /* If we've been to this node before, don't explore it again.  */
-  if (!EQ (Qnil, Fmemq (subtree, subst->seen)))
+  if (!NILP (Fmemq (subtree, subst->seen)))
     return subtree;
 
   /* If this node can be the entry point to a cycle, remember that
@@ -3798,10 +3798,11 @@ string_to_number (char const *string, int base, int 
flags)
 
       if (! (state & DOT_CHAR) && ! (flags & S2N_OVERFLOW_TO_FLOAT))
        {
-         AUTO_STRING (fmt, ("%s is out of fixnum range; "
+         AUTO_STRING (fmt, ("%s (base %d) is out of fixnum range; "
                             "maybe set `read-integer-overflow-as-float'?"));
          AUTO_STRING_WITH_LEN (arg, string, cp - string);
-         xsignal1 (Qoverflow_error, CALLN (Fformat_message, fmt, arg));
+         xsignal1 (Qoverflow_error,
+                   CALLN (Fformat_message, fmt, arg, make_number (base)));
        }
     }
 
@@ -4236,7 +4237,7 @@ usage: (unintern NAME OBARRAY)  */)
      session if we unintern them, as well as even more ways to use
      `setq' or `fset' or whatnot to make the Emacs session
      unusable.  Let's not go down this silly road.  --Stef  */
-  /* if (EQ (tem, Qnil) || EQ (tem, Qt))
+  /* if (NILP (tem) || EQ (tem, Qt))
        error ("Attempt to unintern t or nil"); */
 
   XSYMBOL (tem)->u.s.interned = SYMBOL_UNINTERNED;
diff --git a/src/menu.c b/src/menu.c
index e7d4d78..a088083 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -647,7 +647,7 @@ digest_single_submenu (int start, int end, bool 
top_level_items)
   i = start;
   while (i < end)
     {
-      if (EQ (AREF (menu_items, i), Qnil))
+      if (NILP (AREF (menu_items, i)))
        {
          submenu_stack[submenu_depth++] = save_wv;
          save_wv = prev_wv;
@@ -900,7 +900,7 @@ find_and_call_menu_selection (struct frame *f, int 
menu_bar_items_used,
 
   while (i < menu_bar_items_used)
     {
-      if (EQ (AREF (vector, i), Qnil))
+      if (NILP (AREF (vector, i)))
        {
          subprefix_stack[submenu_depth++] = prefix;
          prefix = entry;
@@ -985,7 +985,7 @@ find_and_return_menu_selection (struct frame *f, bool 
keymaps, void *client_data
 
   while (i < menu_items_used)
     {
-      if (EQ (AREF (menu_items, i), Qnil))
+      if (NILP (AREF (menu_items, i)))
         {
           subprefix_stack[submenu_depth++] = prefix;
           prefix = entry;
diff --git a/src/nsfns.m b/src/nsfns.m
index 9ff7e88..184657f 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -363,7 +363,7 @@ x_set_icon_name (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
       if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
         return;
     }
-  else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
+  else if (!STRINGP (oldval) && NILP (oldval) == NILP (arg))
     return;
 
   fset_icon_name (f, arg);
@@ -1291,7 +1291,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
   window_prompting = x_figure_window_size (f, parms, true, &x_width, 
&x_height);
 
   tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
-  f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !EQ (tem, Qnil));
+  f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !NILP (tem));
 
   /* NOTE: on other terms, this is done in set_mouse_color, however this
      was not getting called under Nextstep.  */
diff --git a/src/nsmenu.m b/src/nsmenu.m
index a438952..18c3230 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -828,7 +828,7 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
   i = 0;
   while (i < menu_items_used)
     {
-      if (EQ (AREF (menu_items, i), Qnil))
+      if (NILP (AREF (menu_items, i)))
        {
          submenu_stack[submenu_depth++] = save_wv;
          save_wv = prev_wv;
diff --git a/src/nsselect.m b/src/nsselect.m
index c72f179..e71a20e 100644
--- a/src/nsselect.m
+++ b/src/nsselect.m
@@ -164,7 +164,7 @@ ns_get_our_change_count_for (Lisp_Object selection)
 static void
 ns_string_to_pasteboard_internal (id pb, Lisp_Object str, NSString *gtype)
 {
-  if (EQ (str, Qnil))
+  if (NILP (str))
     {
       [pb declareTypes: [NSArray array] owner: nil];
     }
@@ -399,7 +399,7 @@ these literal upper-case names.)  The symbol nil is the 
same as
     return Qnil;
 
   CHECK_SYMBOL (selection);
-  if (EQ (selection, Qnil)) selection = QPRIMARY;
+  if (NILP (selection)) selection = QPRIMARY;
   if (EQ (selection, Qt)) selection = QSECONDARY;
   pb = ns_symbol_to_pb (selection);
   if (pb == nil) return Qnil;
@@ -421,7 +421,7 @@ and t is the same as `SECONDARY'.  */)
 {
   check_window_system (NULL);
   CHECK_SYMBOL (selection);
-  if (EQ (selection, Qnil)) selection = QPRIMARY;
+  if (NILP (selection)) selection = QPRIMARY;
   if (EQ (selection, Qt)) selection = QSECONDARY;
   return ns_get_pb_change_count (selection)
     == ns_get_our_change_count_for (selection)
diff --git a/src/process.c b/src/process.c
index 3fccd96..aafb46c 100644
--- a/src/process.c
+++ b/src/process.c
@@ -3587,17 +3587,23 @@ connect_network_socket (Lisp_Object proc, Lisp_Object 
addrinfos,
 
   if (s < 0)
     {
+      const char *err = (p->is_server
+                        ? "make server process failed"
+                        : "make client process failed");
+
       /* If non-blocking got this far - and failed - assume non-blocking is
         not supported after all.  This is probably a wrong assumption, but
         the normal blocking calls to open-network-stream handles this error
         better.  */
       if (p->is_non_blocking_client)
-       return;
+       {
+         Lisp_Object data = get_file_errno_data (err, contact, xerrno);
+
+         pset_status (p, list2 (Fcar (data), Fcdr (data)));
+         return;
+       }
 
-      report_file_errno ((p->is_server
-                         ? "make server process failed"
-                         : "make client process failed"),
-                        contact, xerrno);
+      report_file_errno (err, contact, xerrno);
     }
 
   inch = s;
@@ -4608,7 +4614,7 @@ is nil, from any process) before the timeout expired.  */)
 
       /* Can't wait for a process that is dedicated to a different
         thread.  */
-      if (!EQ (proc->thread, Qnil) && !EQ (proc->thread, Fcurrent_thread ()))
+      if (!NILP (proc->thread) && !EQ (proc->thread, Fcurrent_thread ()))
        {
          Lisp_Object proc_thread_name = XTHREAD (proc->thread)->name;
 
@@ -5015,7 +5021,7 @@ wait_reading_process_output (intmax_t time_limit, int 
nsecs, int read_kbd,
   struct timespec now = invalid_timespec ();
 
   eassert (wait_proc == NULL
-          || EQ (wait_proc->thread, Qnil)
+          || NILP (wait_proc->thread)
           || XTHREAD (wait_proc->thread) == current_thread);
 
   FD_ZERO (&Available);
diff --git a/src/terminal.c b/src/terminal.c
index 070b8aa..1b3acbe 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -483,7 +483,7 @@ static Lisp_Object
 store_terminal_param (struct terminal *t, Lisp_Object parameter, Lisp_Object 
value)
 {
   Lisp_Object old_alist_elt = Fassq (parameter, t->param_alist);
-  if (EQ (old_alist_elt, Qnil))
+  if (NILP (old_alist_elt))
     {
       tset_param_alist (t, Fcons (Fcons (parameter, value), t->param_alist));
       return Qnil;
diff --git a/src/textprop.c b/src/textprop.c
index f7e69f3..fe5b61e 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -2269,7 +2269,7 @@ verify_interval_modification (struct buffer *buf,
       if (!inhibit_modification_hooks)
        {
          hooks = Fnreverse (hooks);
-         while (! EQ (hooks, Qnil))
+         while (! NILP (hooks))
            {
              call_mod_hooks (Fcar (hooks), make_number (start),
                              make_number (end));
diff --git a/src/thread.c b/src/thread.c
index 3eba25b..1c73d93 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -681,7 +681,7 @@ invoke_thread_function (void)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
 
-  Ffuncall (1, &current_thread->function);
+  current_thread->result = Ffuncall (1, &current_thread->function);
   return unbind_to (count, Qnil);
 }
 
@@ -789,6 +789,7 @@ If NAME is given, it must be a string; it names the new 
thread.  */)
   new_thread->m_last_thing_searched = Qnil; /* copy from parent? */
   new_thread->m_saved_last_thing_searched = Qnil;
   new_thread->m_current_buffer = current_thread->m_current_buffer;
+  new_thread->result = Qnil;
   new_thread->error_symbol = Qnil;
   new_thread->error_data = Qnil;
   new_thread->event_object = Qnil;
@@ -933,12 +934,13 @@ thread_join_callback (void *arg)
 
 DEFUN ("thread-join", Fthread_join, Sthread_join, 1, 1, 0,
        doc: /* Wait for THREAD to exit.
-This blocks the current thread until THREAD exits or until
-the current thread is signaled.
-It is an error for a thread to try to join itself.  */)
+This blocks the current thread until THREAD exits or until the current
+thread is signaled.  It returns the result of the THREAD function.  It
+is an error for a thread to try to join itself.  */)
   (Lisp_Object thread)
 {
   struct thread_state *tstate;
+  Lisp_Object error_symbol, error_data;
 
   CHECK_THREAD (thread);
   tstate = XTHREAD (thread);
@@ -946,10 +948,16 @@ It is an error for a thread to try to join itself.  */)
   if (tstate == current_thread)
     error ("Cannot join current thread");
 
+  error_symbol = tstate->error_symbol;
+  error_data = tstate->error_data;
+
   if (thread_alive_p (tstate))
     flush_stack_call_func (thread_join_callback, tstate);
 
-  return Qnil;
+  if (!NILP (error_symbol))
+    Fsignal (error_symbol, error_data);
+
+  return tstate->result;
 }
 
 DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0,
@@ -973,11 +981,17 @@ DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0,
   return result;
 }
 
-DEFUN ("thread-last-error", Fthread_last_error, Sthread_last_error, 0, 0, 0,
-       doc: /* Return the last error form recorded by a dying thread.  */)
-  (void)
+DEFUN ("thread-last-error", Fthread_last_error, Sthread_last_error, 0, 1, 0,
+       doc: /* Return the last error form recorded by a dying thread.
+If CLEANUP is non-nil, remove this error form from history.  */)
+     (Lisp_Object cleanup)
 {
-  return last_thread_error;
+  Lisp_Object result = last_thread_error;
+
+  if (!NILP (cleanup))
+    last_thread_error = Qnil;
+
+  return result;
 }
 
 
@@ -1011,6 +1025,7 @@ init_main_thread (void)
   main_thread.m_saved_last_thing_searched = Qnil;
   main_thread.name = Qnil;
   main_thread.function = Qnil;
+  main_thread.result = Qnil;
   main_thread.error_symbol = Qnil;
   main_thread.error_data = Qnil;
   main_thread.event_object = Qnil;
@@ -1083,4 +1098,12 @@ syms_of_threads (void)
   DEFSYM (Qthreadp, "threadp");
   DEFSYM (Qmutexp, "mutexp");
   DEFSYM (Qcondition_variable_p, "condition-variable-p");
+
+  DEFVAR_LISP ("main-thread", Vmain_thread,
+    doc: /* The main thread of Emacs.  */);
+#ifdef THREADS_ENABLED
+  XSETTHREAD (Vmain_thread, &main_thread);
+#else
+  Vmain_thread = Qnil;
+#endif
 }
diff --git a/src/thread.h b/src/thread.h
index c10e5ec..922eea6 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -52,6 +52,9 @@ struct thread_state
   /* The thread's function.  */
   Lisp_Object function;
 
+  /* The thread's result, if function has finished.  */
+  Lisp_Object result;
+
   /* If non-nil, this thread has been signaled.  */
   Lisp_Object error_symbol;
   Lisp_Object error_data;
diff --git a/src/w32cygwinx.c b/src/w32cygwinx.c
index 8d3ae16..5d48c3a 100644
--- a/src/w32cygwinx.c
+++ b/src/w32cygwinx.c
@@ -24,6 +24,16 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "lisp.h"
 #include "w32common.h"
 
+static Lisp_Object ATTRIBUTE_FORMAT_PRINTF (1, 2)
+format_string (char const *format, ...)
+{
+  va_list args;
+  va_start (args, format);
+  Lisp_Object str = vformat_string (format, args);
+  va_end (args);
+  return str;
+}
+
 DEFUN ("w32-battery-status", Fw32_battery_status, Sw32_battery_status, 0, 0, 0,
        doc: /* Get power status information from Windows system.
 
@@ -92,32 +102,17 @@ The following %-sequences are provided:
       if (system_status.BatteryLifePercent > 100)
        load_percentage = build_string ("N/A");
       else
-       {
-         char buffer[16];
-         snprintf (buffer, 16, "%d", system_status.BatteryLifePercent);
-         load_percentage = build_string (buffer);
-       }
+       load_percentage = format_string ("%d", 
system_status.BatteryLifePercent);
 
       if (seconds_left < 0)
        seconds = minutes = hours = remain = build_string ("N/A");
       else
        {
-         long m;
-         double h;
-         char buffer[16];
-         snprintf (buffer, 16, "%ld", seconds_left);
-         seconds = build_string (buffer);
-
-         m = seconds_left / 60;
-         snprintf (buffer, 16, "%ld", m);
-         minutes = build_string (buffer);
-
-         h = seconds_left / 3600.0;
-         snprintf (buffer, 16, "%3.1f", h);
-         hours = build_string (buffer);
-
-         snprintf (buffer, 16, "%ld:%02ld", m / 60, m % 60);
-         remain = build_string (buffer);
+         long m = seconds_left / 60;
+         seconds = format_string ("%ld", seconds_left);
+         minutes = format_string ("%ld", m);
+         hours = format_string ("%3.1f", seconds_left / 3600.0);
+         remain = format_string ("%ld:%02ld", m / 60, m % 60);
        }
 
       status = listn (CONSTYPE_HEAP, 8,
diff --git a/src/w32term.c b/src/w32term.c
index ff0d2bf..0ae173a 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -1476,7 +1476,7 @@ x_draw_glyphless_glyph_string_foreground (struct 
glyph_string *s)
        {
          sprintf ((char *) buf, "%0*X",
                   glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
-                  (unsigned int) glyph->u.glyphless.ch);
+                  (unsigned int) glyph->u.glyphless.ch & 0xffffff);
          str = buf;
        }
 
diff --git a/src/xdisp.c b/src/xdisp.c
index 1199e1c..316c12e 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -8384,7 +8384,7 @@ next_element_from_buffer (struct it *it)
   eassert (IT_CHARPOS (*it) >= BEGV);
   eassert (NILP (it->string) && !it->s);
   eassert (!it->bidi_p
-          || (EQ (it->bidi_it.string.lstring, Qnil)
+          || (NILP (it->bidi_it.string.lstring)
               && it->bidi_it.string.s == NULL));
 
   /* With bidi reordering, the character to display might not be the
diff --git a/src/xfaces.c b/src/xfaces.c
index eea0672..0f9a741 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -2971,7 +2971,7 @@ FRAME 0 means change the face on all frames, and change 
the default
       if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
        if ((SYMBOLP (value)
             && !EQ (value, Qt)
-            && !EQ (value, Qnil))
+            && !NILP (value))
            /* Overline color.  */
            || (STRINGP (value)
                && SCHARS (value) == 0))
@@ -2985,7 +2985,7 @@ FRAME 0 means change the face on all frames, and change 
the default
       if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value))
        if ((SYMBOLP (value)
             && !EQ (value, Qt)
-            && !EQ (value, Qnil))
+            && !NILP (value))
            /* Strike-through color.  */
            || (STRINGP (value)
                && SCHARS (value) == 0))
diff --git a/src/xfns.c b/src/xfns.c
index fe8170c..66e49df 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -1456,7 +1456,7 @@ x_set_icon_type (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
       if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
        return;
     }
-  else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
+  else if (!STRINGP (oldval) && NILP (oldval) == NILP (arg))
     return;
 
   block_input ();
@@ -5722,7 +5722,7 @@ If TERMINAL is omitted or nil, that stands for the 
selected frame's display.  */
 {
   struct x_display_info *dpyinfo = check_x_display_info (terminal);
 
-  XSynchronize (dpyinfo->display, !EQ (on, Qnil));
+  XSynchronize (dpyinfo->display, !NILP (on));
 
   return Qnil;
 }
diff --git a/src/xmenu.c b/src/xmenu.c
index 58fba8c..a99e8ab 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1487,7 +1487,7 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
   i = 0;
   while (i < menu_items_used)
     {
-      if (EQ (AREF (menu_items, i), Qnil))
+      if (NILP (AREF (menu_items, i)))
        {
          submenu_stack[submenu_depth++] = save_wv;
          save_wv = prev_wv;
@@ -1656,7 +1656,7 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
       i = 0;
       while (i < menu_items_used)
        {
-         if (EQ (AREF (menu_items, i), Qnil))
+         if (NILP (AREF (menu_items, i)))
            {
              subprefix_stack[submenu_depth++] = prefix;
              prefix = entry;
diff --git a/src/xselect.c b/src/xselect.c
index 1f51be4..8448944 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -2094,7 +2094,7 @@ On Nextstep, TERMINAL is unused.  */)
   struct frame *f = frame_for_x_selection (terminal);
 
   CHECK_SYMBOL (selection);
-  if (EQ (selection, Qnil)) selection = QPRIMARY;
+  if (NILP (selection)) selection = QPRIMARY;
   if (EQ (selection, Qt)) selection = QSECONDARY;
 
   if (f && !NILP (LOCAL_SELECTION (selection, FRAME_DISPLAY_INFO (f))))
@@ -2124,7 +2124,7 @@ On Nextstep, TERMINAL is unused.  */)
   struct x_display_info *dpyinfo;
 
   CHECK_SYMBOL (selection);
-  if (EQ (selection, Qnil)) selection = QPRIMARY;
+  if (NILP (selection)) selection = QPRIMARY;
   if (EQ (selection, Qt)) selection = QSECONDARY;
 
   if (!f)
diff --git a/src/xwidget.c b/src/xwidget.c
index 2a53966..758e640 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -1099,7 +1099,7 @@ xwidget_view_lookup (struct xwidget *xw, struct window *w)
 
   ret = Fxwidget_view_lookup (xwidget, window);
 
-  return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
+  return NILP (ret) ? NULL : XXWIDGET_VIEW (ret);
 }
 
 struct xwidget *
diff --git a/test/Makefile.in b/test/Makefile.in
index 6070932..0bc893b 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -169,7 +169,6 @@ WRITE_LOG = > $@ 2>&1 || { STAT=$$?; cat $@; exit $$STAT; }
 ifdef EMACS_HYDRA_CI
 ## On Hydra, always show logs for certain problematic tests.
 lisp/net/tramp-tests.log \
-lisp/epg-tests.log \
 : WRITE_LOG = 2>&1 | tee $@
 endif
 
diff --git a/test/lisp/auth-source-tests.el b/test/lisp/auth-source-tests.el
index be516f2..ca8a3eb 100644
--- a/test/lisp/auth-source-tests.el
+++ b/test/lisp/auth-source-tests.el
@@ -344,5 +344,25 @@
      "session"
      (format "address@hidden" (plist-get auth-info :user) (plist-get auth-info 
:host)))))
 
+(ert-deftest auth-source-delete ()
+  (let* ((netrc-file (make-temp-file "auth-source-test" nil nil "\
+machine a1 port a2 user a3 password a4
+machine b1 port b2 user b3 password b4
+machine c1 port c2 user c3 password c4\n"))
+         (auth-sources (list netrc-file))
+         (auth-source-do-cache nil)
+         (expected '((:host "a1" :port "a2" :user "a3" :secret "a4")))
+         (parameters '(:max 1 :host t)))
+    (unwind-protect
+        (let ((found (apply #'auth-source-delete parameters)))
+          (dolist (f found)
+            (let ((s (plist-get f :secret)))
+              (setf f (plist-put f :secret
+                                 (if (functionp s) (funcall s) s)))))
+          ;; Note: The netrc backend doesn't delete anything, so
+          ;; this is actually the same as `auth-source-search'.
+          (should (equal found expected)))
+      (delete-file netrc-file))))
+
 (provide 'auth-source-tests)
 ;;; auth-source-tests.el ends here
diff --git a/test/lisp/emacs-lisp/lisp-mode-tests.el 
b/test/lisp/emacs-lisp/lisp-mode-tests.el
index 8598d41..30f606d 100644
--- a/test/lisp/emacs-lisp/lisp-mode-tests.el
+++ b/test/lisp/emacs-lisp/lisp-mode-tests.el
@@ -113,6 +113,29 @@ noindent\" 3
       ;; we're indenting ends on the previous line.
       (should (equal (buffer-string) original)))))
 
+(ert-deftest indent-sexp-go ()
+  "Make sure `indent-sexp' doesn't stop after #s."
+  ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31984.
+  (with-temp-buffer
+    (emacs-lisp-mode)
+    (insert "#s(foo\nbar)\n")
+    (goto-char (point-min))
+    (indent-sexp)
+    (should (equal (buffer-string) "\
+#s(foo
+   bar)\n"))))
+
+(ert-deftest indent-sexp-cant-go ()
+  "`indent-sexp' shouldn't error before a sexp."
+  ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31984#32.
+  (with-temp-buffer
+    (emacs-lisp-mode)
+    (insert "(())")
+    (goto-char (1+ (point-min)))
+    ;; Paredit calls `indent-sexp' from this position.
+    (indent-sexp)
+    (should (equal (buffer-string) "(())"))))
+
 (ert-deftest lisp-indent-region ()
   "Test basics of `lisp-indent-region'."
   (with-temp-buffer
diff --git a/test/lisp/emacs-lisp/package-tests.el 
b/test/lisp/emacs-lisp/package-tests.el
index b1adfab..f08bc92 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -473,7 +473,17 @@ Must called from within a `tar-mode' buffer."
                     (let ((process-environment
                            (cons (concat "HOME=" homedir)
                                  process-environment)))
-                      (epg-find-configuration 'OpenPGP))
+                      (epg-find-configuration
+                        'OpenPGP nil
+                        ;; By default we require gpg2 2.1+ due to some
+                        ;; practical problems with pinentry.  But this
+                        ;; test works fine with 2.0 as well.
+                        (let ((prog-alist (copy-tree 
epg-config--program-alist)))
+                          (setf (alist-get "gpg2"
+                                           (alist-get 'OpenPGP prog-alist)
+                                           nil nil #'equal)
+                                "2.0")
+                          prog-alist)))
                   (delete-directory homedir t))))
   (let* ((keyring (expand-file-name "key.pub" package-test-data-dir))
         (package-test-data-dir
diff --git a/test/lisp/epg-tests.el b/test/lisp/epg-tests.el
index c34e589..c1e98a6 100644
--- a/test/lisp/epg-tests.el
+++ b/test/lisp/epg-tests.el
@@ -23,7 +23,6 @@
 
 (require 'ert)
 (require 'epg)
-(require 'trace)
 
 (defvar epg-tests-context nil)
 
@@ -33,17 +32,26 @@
 
 (defconst epg-tests--config-program-alist
   ;; The default `epg-config--program-alist' requires gpg2 2.1 or
-  ;; greater due to some practical problems with pinentry.  But the
-  ;; tests here all work fine with 2.0 as well.
-  (let ((prog-alist (copy-sequence epg-config--program-alist)))
+  ;; greater due to some practical problems with pinentry.  But most
+  ;; tests here work fine with 2.0 as well.
+  (let ((prog-alist (copy-tree epg-config--program-alist)))
     (setf (alist-get "gpg2"
                      (alist-get 'OpenPGP prog-alist)
                      nil nil #'equal)
           "2.0")
     prog-alist))
 
-(defun epg-tests-find-usable-gpg-configuration (&optional _require-passphrase)
-  (epg-find-configuration 'OpenPGP 'no-cache epg-tests--config-program-alist))
+(defun epg-tests-find-usable-gpg-configuration
+    (&optional require-passphrase require-public-key)
+  ;; Clear config cache because we may be using a different
+  ;; program-alist.  We do want to update the cache, so that
+  ;; `epg-make-context' can use our result.
+  (setq epg--configurations nil)
+  (epg-find-configuration 'OpenPGP nil
+                          ;; The symmetric operations fail on Hydra
+                          ;; with gpg 2.0.
+                          (if (or (not require-passphrase) require-public-key)
+                              epg-tests--config-program-alist)))
 
 (defun epg-tests-passphrase-callback (_c _k _d)
   ;; Need to create a copy here, since the string will be wiped out
@@ -63,14 +71,12 @@
                  (format "GNUPGHOME=%s" epg-tests-home-directory))
            process-environment)))
      (unwind-protect
-         (let ((context (epg-make-context 'OpenPGP))
-               (epg-config (epg-tests-find-usable-gpg-configuration
-                            ,(if require-passphrase
-                                 `'require-passphrase))))
-           ;; GNUPGHOME is needed to find a usable gpg, so we can't
-           ;; check whether to skip any earlier (Bug#23561).
-           (unless epg-config
-             (ert-skip "No usable gpg config"))
+         ;; GNUPGHOME is needed to find a usable gpg, so we can't
+         ;; check whether to skip any earlier (Bug#23561).
+         (let ((epg-config (or (epg-tests-find-usable-gpg-configuration
+                                ,require-passphrase ,require-public-key)
+                               (ert-skip "No usable gpg config")))
+               (context (epg-make-context 'OpenPGP)))
            (setf (epg-context-program context)
                  (alist-get 'program epg-config))
           (setf (epg-context-home-directory context)
diff --git a/test/lisp/shadowfile-tests.el b/test/lisp/shadowfile-tests.el
new file mode 100644
index 0000000..085ab47
--- /dev/null
+++ b/test/lisp/shadowfile-tests.el
@@ -0,0 +1,932 @@
+;;; shadowfile-tests.el --- Tests of shadowfile
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; Author: Michael Albinus <address@hidden>
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see `https://www.gnu.org/licenses/'.
+
+;;; Commentary:
+
+;; Some of the tests require access to a remote host files.  Since
+;; this could be problematic, a mock-up connection method "mock" is
+;; used.  Emulating a remote connection, it simply calls "sh -i".
+;; Tramp's file name handlers still run, so this test is sufficient
+;; except for connection establishing.
+
+;; If you want to test a real Tramp connection, set
+;; $REMOTE_TEMPORARY_FILE_DIRECTORY to a suitable value in order to
+;; overwrite the default value.  If you want to skip tests accessing a
+;; remote host, set this environment variable to "/dev/null" or
+;; whatever is appropriate on your system.
+
+;; A whole test run can be performed calling the command `shadowfile-test-all'.
+
+;;; Code:
+
+(require 'ert)
+(require 'shadowfile)
+(require 'tramp)
+
+;; There is no default value on w32 systems, which could work out of the box.
+(defconst shadow-test-remote-temporary-file-directory
+  (cond
+   ((getenv "REMOTE_TEMPORARY_FILE_DIRECTORY"))
+   ((eq system-type 'windows-nt) null-device)
+   (t (add-to-list
+       'tramp-methods
+       '("mock"
+        (tramp-login-program        "sh")
+        (tramp-login-args           (("-i")))
+        (tramp-remote-shell         "/bin/sh")
+        (tramp-remote-shell-args    ("-c"))
+        (tramp-connection-timeout   10)))
+      (add-to-list
+       'tramp-default-host-alist
+       `("\\`mock\\'" nil ,(system-name)))
+      ;; Emacs' Makefile sets $HOME to a nonexistent value.  Needed in
+      ;; batch mode only, therefore.  It cannot be
+      ;; `temporary-directory', because the tests with "~" would fail.
+      (unless (and (null noninteractive) (file-directory-p "~/"))
+        (setenv "HOME" invocation-directory))
+      (format "/mock::%s" temporary-file-directory)))
+  "Temporary directory for Tramp tests.")
+
+(defconst shadow-test-info-file
+  (expand-file-name "shadows_test" temporary-file-directory)
+  "File to keep shadow information in during tests.")
+
+(defconst shadow-test-todo-file
+  (expand-file-name "shadow_todo_test" temporary-file-directory)
+  "File to store the list of uncopied shadows in during tests.")
+
+(ert-deftest shadow-test00-clusters ()
+  "Check cluster definitions.
+Per definition, all files are identical on the different hosts of
+a cluster (or site).  This is not tested here; it must be
+guaranteed by the originator of a cluster definition."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((text-quoting-style 'grave) ;; We inspect the *Messages* buffer!
+        (inhibit-message t)
+        (shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+       shadow-clusters
+       cluster primary regexp mocked-input)
+    (unwind-protect
+       ;; We must mock `read-from-minibuffer' and `read-string', in
+       ;; order to avoid interactive arguments.
+       (cl-letf* (((symbol-function 'read-from-minibuffer)
+                   (lambda (&rest args) (pop mocked-input)))
+                  ((symbol-function 'read-string)
+                   (lambda (&rest args) (pop mocked-input))))
+
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+         ;; Define a cluster.
+         (setq cluster "cluster"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary)
+               mocked-input `(,cluster ,primary ,regexp))
+         (call-interactively 'shadow-define-cluster)
+         (should
+          (string-equal
+           (shadow-cluster-name (shadow-get-cluster cluster)) cluster))
+         (should
+          (string-equal
+           (shadow-cluster-primary (shadow-get-cluster cluster)) primary))
+         (should
+          (string-equal
+           (shadow-cluster-regexp (shadow-get-cluster cluster)) regexp))
+          (should-not (shadow-get-cluster "non-existent-cluster-name"))
+
+          ;; Test `shadow-set-cluster' and `make-shadow-cluster'.
+         (shadow-set-cluster cluster primary regexp)
+         (should
+          (equal (shadow-get-cluster cluster)
+                 (make-shadow-cluster
+                  :name cluster :primary primary :regexp regexp)))
+
+         ;; The primary must be either `shadow-system-name', or a remote file.
+         (setq ;; The second "cluster" is wrong.
+               mocked-input `(,cluster ,cluster ,primary ,regexp))
+          (with-current-buffer (messages-buffer)
+            (narrow-to-region (point-max) (point-max)))
+         (call-interactively 'shadow-define-cluster)
+         (should
+           (string-match
+            (regexp-quote "Not a valid primary!")
+            (with-current-buffer (messages-buffer) (buffer-string))))
+         ;; The first cluster definition is still valid.
+         (should
+          (string-equal
+           (shadow-cluster-name (shadow-get-cluster cluster)) cluster))
+         (should
+          (string-equal
+           (shadow-cluster-primary (shadow-get-cluster cluster)) primary))
+         (should
+          (string-equal
+           (shadow-cluster-regexp (shadow-get-cluster cluster)) regexp))
+
+         ;; The regexp must match the primary name.
+         (setq ;; The second "cluster" is wrong.
+               mocked-input `(,cluster ,primary ,cluster ,regexp))
+          (with-current-buffer (messages-buffer)
+            (narrow-to-region (point-max) (point-max)))
+         (call-interactively 'shadow-define-cluster)
+         (should
+           (string-match
+            (regexp-quote "Regexp doesn't include the primary host!")
+            (with-current-buffer (messages-buffer) (buffer-string))))
+         ;; The first cluster definition is still valid.
+         (should
+          (string-equal
+           (shadow-cluster-name (shadow-get-cluster cluster)) cluster))
+         (should
+          (string-equal
+           (shadow-cluster-primary (shadow-get-cluster cluster)) primary))
+         (should
+          (string-equal
+           (shadow-cluster-regexp (shadow-get-cluster cluster)) regexp))
+
+         ;; Redefine the cluster.
+         (setq primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (shadow-regexp-superquote primary)
+               mocked-input `(,cluster ,primary ,regexp))
+         (call-interactively 'shadow-define-cluster)
+         (should
+          (string-equal
+           (shadow-cluster-name (shadow-get-cluster cluster)) cluster))
+         (should
+          (string-equal
+           (shadow-cluster-primary (shadow-get-cluster cluster)) primary))
+         (should
+          (string-equal
+           (shadow-cluster-regexp (shadow-get-cluster cluster)) regexp))
+
+          ;; Test `shadow-set-cluster' and `make-shadow-cluster'.
+         (shadow-set-cluster cluster primary regexp)
+         (should
+          (equal (shadow-get-cluster cluster)
+                 (make-shadow-cluster
+                  :name cluster :primary primary :regexp regexp))))
+
+      ;; Cleanup.
+      (with-current-buffer (messages-buffer) (widen))
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file)))))
+
+(ert-deftest shadow-test01-sites ()
+  "Check site definitions.
+Per definition, all files are identical on the different hosts of
+a cluster (or site).  This is not tested here; it must be
+guaranteed by the originator of a cluster definition."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+       shadow-clusters
+       cluster1 cluster2 primary1 primary2 regexp1 regexp2 mocked-input)
+    (unwind-protect
+       ;; We must mock `read-from-minibuffer' and `read-string', in
+       ;; order to avoid interactive arguments.
+       (cl-letf* (((symbol-function 'read-from-minibuffer)
+                   (lambda (&rest args) (pop mocked-input)))
+                  ((symbol-function 'read-string)
+                   (lambda (&rest args) (pop mocked-input))))
+
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+         ;; Define a cluster.
+         (setq cluster1 "cluster1"
+               primary1 shadow-system-name
+               regexp1 (shadow-regexp-superquote primary1))
+         (shadow-set-cluster cluster1 primary1 regexp1)
+
+         ;; A site is either a cluster identification, or a primary host.
+          (should (string-equal cluster1 (shadow-site-name cluster1)))
+          (should (string-equal primary1 (shadow-name-site primary1)))
+          (should
+           (string-equal (format "/%s:" cluster1) (shadow-name-site cluster1)))
+          (should (string-equal (system-name) (shadow-site-name primary1)))
+          (should
+           (string-equal
+            (file-remote-p shadow-test-remote-temporary-file-directory)
+            (shadow-name-site
+             (file-remote-p shadow-test-remote-temporary-file-directory))))
+          (should
+           (string-equal
+            (file-remote-p shadow-test-remote-temporary-file-directory)
+            (shadow-site-name
+             (file-remote-p shadow-test-remote-temporary-file-directory))))
+
+          (should (equal (shadow-site-cluster cluster1)
+                        (shadow-get-cluster cluster1)))
+         (should (equal (shadow-site-cluster (shadow-name-site cluster1))
+                        (shadow-get-cluster cluster1)))
+         (should (equal (shadow-site-cluster primary1)
+                        (shadow-get-cluster cluster1)))
+         (should (equal (shadow-site-cluster (shadow-site-name primary1))
+                        (shadow-get-cluster cluster1)))
+         (should (string-equal (shadow-site-primary cluster1) primary1))
+         (should (string-equal (shadow-site-primary primary1) primary1))
+
+          ;; `shadow-read-site' accepts "cluster", "/cluster:",
+          ;; "system", "/system:".  It shall reject bad site names.
+         (setq mocked-input
+                `(,cluster1 ,(shadow-name-site cluster1)
+                  ,primary1 ,(shadow-site-name primary1)
+                  ,shadow-system-name "" "bad" "/bad:"))
+         (should (string-equal (shadow-read-site) cluster1))
+         (should (string-equal (shadow-read-site) (shadow-name-site cluster1)))
+         (should (string-equal (shadow-read-site) primary1))
+         (should (string-equal (shadow-read-site) (shadow-site-name primary1)))
+         (should (string-equal (shadow-read-site) shadow-system-name))
+         (should-not (shadow-read-site)) ; ""
+         (should-not (shadow-read-site)) ; "bad"
+         (should-not (shadow-read-site)) ; "/bad:"
+         (should-error (shadow-read-site)) ; no input at all
+
+         ;; Define a second cluster.
+          (setq cluster2 "cluster2"
+               primary2
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp2 (format "^\\(%s\\|%s\\)$" shadow-system-name primary2))
+         (shadow-set-cluster cluster2 primary2 regexp2)
+
+          ;; `shadow-site-match' shall know all different kind of site names.
+          (should (shadow-site-match cluster1 cluster1))
+          (should (shadow-site-match primary1 primary1))
+          (should (shadow-site-match cluster1 primary1))
+          (should (shadow-site-match primary1 cluster1))
+          (should (shadow-site-match cluster2 cluster2))
+          (should (shadow-site-match primary2 primary2))
+          (should (shadow-site-match cluster2 primary2))
+          (should (shadow-site-match primary2 cluster2))
+
+          ;; The regexp of `cluster2' matches the primary of
+          ;; `cluster1'.  Not vice versa.
+          (should (shadow-site-match cluster2 cluster1))
+          (should-not (shadow-site-match cluster1 cluster2))
+
+          ;; If we use the primaries of a cluster, it doesn't match.
+          (should-not
+           (shadow-site-match (shadow-site-primary cluster2) cluster1))
+          (should-not
+           (shadow-site-match (shadow-site-primary cluster1) cluster2)))
+
+      ;; Cleanup.
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file)))))
+
+(ert-deftest shadow-test02-files ()
+  "Check file manipulation functions."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+       shadow-clusters
+       cluster primary regexp file hup)
+    (unwind-protect
+       (progn
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+         ;; Define a cluster.
+         (setq cluster "cluster"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary)
+                file (make-temp-name
+                      (expand-file-name
+                       "shadowfile-tests" temporary-file-directory)))
+         (shadow-set-cluster cluster primary regexp)
+
+          ;; The constant structure to compare with.
+          (setq hup (make-tramp-file-name :host (system-name) :localname file))
+
+          ;; The structure a local file is transformed in.
+          (should (equal (shadow-parse-name file) hup))
+          (should (equal (shadow-parse-name (concat "/" cluster ":" file)) 
hup))
+          (should (equal (shadow-parse-name (concat primary file)) hup))
+
+          ;; A local file name is kept.
+          (should
+           (string-equal (shadow-local-file file) file))
+          ;; A file on this cluster is also local.
+          (should
+           (string-equal
+           (shadow-local-file (concat "/" cluster ":" file)) file))
+          ;; A file on the primary host is also local.
+          (should
+           (string-equal (shadow-local-file (concat primary file)) file))
+
+         ;; Redefine the cluster.
+         (setq primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster primary regexp)
+
+          ;; The structure of the local file is still the same.
+          (should (equal (shadow-parse-name file) hup))
+          ;; The cluster name must be used.
+          (setf (tramp-file-name-host hup) cluster)
+          (should (equal (shadow-parse-name (concat "/" cluster ":" file)) 
hup))
+          ;; The structure of a remote file is different.
+          (should
+           (equal (shadow-parse-name (concat primary file))
+                  (tramp-dissect-file-name (concat primary file))))
+
+          ;; A local file is still local.
+          (should (shadow-local-file file))
+          ;; A file on this cluster is not local.
+          (should-not (shadow-local-file (concat "/" cluster ":" file)))
+          ;; A file on the primary host is not local.
+          (should-not (shadow-local-file (concat primary file)))
+         ;; There's no error on wrong FILE.
+         (should-not (shadow-local-file nil)))
+
+      ;; Cleanup.
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file)))))
+
+(ert-deftest shadow-test03-expand-cluster-in-file-name ()
+  "Check canonical file name of a cluster or site."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+       shadow-clusters
+       cluster primary regexp file1 file2)
+    (unwind-protect
+       (progn
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+         ;; Define a cluster.
+         (setq cluster "cluster"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster primary regexp)
+
+         (setq file1
+               (make-temp-name
+                (expand-file-name "shadowfile-tests" temporary-file-directory))
+               file2
+               (make-temp-name
+                (expand-file-name
+                 "shadowfile-tests"
+                 shadow-test-remote-temporary-file-directory)))
+
+          ;; A local file name is kept.
+          (should
+           (string-equal (shadow-expand-cluster-in-file-name file1) file1))
+          ;; A remote file is kept.
+          (should
+           (string-equal (shadow-expand-cluster-in-file-name file2) file2))
+          ;; A cluster name is expanded to the primary name.
+          (should
+           (string-equal
+            (shadow-expand-cluster-in-file-name (format "/%s:%s" cluster 
file1))
+            (shadow-expand-cluster-in-file-name (concat primary file1))))
+          ;; A primary name is expanded if it is a local file name.
+          (should
+           (string-equal
+            (shadow-expand-cluster-in-file-name (concat primary file1)) file1))
+
+         ;; Redefine the cluster.
+         (setq primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster primary regexp)
+
+          ;; A cluster name is expanded to the primary name.
+          (should
+           (string-equal
+            (shadow-expand-cluster-in-file-name (format "/%s:%s" cluster 
file1))
+            (shadow-expand-cluster-in-file-name (concat primary file1))))
+          ;; A primary name is not expanded if it isn't is a local file name.
+          (should
+           (string-equal
+            (shadow-expand-cluster-in-file-name (concat primary file1))
+            (concat primary file1))))
+
+      ;; Cleanup.
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file)))))
+
+(ert-deftest shadow-test04-contract-file-name ()
+  "Check canonical file name of a cluster or site."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+       shadow-clusters
+       cluster primary regexp file)
+    (unwind-protect
+       (progn
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+         ;; Define a cluster.
+         (setq cluster "cluster"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary)
+                file (make-temp-name
+                      (expand-file-name
+                       "shadowfile-tests" temporary-file-directory)))
+         (shadow-set-cluster cluster primary regexp)
+
+          ;; The cluster name is prepended for local files.
+          (should
+           (string-equal
+            (shadow-contract-file-name file) (concat "/cluster:" file)))
+          ;; A cluster file name is preserved.
+          (should
+           (string-equal
+            (shadow-contract-file-name (concat "/cluster:" file))
+            (concat "/cluster:" file)))
+          ;; `shadow-system-name' is mapped to the cluster.
+          (should
+           (string-equal
+            (shadow-contract-file-name (concat shadow-system-name file))
+            (concat "/cluster:" file)))
+
+         ;; Redefine the cluster.
+         (setq primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster primary regexp)
+
+          ;; A remote file name is mapped to the cluster.
+          (should
+           (string-equal
+            (shadow-contract-file-name
+             (concat
+              (file-remote-p shadow-test-remote-temporary-file-directory) 
file))
+            (concat "/cluster:" file))))
+
+      ;; Cleanup.
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file)))))
+
+(ert-deftest shadow-test05-file-match ()
+  "Check `shadow-same-site' and `shadow-file-match'."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+       shadow-clusters
+       cluster primary regexp file)
+    (unwind-protect
+       (progn
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+         ;; Define a cluster.
+         (setq cluster "cluster"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary)
+                file (make-temp-name
+                      (expand-file-name
+                       "shadowfile-tests" temporary-file-directory)))
+         (shadow-set-cluster cluster primary regexp)
+
+          (should (shadow-same-site (shadow-parse-name "/cluster:") file))
+          (should
+          (shadow-same-site (shadow-parse-name shadow-system-name) file))
+          (should (shadow-same-site (shadow-parse-name file) file))
+
+          (should
+          (shadow-file-match
+           (shadow-parse-name (concat "/cluster:" file)) file))
+          (should
+          (shadow-file-match
+           (shadow-parse-name (concat shadow-system-name file)) file))
+          (should (shadow-file-match (shadow-parse-name file) file))
+
+         ;; Redefine the cluster.
+         (setq primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster primary regexp)
+
+          (should
+          (shadow-file-match
+           (shadow-parse-name
+            (concat
+             (file-remote-p shadow-test-remote-temporary-file-directory)
+             file))
+           file)))
+
+      ;; Cleanup.
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file)))))
+
+(ert-deftest shadow-test06-literal-groups ()
+  "Check literal group definitions."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+       shadow-clusters shadow-literal-groups
+       cluster1 cluster2 primary regexp file1 file2 mocked-input)
+    (unwind-protect
+       ;; We must mock `read-from-minibuffer' and `read-string', in
+       ;; order to avoid interactive arguments.
+       (cl-letf* (((symbol-function 'read-from-minibuffer)
+                   (lambda (&rest args) (pop mocked-input)))
+                  ((symbol-function 'read-string)
+                   (lambda (&rest args) (pop mocked-input))))
+
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+         ;; Define clusters.
+         (setq cluster1 "cluster1"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster1 primary regexp)
+
+         (setq cluster2 "cluster2"
+               primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (format "^\\(%s\\|%s\\)$" shadow-system-name primary))
+         (shadow-set-cluster cluster2 primary regexp)
+
+         ;; Define a literal group.
+         (setq file1
+               (make-temp-name
+                (expand-file-name "shadowfile-tests" temporary-file-directory))
+               file2
+               (make-temp-name
+                (expand-file-name
+                 "shadowfile-tests"
+                 shadow-test-remote-temporary-file-directory))
+               mocked-input `(,cluster1 ,file1 ,cluster2 ,file2 ,(kbd "RET")))
+         (with-temp-buffer
+           (setq-local buffer-file-name file1)
+           (call-interactively 'shadow-define-literal-group))
+
+          ;; `shadow-literal-groups' is a list of lists.
+          (should (consp shadow-literal-groups))
+          (should (consp (car shadow-literal-groups)))
+          (should-not (cdr shadow-literal-groups))
+
+         (should (member (format "/%s:%s" cluster1 (file-local-name file1))
+                          (car shadow-literal-groups)))
+         (should (member (format "/%s:%s" cluster2 (file-local-name file2))
+                          (car shadow-literal-groups))))
+
+      ;; Cleanup.
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file)))))
+
+(ert-deftest shadow-test07-regexp-groups ()
+  "Check regexp group definitions."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+       shadow-clusters shadow-regexp-groups
+       cluster1 cluster2 primary regexp file mocked-input)
+    (unwind-protect
+       ;; We must mock `read-from-minibuffer' and `read-string', in
+       ;; order to avoid interactive arguments.
+       (cl-letf* (((symbol-function 'read-from-minibuffer)
+                   (lambda (&rest args) (pop mocked-input)))
+                  ((symbol-function 'read-string)
+                   (lambda (&rest args) (pop mocked-input))))
+
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+         ;; Define clusters.
+         (setq cluster1 "cluster1"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster1 primary regexp)
+
+         (setq cluster2 "cluster2"
+               primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (format "^\\(%s\\|%s\\)$" shadow-system-name primary))
+         (shadow-set-cluster cluster2 primary regexp)
+
+         ;; Define a regexp group.
+         (setq file
+               (make-temp-name
+                (expand-file-name "shadowfile-tests" temporary-file-directory))
+               mocked-input `(,(shadow-regexp-superquote file)
+                               ,cluster1 ,cluster2 ,(kbd "RET")))
+         (with-temp-buffer
+           (setq-local buffer-file-name nil)
+           (call-interactively 'shadow-define-regexp-group))
+
+          ;; `shadow-regexp-groups' is a list of lists.
+          (should (consp shadow-regexp-groups))
+          (should (consp (car shadow-regexp-groups)))
+          (should-not (cdr shadow-regexp-groups))
+
+         (should
+           (member
+            (concat
+             (shadow-site-primary cluster1) (shadow-regexp-superquote file))
+            (car shadow-regexp-groups)))
+         (should
+           (member
+            (concat
+             (shadow-site-primary cluster2) (shadow-regexp-superquote file))
+            (car shadow-regexp-groups))))
+
+      ;; Cleanup.
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file)))))
+
+(ert-deftest shadow-test08-shadow-todo ()
+  "Check that needed shadows are added to todo."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+  (skip-unless (file-writable-p shadow-test-remote-temporary-file-directory))
+
+  (let ((backup-inhibited t)
+        (shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+        (shadow-inhibit-message t)
+       shadow-clusters shadow-literal-groups shadow-regexp-groups
+        shadow-files-to-copy
+       cluster1 cluster2 primary regexp file)
+    (unwind-protect
+        (condition-case err
+        (progn
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+
+          (message "Point 1")
+          ;; Define clusters.
+         (setq cluster1 "cluster1"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster1 primary regexp)
+
+         (setq cluster2 "cluster2"
+               primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster2 primary regexp)
+
+          (message "Point 2")
+         ;; Define a literal group.
+         (setq file
+               (make-temp-name
+                (expand-file-name "shadowfile-tests" temporary-file-directory))
+                shadow-literal-groups
+                `((,(concat "/cluster1:" file) ,(concat "/cluster2:" file))))
+
+          (message "Point 3")
+          ;; Save file from "cluster1" definition.
+          (with-temp-buffer
+            (setq buffer-file-name file)
+            (insert "foo")
+            (save-buffer))
+          (message "%s" file)
+          (message "%s" (shadow-contract-file-name (concat "/cluster2:" file)))
+          (message "%s" shadow-files-to-copy)
+         (should
+           (member
+            (cons file (shadow-contract-file-name (concat "/cluster2:" file)))
+            shadow-files-to-copy))
+
+          (message "Point 4")
+          ;; Save file from "cluster2" definition.
+          (with-temp-buffer
+            (message "Point 4.1")
+            (message "%s" file)
+            (message "%s" (shadow-site-primary cluster2))
+            (setq buffer-file-name (concat (shadow-site-primary cluster2) 
file))
+            (message "Point 4.2")
+            (insert "foo")
+            (message "%s" buffer-file-name)
+            (save-buffer))
+          (message "Point 4.3")
+          (message "%s" (shadow-site-primary cluster2))
+          (message "%s" (shadow-contract-file-name (concat "/cluster1:" file)))
+          (message "%s" shadow-files-to-copy)
+         (should
+           (member
+            (cons
+             (concat (shadow-site-primary cluster2) file)
+             (shadow-contract-file-name (concat "/cluster1:" file)))
+            shadow-files-to-copy))
+
+          (message "Point 5")
+         ;; Define a regexp group.
+         (setq shadow-files-to-copy nil
+                shadow-regexp-groups
+                `((,(concat (shadow-site-primary cluster1)
+                            (shadow-regexp-superquote file))
+                   ,(concat (shadow-site-primary cluster2)
+                            (shadow-regexp-superquote file)))))
+
+          (message "Point 6")
+          ;; Save file from "cluster1" definition.
+          (with-temp-buffer
+            (setq buffer-file-name file)
+            (insert "foo")
+            (save-buffer))
+         (should
+           (member
+            (cons file (shadow-contract-file-name (concat "/cluster2:" file)))
+            shadow-files-to-copy))
+
+          (message "Point 7")
+          ;; Save file from "cluster2" definition.
+          (with-temp-buffer
+            (setq buffer-file-name (concat (shadow-site-primary cluster2) 
file))
+            (insert "foo")
+            (save-buffer))
+         (should
+           (member
+            (cons
+             (concat (shadow-site-primary cluster2) file)
+             (shadow-contract-file-name (concat "/cluster1:" file)))
+            shadow-files-to-copy)))
+        (error (message "Error: %s" err) (signal (car err) (cdr err))))
+
+      ;; Cleanup.
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file))
+      (ignore-errors
+        (when (file-exists-p file)
+         (delete-file file)))
+      (ignore-errors
+        (when (file-exists-p (concat (shadow-site-primary cluster2) file))
+         (delete-file (concat (shadow-site-primary cluster2) file)))))))
+
+(ert-deftest shadow-test09-shadow-copy-files ()
+  "Check that needed shadow files are copied."
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
+
+  (let ((backup-inhibited t)
+        (shadow-info-file shadow-test-info-file)
+       (shadow-todo-file shadow-test-todo-file)
+        (shadow-inhibit-message t)
+        (shadow-noquery t)
+        shadow-clusters shadow-files-to-copy
+       cluster1 cluster2 primary regexp file mocked-input)
+    (unwind-protect
+       (progn
+         ;; Cleanup.
+         (when (file-exists-p shadow-info-file)
+           (delete-file shadow-info-file))
+         (when (file-exists-p shadow-todo-file)
+           (delete-file shadow-todo-file))
+          (when (buffer-live-p shadow-todo-buffer)
+            (with-current-buffer shadow-todo-buffer (erase-buffer)))
+
+          ;; Define clusters.
+         (setq cluster1 "cluster1"
+               primary shadow-system-name
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster1 primary regexp)
+
+         (setq cluster2 "cluster2"
+               primary
+               (file-remote-p shadow-test-remote-temporary-file-directory)
+               regexp (shadow-regexp-superquote primary))
+         (shadow-set-cluster cluster2 primary regexp)
+
+         ;; Define files to copy.
+         (setq file
+               (make-temp-name
+                (expand-file-name "shadowfile-tests" temporary-file-directory))
+                shadow-literal-groups
+                `((,(concat "/cluster1:" file) ,(concat "/cluster2:" file)))
+                shadow-regexp-groups
+                `((,(concat (shadow-site-primary cluster1)
+                            (shadow-regexp-superquote file))
+                   ,(concat (shadow-site-primary cluster2)
+                            (shadow-regexp-superquote file))))
+               mocked-input `(,(concat (shadow-site-primary cluster2) file)
+                               ,file))
+
+          ;; Save files.
+          (with-temp-buffer
+            (setq buffer-file-name file)
+            (insert "foo")
+            (save-buffer))
+          (with-temp-buffer
+            (setq buffer-file-name (concat (shadow-site-primary cluster2) 
file))
+            (insert "foo")
+            (save-buffer))
+
+         ;; We must mock `write-region', in order to check proper
+         ;; action.
+          (add-function
+           :before (symbol-function 'write-region)
+          (lambda (&rest args)
+             (when (and (buffer-file-name) mocked-input)
+               (should (equal (buffer-file-name) (pop mocked-input)))))
+           '((name . "write-region-mock")))
+
+          ;; Copy the files.
+          (shadow-copy-files 'noquery)
+          (should-not shadow-files-to-copy)
+          (with-current-buffer shadow-todo-buffer
+            (goto-char (point-min))
+            (should
+             (looking-at (regexp-quote "(setq shadow-files-to-copy nil)")))))
+
+      ;; Cleanup.
+      (remove-function (symbol-function 'write-region) "write-region-mock")
+      (when (file-exists-p shadow-info-file)
+       (delete-file shadow-info-file))
+      (when (file-exists-p shadow-todo-file)
+       (delete-file shadow-todo-file))
+      (ignore-errors
+        (when (file-exists-p file)
+         (delete-file file)))
+      (ignore-errors
+        (when (file-exists-p (concat (shadow-site-primary cluster2) file))
+         (delete-file (concat (shadow-site-primary cluster2) file)))))))
+
+(defun shadowfile-test-all (&optional interactive)
+  "Run all tests for \\[shadowfile]."
+  (interactive "p")
+  (if interactive
+      (ert-run-tests-interactively "^shadowfile-")
+    (ert-run-tests-batch "^shadowfile-")))
+
+(let ((shadow-info-file shadow-test-info-file)
+      (shadow-todo-file shadow-test-todo-file))
+  (shadow-initialize))
+
+(provide 'shadowfile-tests)
+;;; shadowfile-tests.el ends here
diff --git a/test/lisp/wdired-tests.el b/test/lisp/wdired-tests.el
new file mode 100644
index 0000000..7199470
--- /dev/null
+++ b/test/lisp/wdired-tests.el
@@ -0,0 +1,105 @@
+;;; wdired-tests.el --- tests for wdired.el          -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'dired)
+
+(ert-deftest wdired-test-bug32173-01 ()
+  "Test using non-nil wdired-use-interactive-rename.
+Partially modifying a file name should succeed."
+  (let* ((test-dir (make-temp-file "test-dir-" t))
+        (test-file (concat (file-name-as-directory test-dir) "foo.c"))
+        (replace "bar")
+        (new-file (replace-regexp-in-string "foo" replace test-file))
+        (wdired-use-interactive-rename t))
+    (write-region "" nil test-file nil 'silent)
+    (advice-add 'dired-query ; Don't ask confirmation to overwrite a file.
+                :override
+                (lambda (_sym _prompt &rest _args) (setq dired-query t))
+                '((name . "advice-dired-query")))
+    (let ((buf (find-file-noselect test-dir)))
+      (unwind-protect
+         (with-current-buffer buf
+           (should (equal (dired-file-name-at-point) test-file))
+           (dired-toggle-read-only)
+           (kill-region (point) (progn (search-forward ".")
+                                       (forward-char -1) (point)))
+           (insert replace)
+           (wdired-finish-edit)
+           (should (equal (dired-file-name-at-point) new-file)))
+       (if buf (kill-buffer buf))
+       (delete-directory test-dir t)))))
+
+(ert-deftest wdired-test-bug32173-02 ()
+  "Test using non-nil wdired-use-interactive-rename.
+Aborting an edit should leaving original file name unchanged."
+  (let* ((test-dir (make-temp-file "test-dir-" t))
+        (test-file (concat (file-name-as-directory test-dir) "foo.c"))
+        (wdired-use-interactive-rename t))
+    (write-region "" nil test-file nil 'silent)
+    ;; Make dired-do-create-files-regexp a noop to mimic typing C-g
+    ;; at its prompt before wdired-finish-edit returns.
+    (advice-add 'dired-do-create-files-regexp
+                :override
+                (lambda (&rest _) (ignore))
+                '((name . "advice-dired-do-create-files-regexp")))
+    (let ((buf (find-file-noselect test-dir)))
+      (unwind-protect
+         (with-current-buffer buf
+           (should (equal (dired-file-name-at-point) test-file))
+           (dired-toggle-read-only)
+           (kill-region (point) (progn (search-forward ".")
+                                       (forward-char -1) (point)))
+           (insert "bar")
+           (wdired-finish-edit)
+           (should (equal (dired-get-filename) test-file)))
+       (if buf (kill-buffer buf))
+       (delete-directory test-dir t)))))
+
+(ert-deftest wdired-test-unfinished-edit-01 ()
+  "Test editing a file name without saving the change.
+Finding the new name should be possible while still in
+wdired-mode."
+  :expected-result (if (< emacs-major-version 27) :failed :passed)
+  (let* ((test-dir (make-temp-file "test-dir-" t))
+        (test-file (concat (file-name-as-directory test-dir) "foo.c"))
+        (replace "bar")
+        (new-file (replace-regexp-in-string "foo" replace test-file)))
+    (write-region "" nil test-file nil 'silent)
+    (let ((buf (find-file-noselect test-dir)))
+      (unwind-protect
+         (with-current-buffer buf
+           (should (equal (dired-file-name-at-point) test-file))
+           (dired-toggle-read-only)
+           (kill-region (point) (progn (search-forward ".")
+                                       (forward-char -1) (point)))
+           (insert replace)
+           (should (equal (dired-get-filename) new-file))))
+       (when buf
+         (with-current-buffer buf
+            ;; Prevent kill-buffer-query-functions from chiming in.
+           (set-buffer-modified-p nil)
+           (kill-buffer buf)))
+       (delete-directory test-dir t))))
+
+
+(provide 'wdired-tests)
+;;; wdired-tests.el ends here
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index c828000..2951270 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -165,10 +165,12 @@
                 :type 'overflow-error)
   (should-error (read (substring (format "%d" most-negative-fixnum) 1))
                 :type 'overflow-error)
-  (should-error (read (format "#x%x" most-negative-fixnum))
-                :type 'overflow-error)
-  (should-error (read (format "#o%o" most-negative-fixnum))
-                :type 'overflow-error)
+  (let ((binary-as-unsigned nil))
+    (dolist (fmt '("%d" "%s" "#o%o" "#x%x"))
+      (dolist (val (list most-negative-fixnum (1+ most-negative-fixnum)
+                         -1 0 1
+                         (1- most-positive-fixnum) most-positive-fixnum))
+        (should (eq val (read (format fmt val)))))))
   (should-error (read (format "#32rG%x" most-positive-fixnum))
                 :type 'overflow-error))
 
diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el
index d9cca55..e4b9cbe 100644
--- a/test/src/fns-tests.el
+++ b/test/src/fns-tests.el
@@ -23,6 +23,17 @@
 
 (require 'cl-lib)
 
+;; Test that equality predicates work correctly on NaNs when combined
+;; with hash tables based on those predicates.  This was not the case
+;; for eql in Emacs 26.
+(ert-deftest fns-tests-equality-nan ()
+  (dolist (test (list #'eq #'eql #'equal))
+    (let* ((h (make-hash-table :test test))
+           (nan 0.0e+NaN)
+           (-nan (- nan)))
+      (puthash nan t h)
+      (should (eq (funcall test nan -nan) (gethash -nan h))))))
+
 (ert-deftest fns-tests-reverse ()
   (should-error (reverse))
   (should-error (reverse 1))
diff --git a/test/src/thread-tests.el b/test/src/thread-tests.el
index a00a9c8..364f6d6 100644
--- a/test/src/thread-tests.el
+++ b/test/src/thread-tests.el
@@ -34,10 +34,11 @@
 (declare-function thread--blocker "thread.c" (thread))
 (declare-function thread-alive-p "thread.c" (thread))
 (declare-function thread-join "thread.c" (thread))
-(declare-function thread-last-error "thread.c" ())
+(declare-function thread-last-error "thread.c" (&optional cleanup))
 (declare-function thread-name "thread.c" (thread))
 (declare-function thread-signal "thread.c" (thread error-symbol data))
 (declare-function thread-yield "thread.c" ())
+(defvar main-thread)
 
 (ert-deftest threads-is-one ()
   "Test for existence of a thread."
@@ -71,6 +72,11 @@
   (skip-unless (featurep 'threads))
   (should (listp (all-threads))))
 
+(ert-deftest threads-main-thread ()
+  "Simple test for all-threads."
+  (skip-unless (featurep 'threads))
+  (should (eq main-thread (car (all-threads)))))
+
 (defvar threads-test-global nil)
 
 (defun threads-test-thread1 ()
@@ -94,15 +100,24 @@
    (progn
      (setq threads-test-global nil)
      (let ((thread (make-thread #'threads-test-thread1)))
-       (thread-join thread)
-       (and threads-test-global
-           (not (thread-alive-p thread)))))))
+       (and (= (thread-join thread) 23)
+            (= threads-test-global 23)
+            (not (thread-alive-p thread)))))))
 
 (ert-deftest threads-join-self ()
   "Cannot `thread-join' the current thread."
   (skip-unless (featurep 'threads))
   (should-error (thread-join (current-thread))))
 
+(ert-deftest threads-join-error ()
+  "Test of error signalling from `thread-join'."
+  :tags '(:unstable)
+  (skip-unless (featurep 'threads))
+  (let ((thread (make-thread #'threads-call-error)))
+    (while (thread-alive-p thread)
+      (thread-yield))
+    (should-error (thread-join thread))))
+
 (defvar threads-test-binding nil)
 
 (defun threads-test-thread2 ()
@@ -191,7 +206,7 @@
 (ert-deftest threads-mutex-signal ()
   "Test signaling a blocked thread."
   (skip-unless (featurep 'threads))
-  (should
+  (should-error
    (progn
      (setq threads-mutex (make-mutex))
      (setq threads-mutex-key nil)
@@ -200,8 +215,10 @@
        (while (not threads-mutex-key)
         (thread-yield))
        (thread-signal thr 'quit nil)
-       (thread-join thr))
-     t)))
+       ;; `quit' is not catched by `should-error'.  We must indicate it.
+       (condition-case nil
+           (thread-join thr)
+         (quit (signal 'error nil)))))))
 
 (defun threads-test-io-switch ()
   (setq threads-test-global 23))
@@ -275,6 +292,9 @@
       (thread-yield))
     (should (equal (thread-last-error)
                    '(error "Error is called")))
+    (should (equal (thread-last-error 'cleanup)
+                   '(error "Error is called")))
+    (should-not (thread-last-error))
     (setq th2 (make-thread #'threads-custom "threads-custom"))
     (should (threadp th2))))
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]