]> code.delx.au - gnu-emacs/blobdiff - lisp/files.el
*** empty log message ***
[gnu-emacs] / lisp / files.el
index 039f7fc5a2238c4ae5d2c112c9e8a1c5c0457701..17c54f69d516b335d2e59832040e68513774845a 100644 (file)
@@ -133,24 +133,26 @@ This variable is relevant only if `backup-by-copying' and
   :type '(choice (const nil) integer)
   :group 'backup)
 
-(defvar backup-enable-predicate
-  (lambda (name)
-    (not (or (let ((comp (compare-strings temporary-file-directory 0 nil
-                                     name 0 nil)))
-              ;; Directory is under temporary-file-directory.
-              (and (not (eq comp t))
-                   (< comp -1)))
-            (if small-temporary-file-directory
-                (let ((comp (compare-strings small-temporary-file-directory
-                                             0 nil
-                                             name 0 nil)))
-                  ;; Directory is under small-temporary-file-directory.
-                  (and (not (eq comp t))
-                       (< comp -1)))))))
+(defun normal-backup-enable-predicate (name)
+  "Default `backup-enable-predicate' function.
+Checks for files in `temporary-file-directory' or
+`small-temporary-file-directory'."
+  (not (or (let ((comp (compare-strings temporary-file-directory 0 nil
+                                       name 0 nil)))
+            ;; Directory is under temporary-file-directory.
+            (and (not (eq comp t))
+                 (< comp (- (length temporary-file-directory)))))
+          (if small-temporary-file-directory
+              (let ((comp (compare-strings small-temporary-file-directory
+                                           0 nil
+                                           name 0 nil)))
+                ;; Directory is under small-temporary-file-directory.
+                (and (not (eq comp t))
+                     (< comp (- (length small-temporary-file-directory)))))))))
+
+(defvar backup-enable-predicate 'normal-backup-enable-predicate
   "Predicate that looks at a file name and decides whether to make backups.
-Called with an absolute file name as argument, it returns t to enable backup.
-The default version checks for files in `temporary-file-directory' or
-`small-temporary-file-directory'.")
+Called with an absolute file name as argument, it returns t to enable backup.")
 
 (defcustom buffer-offer-save nil
   "*Non-nil in a buffer means always offer to save buffer on exit.
@@ -458,8 +460,9 @@ Runs the usual ange-ftp hook, but only for completion operations."
 (defun convert-standard-filename (filename)
   "Convert a standard file's name to something suitable for the current OS.
 This function's standard definition is trivial; it just returns the argument.
-However, on some systems, the function is redefined
-with a definition that really does change some file names."
+However, on some systems, the function is redefined with a definition
+that really does change some file names to canonicalize certain
+patterns and to guarantee valid names."
   filename)
 \f
 (defun pwd ()
@@ -472,7 +475,9 @@ with a definition that really does change some file names."
 Not actually set up until the first time you you use it.")
 
 (defun parse-colon-path (cd-path)
-  "Explode a colon-separated search path into a list of directory names."
+  "Explode a colon-separated search path into a list of directory names.
+\(For values of `colon' equal to `path-separator'.)"
+  ;; We could use split-string here.
   (and cd-path
        (let (cd-prefix cd-list (cd-start 0) cd-colon)
         (setq cd-path (concat cd-path path-separator))
@@ -1310,135 +1315,137 @@ in that case, this function acts as if `enable-local-variables' were t."
                    (prin1-to-string err)))))
 
 (defvar auto-mode-alist
-  '(("\\.te?xt\\'" . text-mode)
-    ("\\.c\\'" . c-mode)
-    ("\\.h\\'" . c-mode)
-    ("\\.tex\\'" . tex-mode)
-    ("\\.ltx\\'" . latex-mode)
-    ("\\.el\\'" . emacs-lisp-mode)
-    ("\\.scm\\'" . scheme-mode)
-    ("\\.l\\'" . lisp-mode)
-    ("\\.lisp\\'" . lisp-mode)
-    ("\\.f\\'" . fortran-mode)
-    ("\\.F\\'" . fortran-mode)
-    ("\\.for\\'" . fortran-mode)
-    ("\\.p\\'" . pascal-mode)
-    ("\\.pas\\'" . pascal-mode)
-    ("\\.ad[abs]\\'" . ada-mode)
-    ("\\.\\([pP][Llm]\\|al\\)\\'" . perl-mode)
-    ("\\.s?html?\\'" . html-mode)
-    ("\\.cc\\'" . c++-mode)
-    ("\\.hh\\'" . c++-mode)
-    ("\\.hpp\\'" . c++-mode)
-    ("\\.C\\'" . c++-mode)
-    ("\\.H\\'" . c++-mode)
-    ("\\.cpp\\'" . c++-mode)
-    ("\\.cxx\\'" . c++-mode)
-    ("\\.hxx\\'" . c++-mode)
-    ("\\.c\\+\\+\\'" . c++-mode)
-    ("\\.h\\+\\+\\'" . c++-mode)
-    ("\\.m\\'" . objc-mode)
-    ("\\.java\\'" . java-mode)
-    ("\\.mk\\'" . makefile-mode)
-    ("\\(M\\|m\\|GNUm\\)akefile\\(\\.in\\)?\\'" . makefile-mode)
-    ("\\.am\\'" . makefile-mode)       ;For Automake.
+  (mapc
+   (lambda (elt)
+     (cons (purecopy (car elt)) (cdr elt)))
+   '(("\\.te?xt\\'" . text-mode)
+     ("\\.c\\'" . c-mode)
+     ("\\.h\\'" . c-mode)
+     ("\\.tex\\'" . tex-mode)
+     ("\\.ltx\\'" . latex-mode)
+     ("\\.el\\'" . emacs-lisp-mode)
+     ("\\.scm\\'" . scheme-mode)
+     ("\\.l\\'" . lisp-mode)
+     ("\\.lisp\\'" . lisp-mode)
+     ("\\.f\\'" . fortran-mode)
+     ("\\.F\\'" . fortran-mode)
+     ("\\.for\\'" . fortran-mode)
+     ("\\.p\\'" . pascal-mode)
+     ("\\.pas\\'" . pascal-mode)
+     ("\\.ad[abs]\\'" . ada-mode)
+     ("\\.\\([pP][Llm]\\|al\\)\\'" . perl-mode)
+     ("\\.s?html?\\'" . html-mode)
+     ("\\.cc\\'" . c++-mode)
+     ("\\.hh\\'" . c++-mode)
+     ("\\.hpp\\'" . c++-mode)
+     ("\\.C\\'" . c++-mode)
+     ("\\.H\\'" . c++-mode)
+     ("\\.cpp\\'" . c++-mode)
+     ("\\.cxx\\'" . c++-mode)
+     ("\\.hxx\\'" . c++-mode)
+     ("\\.c\\+\\+\\'" . c++-mode)
+     ("\\.h\\+\\+\\'" . c++-mode)
+     ("\\.m\\'" . objc-mode)
+     ("\\.java\\'" . java-mode)
+     ("\\.mk\\'" . makefile-mode)
+     ("\\(M\\|m\\|GNUm\\)akefile\\(\\.in\\)?\\'" . makefile-mode)
+     ("\\.am\\'" . makefile-mode)      ;For Automake.
 ;;; Less common extensions come here
 ;;; so more common ones above are found faster.
-    ("\\.texinfo\\'" . texinfo-mode)
-    ("\\.te?xi\\'" . texinfo-mode)
-    ("\\.s\\'" . asm-mode)
-    ("\\.S\\'" . asm-mode)
-    ("\\.asm\\'" . asm-mode)
-    ("ChangeLog\\'" . change-log-mode)
-    ("change\\.log\\'" . change-log-mode)
-    ("changelo\\'" . change-log-mode)
-    ("ChangeLog\\.[0-9]+\\'" . change-log-mode)
-    ;; for MSDOS and MS-Windows (which are case-insensitive)
-    ("changelog\\'" . change-log-mode)
-    ("changelog\\.[0-9]+\\'" . change-log-mode)
-    ("\\$CHANGE_LOG\\$\\.TXT" . change-log-mode)
-    ("\\.scm\\.[0-9]*\\'" . scheme-mode)
-    ("\\.[ck]?sh\\'\\|\\.shar\\'\\|/\\.z?profile\\'" . sh-mode)
-    ("\\(/\\|\\`\\)\\.\\(bash_profile\\|z?login\\|bash_login\\|z?logout\\)\\'" . sh-mode)
-    ("\\(/\\|\\`\\)\\.\\(bash_logout\\|[kz]shrc\\|bashrc\\|t?cshrc\\|esrc\\)\\'" . sh-mode)
-    ("\\(/\\|\\`\\)\\.\\([kz]shenv\\|xinitrc\\|startxrc\\|xsession\\)\\'" . sh-mode)
-    ("\\.m?spec$" . sh-mode)
-    ("\\.mm\\'" . nroff-mode)
-    ("\\.me\\'" . nroff-mode)
-    ("\\.ms\\'" . nroff-mode)
-    ("\\.man\\'" . nroff-mode)
-    ("\\.\\(u?lpc\\|pike\\|pmod\\)\\'" . pike-mode)
+     ("\\.texinfo\\'" . texinfo-mode)
+     ("\\.te?xi\\'" . texinfo-mode)
+     ("\\.s\\'" . asm-mode)
+     ("\\.S\\'" . asm-mode)
+     ("\\.asm\\'" . asm-mode)
+     ("ChangeLog\\'" . change-log-mode)
+     ("change\\.log\\'" . change-log-mode)
+     ("changelo\\'" . change-log-mode)
+     ("ChangeLog\\.[0-9]+\\'" . change-log-mode)
+     ;; for MSDOS and MS-Windows (which are case-insensitive)
+     ("changelog\\'" . change-log-mode)
+     ("changelog\\.[0-9]+\\'" . change-log-mode)
+     ("\\$CHANGE_LOG\\$\\.TXT" . change-log-mode)
+     ("\\.scm\\.[0-9]*\\'" . scheme-mode)
+     ("\\.[ck]?sh\\'\\|\\.shar\\'\\|/\\.z?profile\\'" . sh-mode)
+     ("\\(/\\|\\`\\)\\.\\(bash_profile\\|z?login\\|bash_login\\|z?logout\\)\\'" . sh-mode)
+     ("\\(/\\|\\`\\)\\.\\(bash_logout\\|shrc\\|[kz]shrc\\|bashrc\\|t?cshrc\\|esrc\\)\\'" . sh-mode)
+     ("\\(/\\|\\`\\)\\.\\([kz]shenv\\|xinitrc\\|startxrc\\|xsession\\)\\'" . sh-mode)
+     ("\\.m?spec$" . sh-mode)
+     ("\\.mm\\'" . nroff-mode)
+     ("\\.me\\'" . nroff-mode)
+     ("\\.ms\\'" . nroff-mode)
+     ("\\.man\\'" . nroff-mode)
+     ("\\.\\(u?lpc\\|pike\\|pmod\\)\\'" . pike-mode)
 ;;; The following should come after the ChangeLog pattern
 ;;; for the sake of ChangeLog.1, etc.
 ;;; and after the .scm.[0-9] pattern too.
-    ("\\.[12345678]\\'" . nroff-mode)
-    ("\\.TeX\\'" . tex-mode)
-    ("\\.sty\\'" . latex-mode)
-    ("\\.cls\\'" . latex-mode)         ;LaTeX 2e class
-    ("\\.clo\\'" . latex-mode)         ;LaTeX 2e class option
-    ("\\.bbl\\'" . latex-mode)
-    ("\\.bib\\'" . bibtex-mode)
-    ("\\.sql\\'" . sql-mode)
-    ("\\.m4\\'" . m4-mode)
-    ("\\.mc\\'" . m4-mode)
-    ("\\.mf\\'" . metafont-mode)
-    ("\\.mp\\'" . metapost-mode)
-    ("\\.vhdl?\\'" . vhdl-mode)
-    ("\\.article\\'" . text-mode)
-    ("\\.letter\\'" . text-mode)
-    ("\\.tcl\\'" . tcl-mode)
-    ("\\.exp\\'" . tcl-mode)
-    ("\\.itcl\\'" . tcl-mode)
-    ("\\.itk\\'" . tcl-mode)
-    ("\\.icn\\'" . icon-mode)
-    ("\\.sim\\'" . simula-mode)
-    ("\\.mss\\'" . scribe-mode)
-    ("\\.f90\\'" . f90-mode)
-    ("\\.pro\\'" . idlwave-mode)
-    ("\\.lsp\\'" . lisp-mode)
-    ("\\.awk\\'" . awk-mode)
-    ("\\.prolog\\'" . prolog-mode)
-    ("\\.tar\\'" . tar-mode)
-    ("\\.\\(arc\\|zip\\|lzh\\|zoo\\|jar\\)\\'" . archive-mode)
-    ("\\.\\(ARC\\|ZIP\\|LZH\\|ZOO\\|JAR\\)\\'" . archive-mode)
-    ;; Mailer puts message to be edited in
-    ;; /tmp/Re.... or Message
-    ("\\`/tmp/Re" . text-mode)
-    ("/Message[0-9]*\\'" . text-mode)
-    ("/drafts/[0-9]+\\'" . mh-letter-mode)
-    ("\\.zone\\'" . zone-mode)
-    ;; some news reader is reported to use this
-    ("\\`/tmp/fol/" . text-mode)
-    ("\\.y\\'" . c-mode)
-    ("\\.lex\\'" . c-mode)
-    ("\\.oak\\'" . scheme-mode)
-    ("\\.sgml?\\'" . sgml-mode)
-    ("\\.xml\\'" . sgml-mode)
-    ("\\.dtd\\'" . sgml-mode)
-    ("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
-    ("\\.idl\\'" . idl-mode)
-    ;; .emacs following a directory delimiter
-    ;; in Unix, MSDOG or VMS syntax.
-    ("[]>:/\\]\\..*emacs\\'" . emacs-lisp-mode)
-    ("\\`\\..*emacs\\'" . emacs-lisp-mode)
-    ;; _emacs following a directory delimiter
-    ;; in MsDos syntax
-    ("[:/]_emacs\\'" . emacs-lisp-mode)
-    ("/crontab\\.X*[0-9]+\\'" . shell-script-mode)
-    ("\\.ml\\'" . lisp-mode)
-    ("\\.asn$" . snmp-mode)
-    ("\\.mib$" . snmp-mode)
-    ("\\.smi$" . snmp-mode)
-    ("\\.as2$" . snmpv2-mode)
-    ("\\.mi2$" . snmpv2-mode)
-    ("\\.sm2$" . snmpv2-mode)
-    ("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode)
-    ("\\.[eE]?[pP][sS]$" . ps-mode)
-    ("configure\\.in\\'" . autoconf-mode)
-    ("EBROWSE\\'" . ebrowse-tree-mode)
-    ("\\.ebrowse\\'" . ebrowse-tree-mode))
-  "\
-Alist of filename patterns vs corresponding major mode functions.
+     ("\\.[12345678]\\'" . nroff-mode)
+     ("\\.TeX\\'" . tex-mode)
+     ("\\.sty\\'" . latex-mode)
+     ("\\.cls\\'" . latex-mode)                ;LaTeX 2e class
+     ("\\.clo\\'" . latex-mode)                ;LaTeX 2e class option
+     ("\\.bbl\\'" . latex-mode)
+     ("\\.bib\\'" . bibtex-mode)
+     ("\\.sql\\'" . sql-mode)
+     ("\\.m4\\'" . m4-mode)
+     ("\\.mc\\'" . m4-mode)
+     ("\\.mf\\'" . metafont-mode)
+     ("\\.mp\\'" . metapost-mode)
+     ("\\.vhdl?\\'" . vhdl-mode)
+     ("\\.article\\'" . text-mode)
+     ("\\.letter\\'" . text-mode)
+     ("\\.tcl\\'" . tcl-mode)
+     ("\\.exp\\'" . tcl-mode)
+     ("\\.itcl\\'" . tcl-mode)
+     ("\\.itk\\'" . tcl-mode)
+     ("\\.icn\\'" . icon-mode)
+     ("\\.sim\\'" . simula-mode)
+     ("\\.mss\\'" . scribe-mode)
+     ("\\.f90\\'" . f90-mode)
+     ("\\.pro\\'" . idlwave-mode)
+     ("\\.lsp\\'" . lisp-mode)
+     ("\\.awk\\'" . awk-mode)
+     ("\\.prolog\\'" . prolog-mode)
+     ("\\.tar\\'" . tar-mode)
+     ("\\.\\(arc\\|zip\\|lzh\\|zoo\\|jar\\)\\'" . archive-mode)
+     ("\\.\\(ARC\\|ZIP\\|LZH\\|ZOO\\|JAR\\)\\'" . archive-mode)
+     ;; Mailer puts message to be edited in
+     ;; /tmp/Re.... or Message
+     ("\\`/tmp/Re" . text-mode)
+     ("/Message[0-9]*\\'" . text-mode)
+     ("/drafts/[0-9]+\\'" . mh-letter-mode)
+     ("\\.zone\\'" . zone-mode)
+     ;; some news reader is reported to use this
+     ("\\`/tmp/fol/" . text-mode)
+     ("\\.y\\'" . c-mode)
+     ("\\.lex\\'" . c-mode)
+     ("\\.oak\\'" . scheme-mode)
+     ("\\.sgml?\\'" . sgml-mode)
+     ("\\.xml\\'" . sgml-mode)
+     ("\\.dtd\\'" . sgml-mode)
+     ("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
+     ("\\.idl\\'" . idl-mode)
+     ;; .emacs following a directory delimiter
+     ;; in Unix, MSDOG or VMS syntax.
+     ("[]>:/\\]\\..*emacs\\'" . emacs-lisp-mode)
+     ("\\`\\..*emacs\\'" . emacs-lisp-mode)
+     ;; _emacs following a directory delimiter
+     ;; in MsDos syntax
+     ("[:/]_emacs\\'" . emacs-lisp-mode)
+     ("/crontab\\.X*[0-9]+\\'" . shell-script-mode)
+     ("\\.ml\\'" . lisp-mode)
+     ("\\.asn$" . snmp-mode)
+     ("\\.mib$" . snmp-mode)
+     ("\\.smi$" . snmp-mode)
+     ("\\.as2$" . snmpv2-mode)
+     ("\\.mi2$" . snmpv2-mode)
+     ("\\.sm2$" . snmpv2-mode)
+     ("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode)
+     ("\\.[eE]?[pP][sS]$" . ps-mode)
+     ("configure\\.in\\'" . autoconf-mode)
+     ("BROWSE\\'" . ebrowse-tree-mode)
+     ("\\.ebrowse\\'" . ebrowse-tree-mode)))
+  "Alist of filename patterns vs corresponding major mode functions.
 Each element looks like (REGEXP . FUNCTION) or (REGEXP FUNCTION NON-NIL).
 \(NON-NIL stands for anything that is not nil; the value does not matter.)
 Visiting a file whose name matches REGEXP specifies FUNCTION as the
@@ -1450,43 +1457,47 @@ REGEXP and search the list again for another match.")
 
 
 (defvar interpreter-mode-alist
-  '(("perl" . perl-mode)
-    ("perl5" . perl-mode)
-    ("miniperl" . perl-mode)
-    ("wish" . tcl-mode)
-    ("wishx" . tcl-mode)
-    ("tcl" . tcl-mode)
-    ("tclsh" . tcl-mode)
-    ("awk" . awk-mode)
-    ("mawk" . awk-mode)
-    ("nawk" . awk-mode)
-    ("gawk" . awk-mode)
-    ("scm" . scheme-mode)
-    ("ash" . sh-mode)
-    ("bash" . sh-mode)
-    ("csh" . sh-mode)
-    ("dtksh" . sh-mode)
-    ("es" . sh-mode)
-    ("itcsh" . sh-mode)
-    ("jsh" . sh-mode)
-    ("ksh" . sh-mode)
-    ("oash" . sh-mode)
-    ("pdksh" . sh-mode)
-    ("rc" . sh-mode)
-    ("rpm" . sh-mode)
-    ("sh" . sh-mode)
-    ("sh5" . sh-mode)
-    ("tcsh" . sh-mode)
-    ("wksh" . sh-mode)
-    ("wsh" . sh-mode)
-    ("zsh" . sh-mode)
-    ("tail" . text-mode)
-    ("more" . text-mode)
-    ("less" . text-mode)
-    ("pg" . text-mode)
-    ("make" . makefile-mode)           ; Debian uses this
-    ("guile" . scheme-mode)
-    ("clisp" . lisp-mode))
+  (mapc
+   (lambda (l)
+     (cons (purecopy (car l)) (cdr l)))
+   '(("perl" . perl-mode)
+     ("perl5" . perl-mode)
+     ("miniperl" . perl-mode)
+     ("wish" . tcl-mode)
+     ("wishx" . tcl-mode)
+     ("tcl" . tcl-mode)
+     ("tclsh" . tcl-mode)
+     ("awk" . awk-mode)
+     ("mawk" . awk-mode)
+     ("nawk" . awk-mode)
+     ("gawk" . awk-mode)
+     ("scm" . scheme-mode)
+     ("ash" . sh-mode)
+     ("bash" . sh-mode)
+     ("bash2" . sh-mode)
+     ("csh" . sh-mode)
+     ("dtksh" . sh-mode)
+     ("es" . sh-mode)
+     ("itcsh" . sh-mode)
+     ("jsh" . sh-mode)
+     ("ksh" . sh-mode)
+     ("oash" . sh-mode)
+     ("pdksh" . sh-mode)
+     ("rc" . sh-mode)
+     ("rpm" . sh-mode)
+     ("sh" . sh-mode)
+     ("sh5" . sh-mode)
+     ("tcsh" . sh-mode)
+     ("wksh" . sh-mode)
+     ("wsh" . sh-mode)
+     ("zsh" . sh-mode)
+     ("tail" . text-mode)
+     ("more" . text-mode)
+     ("less" . text-mode)
+     ("pg" . text-mode)
+     ("make" . makefile-mode)          ; Debian uses this
+     ("guile" . scheme-mode)
+     ("clisp" . lisp-mode)))
   "Alist mapping interpreter names to major modes.
 This alist applies to files whose first line starts with `#!'.
 Each element looks like (INTERPRETER . MODE).
@@ -1502,6 +1513,17 @@ If it matches, mode MODE is selected.")
 When checking `inhibit-first-line-modes-regexps', we first discard
 from the end of the file name anything that matches one of these regexps.")
 
+(defvar auto-mode-interpreter-regexp 
+  "#![ \t]?\\([^ \t\n]*\
+/bin/env[ \t]\\)?\\([^ \t\n]+\\)"
+  "Regular expression matching interpreters, for file mode determination.
+This regular expression is matched against the first line of a file
+to determine the file's mode in `set-auto-mode' when Emacs can't deduce
+a mode from the file's name.  If it matches, the file is assumed to
+be interpreted by the interpreter matched by the second group of the
+regular expression.  The mode is then determined as the mode associated
+with that interpreter in `interpreter-mode-alist'.")
+
 (defun set-auto-mode (&optional just-from-file-name)
   "Select major mode appropriate for current buffer.
 This checks for a -*- mode tag in the buffer's text,
@@ -1583,7 +1605,7 @@ and we don't even do that unless it would come from the file name."
     ;; outside the save-excursion.
     (when modes
       (unless just-from-file-name
-       (mapcar 'funcall (nreverse modes)))
+       (mapc 'funcall (nreverse modes)))
       (setq done t))
     ;; If we didn't find a mode from a -*- line, try using the file name.
     (if (and (not done) buffer-file-name)
@@ -1623,8 +1645,7 @@ and we don't even do that unless it would come from the file name."
                (let ((interpreter
                       (save-excursion
                         (goto-char (point-min))
-                        (if (looking-at "#![ \t]?\\([^ \t\n]*\
-/bin/env[ \t]\\)?\\([^ \t\n]+\\)")
+                        (if (looking-at auto-mode-interpreter-regexp)
                             (match-string 2)
                           "")))
                      elt)
@@ -2223,7 +2244,7 @@ names matching REGEXP will be made in DIRECTORY.  DIRECTORY may be
 relative or absolute.  If it is absolute, so that all matching files
 are backed up into the same directory, the file names in this
 directory will be the full name of the file backed up with all
-directory separators changed to `|' to prevent clashes.  This will not
+directory separators changed to `!' to prevent clashes.  This will not
 work correctly if your filesystem truncates the resulting name.
 
 For the common case of all backups going into one directory, the alist
@@ -2266,7 +2287,7 @@ doesn't exist, it is created."
 (defun make-backup-file-name-1 (file)
   "Subroutine of `make-backup-file-name' and `find-backup-file-name'."
   (let ((alist backup-directory-alist)
-       elt backup-directory)
+       elt backup-directory dir-sep-string)
     (while alist
       (setq elt (pop alist))
       (if (string-match (car elt) file)
@@ -2279,14 +2300,37 @@ doesn't exist, it is created."
            (make-directory backup-directory 'parents)
          (file-error file)))
       (if (file-name-absolute-p backup-directory)
-         ;; Make the name unique by substituting directory
-         ;; separators.  It may not really be worth bothering about
-         ;; doubling `|'s in the original name...
-         (expand-file-name
-          (subst-char-in-string
-           directory-sep-char ?|
-           (replace-regexp-in-string "|" "||" file))
-          backup-directory)
+         (progn
+           (when (memq system-type '(windows-nt ms-dos))
+             ;; Normalize DOSish file names: convert all slashes to
+             ;; directory-sep-char, downcase the drive letter, if any,
+             ;; and replace the leading "x:" with "/drive_x".
+             (or (file-name-absolute-p file)
+                 (setq file (expand-file-name file))) ; make defaults explicit
+             ;; Replace any invalid file-name characters (for the
+             ;; case of backing up remote files).
+             (setq file (convert-standard-filename file))
+             (setq dir-sep-string (char-to-string directory-sep-char))
+             (or (eq directory-sep-char ?/)
+                 (subst-char-in-string ?/ ?\\ file))
+             (or (eq directory-sep-char ?\\)
+                 (subst-char-in-string ?\\ ?/ file))
+             (if (eq (aref file 1) ?:)
+                 (setq file (concat dir-sep-string
+                                    "drive_"
+                                    (char-to-string (downcase (aref file 0)))
+                                    (if (eq (aref file 2) directory-sep-char)
+                                        ""
+                                      dir-sep-string)
+                                    (substring file 2)))))
+           ;; Make the name unique by substituting directory
+           ;; separators.  It may not really be worth bothering about
+           ;; doubling `!'s in the original name...
+           (expand-file-name
+            (subst-char-in-string
+             directory-sep-char ?!
+             (replace-regexp-in-string "!" "!!" file))
+            backup-directory))
        (expand-file-name (file-name-nondirectory file)
                          (file-name-as-directory
                           (expand-file-name backup-directory
@@ -2464,8 +2508,11 @@ the last real save, but optional arg FORCE non-nil means delete anyway."
 (defvar auto-save-hook nil
   "Normal hook run just before auto-saving.")
 
-(defvar after-save-hook nil
-  "Normal hook that is run after a buffer is saved to its file.")
+(defcustom after-save-hook nil
+  "Normal hook that is run after a buffer is saved to its file."
+  :options '(executable-make-buffer-file-executable-if-script-p)
+  :type 'hook
+  :group 'files)
 
 (defvar save-buffer-coding-system nil
   "If non-nil, use this coding system for saving the buffer.
@@ -2639,7 +2686,7 @@ After saving the buffer, this function runs `after-save-hook'."
        (cond ((and tempsetmodes (not setmodes))
               ;; Change the mode back, after writing.
               (setq setmodes (file-modes buffer-file-name))
-              (set-file-modes buffer-file-name 511)))
+              (set-file-modes buffer-file-name (logior setmodes 128))))
        (write-region (point-min) (point-max)
                      buffer-file-name nil t buffer-file-truename)))
     setmodes))
@@ -2983,12 +3030,15 @@ non-nil, it is called instead of rereading visited file contents."
             (not (file-exists-p file-name)))
           (error "Auto-save file %s not current" file-name))
          ((save-window-excursion
-            (if (not (memq system-type '(vax-vms windows-nt)))
-                (with-output-to-temp-buffer "*Directory*"
-                  (buffer-disable-undo standard-output)
-                  (call-process "ls" nil standard-output nil
-                                (if (file-symlink-p file) "-lL" "-l")
-                                file file-name)))
+            (with-output-to-temp-buffer "*Directory*"
+              (buffer-disable-undo standard-output)
+              (save-excursion
+                (let ((switches dired-listing-switches))
+                  (if (file-symlink-p file)
+                      (setq switches (concat switches "L")))
+                  (set-buffer standard-output)
+                  (insert-directory file switches)
+                  (insert-directory file-name switches))))
             (yes-or-no-p (format "Recover auto save file %s? " file-name)))
           (switch-to-buffer (find-file-noselect file t))
           (let ((buffer-read-only nil)
@@ -3011,6 +3061,9 @@ Then you'll be asked about a number of files to recover."
   (interactive)
   (if (null auto-save-list-file-prefix)
       (error "You set `auto-save-list-file-prefix' to disable making session files"))
+  (let ((dir (file-name-directory auto-save-list-file-prefix)))
+    (unless (file-directory-p dir)
+      (make-directory dir t)))
   (let ((ls-lisp-support-shell-wildcards t))
     (dired (concat auto-save-list-file-prefix "*")
           (concat dired-listing-switches "t")))
@@ -3177,7 +3230,7 @@ See also `auto-save-file-name-p'."
            (let ((fn (file-name-nondirectory buffer-file-name)))
              (string-match "\\`\\([^.]+\\)\\(\\.\\(..?\\)?.?\\|\\)\\'" fn)
              (concat (file-name-directory buffer-file-name)
-                     "#" (match-string 1 fn) 
+                     "#" (match-string 1 fn)
                      "." (match-string 3 fn) "#"))
          (concat (file-name-directory filename)
                  "#"
@@ -3371,6 +3424,52 @@ and `list-directory-verbose-switches'."
        (let ((wildcard (not (file-directory-p dirname))))
          (insert-directory dirname switches wildcard (not wildcard)))))))
 
+(defun shell-quote-wildcard-pattern (pattern)
+  "Quote characters special to the shell in PATTERN, leave wildcards alone.
+
+PATTERN is assumed to represent a file-name wildcard suitable for the
+underlying filesystem.  For Unix and GNU/Linux, the characters from the
+set [ \\t\\n;<>&|()#$] are quoted with a backslash; for DOS/Windows, all
+the parts of the pattern which don't include wildcard characters are
+quoted with double quotes.
+Existing quote characters in PATTERN are left alone, so you can pass
+PATTERN that already quotes some of the special characters."
+  (save-match-data
+    (cond
+     ((memq system-type '(ms-dos windows-nt))
+      ;; DOS/Windows don't allow `"' in file names.  So if the
+      ;; argument has quotes, we can safely assume it is already
+      ;; quoted by the caller.
+      (if (or (string-match "[\"]" pattern)
+             ;; We quote [&()#$'] in case their shell is a port of a
+             ;; Unixy shell.  We quote [,=+] because stock DOS and
+             ;; Windows shells require that in some cases, such as
+             ;; passing arguments to batch files that use positional
+             ;; arguments like %1.
+             (not (string-match "[ \t;&()#$',=+]" pattern)))
+         pattern
+       (let ((result "\"")
+             (beg 0)
+             end)
+         (while (string-match "[*?]+" pattern beg)
+           (setq end (match-beginning 0)
+                 result (concat result (substring pattern beg end)
+                                "\""
+                                (substring pattern end (match-end 0))
+                                "\"")
+                 beg (match-end 0)))
+         (concat result (substring pattern beg) "\""))))
+     (t
+      (let ((beg 0))
+       (while (string-match "[ \t\n;<>&|()#$]" pattern beg)
+         (setq pattern
+               (concat (substring pattern 0 (match-beginning 0))
+                       "\\"
+                       (substring pattern (match-beginning 0)))
+               beg (1+ (match-end 0)))))
+      pattern))))
+  
+
 (defvar insert-directory-program "ls"
   "Absolute or relative name of the `ls' program used by `insert-directory'.")
 
@@ -3406,7 +3505,7 @@ If WILDCARD, it also runs the shell specified by `shell-file-name'."
   ;; We need the directory in order to find the right handler.
   (let ((handler (find-file-name-handler (expand-file-name file)
                                         'insert-directory)))
-    (if handler
+   (if handler
        (funcall handler 'insert-directory file switches
                 wildcard full-directory-p)
       (if (eq system-type 'vax-vms)
@@ -3419,63 +3518,68 @@ If WILDCARD, it also runs the shell specified by `shell-file-name'."
               (coding-system-for-write coding-system-for-read)
               (result
                (if wildcard
-                   ;; Run ls in the directory of the file pattern we asked for.
+                   ;; Run ls in the directory of the file pattern we asked for
                    (let ((default-directory
                            (if (file-name-absolute-p file)
                                (file-name-directory file)
                              (file-name-directory (expand-file-name file))))
-                         (pattern (file-name-nondirectory file))
-                         (beg 0))
-                     ;; Quote some characters that have special meanings in shells;
-                     ;; but don't quote the wildcards--we want them to be special.
-                     ;; We also currently don't quote the quoting characters
-                     ;; in case people want to use them explicitly to quote
-                     ;; wildcard characters.
-                     (while (string-match "[ \t\n;<>&|()#$]" pattern beg)
-                       (setq pattern
-                             (concat (substring pattern 0 (match-beginning 0))
-                                     "\\"
-                                     (substring pattern (match-beginning 0)))
-                             beg (1+ (match-end 0))))
-                     (call-process shell-file-name nil t nil
-                                   "-c" (concat "\\";; Disregard shell aliases!
-                                                insert-directory-program
-                                                " -d "
-                                                (if (stringp switches)
-                                                    switches
-                                                  (mapconcat 'identity switches " "))
-                                                " -- "
-                                                 pattern)))
+                         (pattern (file-name-nondirectory file)))
+                     (call-process
+                      shell-file-name nil t nil
+                      "-c" (concat (if (memq system-type '(ms-dos windows-nt))
+                                       ""
+                                     "\\") ; Disregard Unix shell aliases!
+                                   insert-directory-program
+                                   " -d "
+                                   (if (stringp switches)
+                                       switches
+                                     (mapconcat 'identity switches " "))
+                                   " -- "
+                                   ;; Quote some characters that have
+                                   ;; special meanings in shells; but
+                                   ;; don't quote the wildcards--we
+                                   ;; want them to be special.  We
+                                   ;; also currently don't quote the
+                                   ;; quoting characters in case
+                                   ;; people want to use them
+                                   ;; explicitly to quote wildcard
+                                   ;; characters.
+                                   (shell-quote-wildcard-pattern pattern))))
                  ;; SunOS 4.1.3, SVr4 and others need the "." to list the
                  ;; directory if FILE is a symbolic link.
                  (apply 'call-process
-                         insert-directory-program nil t nil
-                         (let (list)
-                           (if (listp switches)
-                               (setq list switches)
-                             (if (not (equal switches ""))
-                                 (progn
-                                   ;; Split the switches at any spaces
-                                   ;; so we can pass separate options as separate args.
-                                   (while (string-match " " switches)
-                                     (setq list (cons (substring switches 0 (match-beginning 0))
-                                                      list)
-                                           switches (substring switches (match-end 0))))
-                                   (setq list (nreverse (cons switches list))))))
-                           (append list
-                                   ;; Avoid lossage if FILE starts with `-'.
-                                   '("--")
-                                   (progn
-                                     (if (string-match "\\`~" file)
-                                         (setq file (expand-file-name file)))
-                                     (list
-                                      (if full-directory-p
-                                          (concat (file-name-as-directory file) ".")
-                                        file)))))))))
+                        insert-directory-program nil t nil
+                        (append
+                         (if (listp switches) switches
+                           (unless (equal switches "")
+                             ;; Split the switches at any spaces so we can
+                             ;; pass separate options as separate args.
+                             (split-string switches)))
+                         ;; Avoid lossage if FILE starts with `-'.
+                         '("--")
+                         (progn
+                           (if (string-match "\\`~" file)
+                               (setq file (expand-file-name file)))
+                           (list
+                            (if full-directory-p
+                                (concat (file-name-as-directory file) ".")
+                              file))))))))
          (if (/= result 0)
-             ;; We get here if ls failed.
-             ;; Access the file to get a suitable error.
-             (access-file file "Reading directory")
+             ;; We get here if `insert-directory-program' failed.
+             ;; On non-Posix systems, we cannot open a directory, so
+             ;; don't even try, because that will always result in
+             ;; the ubiquitous "Access denied".  Instead, show them
+             ;; the `ls' command line and let them guess what went
+             ;; wrong.
+             (if (and (file-directory-p file)
+                      (memq system-type '(ms-dos windows-nt)))
+                 (error
+                  "Reading directory: \"%s %s -- %s\" exited with status %s"
+                  insert-directory-program
+                  (if (listp switches) (concat switches) switches)
+                  file result)
+               ;; Unix.  Access the file to get a suitable error.
+               (access-file file "Reading directory"))
            ;; Replace "total" with "used", to avoid confusion.
            ;; Add in the amount of free space.
            (save-excursion
@@ -3494,7 +3598,7 @@ If WILDCARD, it also runs the shell specified by `shell-file-name'."
                      (forward-word -1)
                      (setq available (buffer-substring (point) end))))
                  (insert " available " available))))))))))
-                   
+
 (defvar kill-emacs-query-functions nil
   "Functions to call with no arguments to query about killing Emacs.
 If any of these functions returns nil, killing Emacs is cancelled.