Doc fix.
[bpt/emacs.git] / lisp / files.el
index b86b8d6..bd808dd 100644 (file)
@@ -472,7 +472,7 @@ patterns and to guarantee valid names."
 
 (defvar cd-path nil
   "Value of the CDPATH environment variable, as a list.
-Not actually set up until the first time you you use it.")
+Not actually set up until the first time you use it.")
 
 (defun parse-colon-path (cd-path)
   "Explode a colon-separated search path into a list of directory names.
@@ -535,10 +535,11 @@ colon-separated list of directories when resolving a relative directory name."
 
 (defun load-file (file)
   "Load the Lisp file named FILE."
-  (interactive "fLoad file: ")
-  (let ((completion-ignored-extensions
-        (delete ".elc" completion-ignored-extensions)))
-    (load (expand-file-name file) nil nil t)))
+  ;; This is a case where .elc makes a lot of sense.
+  (interactive (list (let ((completion-ignored-extensions
+                           (remove ".elc" completion-ignored-extensions)))
+                      (read-file-name "Load file: "))))
+  (load (expand-file-name file) nil nil t))
 
 (defun load-library (library)
   "Load the library named LIBRARY.
@@ -940,20 +941,20 @@ If there is no such live buffer, return nil."
                  (setq found (car list))))
            (setq list (cdr list)))
          found)
-       (let ((number (nthcdr 10 (file-attributes truename)))
-             (list (buffer-list)) found)
+       (let* ((attributes (file-attributes truename))
+              (number (nthcdr 10 attributes))
+              (list (buffer-list)) found)
          (and buffer-file-numbers-unique
               number
               (while (and (not found) list)
-                (save-excursion
-                  (set-buffer (car list))
+                (with-current-buffer (car list)
                   (if (and buffer-file-name
                            (equal buffer-file-number number)
                            ;; Verify this buffer's file number
                            ;; still belongs to its file.
                            (file-exists-p buffer-file-name)
-                           (equal (nthcdr 10 (file-attributes buffer-file-name))
-                                  number))
+                           (equal (file-attributes buffer-file-name)
+                                  attributes))
                       (setq found (car list))))
                 (setq list (cdr list))))
          found))))
@@ -966,6 +967,15 @@ whose names match the pattern."
   :version "20.4"
   :type 'boolean)
 
+(defcustom find-file-suppress-same-file-warnings nil
+  "*Non-nil means suppress warning messages for symlinked files.
+When nil, Emacs prints a warning when visiting a file that is already
+visited, but with a different name.  Setting this option to t
+suppresses this warning."
+  :group 'files
+  :version "21.1"
+  :type 'boolean)
+
 (defun find-file-noselect (filename &optional nowarn rawfile wildcards)
   "Read file FILENAME into a buffer and return the buffer.
 If a buffer exists visiting FILENAME, return that one, but
@@ -998,7 +1008,7 @@ that are visiting the various files."
              (find-file-wildcards nil))
          (if (null files)
              (find-file-noselect filename)
-           (car (mapcar #'find-file-noselect files))))
+           (mapcar #'find-file-noselect files)))
       (let* ((buf (get-file-buffer filename))
             (truename (abbreviate-file-name (file-truename filename)))
             (number (nthcdr 10 (file-attributes truename)))
@@ -1008,6 +1018,7 @@ that are visiting the various files."
        (if other
            (progn
              (or nowarn
+                 find-file-suppress-same-file-warnings
                  (string-equal filename (buffer-file-name other))
                  (message "%s and %s are the same file"
                           filename (buffer-file-name other)))
@@ -1160,7 +1171,7 @@ that are visiting the various files."
   "Like `insert-file-contents', but only reads in the file literally.
 A buffer may be modified in several ways after reading into the buffer,
 to Emacs features such as format decoding, character code
-conversion, find-file-hooks, automatic uncompression, etc.
+conversion, `find-file-hooks', automatic uncompression, etc.
 
 This function ensures that none of these modifications will take place."
   (let ((format-alist nil)
@@ -1204,7 +1215,8 @@ Format conversion and character code conversion are both disabled,
 and multibyte characters are disabled in the resulting buffer.
 The major mode used is Fundamental mode regardless of the file name,
 and local variable specifications in the file are ignored.
-Automatic uncompression is also disabled.
+Automatic uncompression and adding a newline at the end of the
+file due to `require-final-newline' is also disabled.
 
 You cannot absolutely rely on this function to result in
 visiting the file literally.  If Emacs already has a buffer
@@ -1238,52 +1250,53 @@ unless NOMODES is non-nil."
       nil
     (let* (not-serious
           (msg
-           (cond ((and error (file-attributes buffer-file-name))
-                  (setq buffer-read-only t)
-                  "File exists, but cannot be read")
-                 ((not buffer-read-only)
-                  (if (and warn
-                           ;; No need to warn if buffer is auto-saved
-                           ;; under the name of the visited file.
-                           (not (and buffer-file-name
-                                     auto-save-visited-file-name))
-                           (file-newer-than-file-p (or buffer-auto-save-file-name
-                                                       (make-auto-save-file-name))
-                                                   buffer-file-name))
-                      (format "%s has auto save data; consider M-x recover-file"
-                              (file-name-nondirectory buffer-file-name))
-                    (setq not-serious t)
-                    (if error "(New file)" nil)))
-                 ((not error)
-                  (setq not-serious t)
-                  "Note: file is write protected")
-                 ((file-attributes (directory-file-name default-directory))
-                  "File not found and directory write-protected")
-                 ((file-exists-p (file-name-directory buffer-file-name))
-                  (setq buffer-read-only nil))
-                 (t
-                  (setq buffer-read-only nil)
-                  (if (file-exists-p (file-name-directory (directory-file-name (file-name-directory buffer-file-name))))
-                      "Use M-x make-directory RET RET to create the directory"
-                    "Use C-u M-x make-directory RET RET to create directory and its parents")))))
-      (if msg
-         (progn
-           (message msg)
-           (or not-serious (sit-for 1 nil t)))))
-    (if (and auto-save-default (not noauto))
-       (auto-save-mode t)))
+           (cond
+            ((not warn) nil)
+            ((and error (file-attributes buffer-file-name))
+             (setq buffer-read-only t)
+             "File exists, but cannot be read")
+            ((not buffer-read-only)
+             (if (and warn
+                      ;; No need to warn if buffer is auto-saved
+                      ;; under the name of the visited file.
+                      (not (and buffer-file-name
+                                auto-save-visited-file-name))
+                      (file-newer-than-file-p (or buffer-auto-save-file-name
+                                                  (make-auto-save-file-name))
+                                              buffer-file-name))
+                 (format "%s has auto save data; consider M-x recover-file"
+                         (file-name-nondirectory buffer-file-name))
+               (setq not-serious t)
+               (if error "(New file)" nil)))
+            ((not error)
+             (setq not-serious t)
+             "Note: file is write protected")
+            ((file-attributes (directory-file-name default-directory))
+             "File not found and directory write-protected")
+            ((file-exists-p (file-name-directory buffer-file-name))
+             (setq buffer-read-only nil))
+            (t
+             (setq buffer-read-only nil)
+             (if (file-exists-p (file-name-directory (directory-file-name (file-name-directory buffer-file-name))))
+                 "Use M-x make-directory RET RET to create the directory"
+               "Use C-u M-x make-directory RET RET to create directory and its parents")))))
+      (when msg
+       (message msg)
+       (or not-serious (sit-for 1 nil t))))
+    (when (and auto-save-default (not noauto))
+      (auto-save-mode t)))
   ;; Make people do a little extra work (C-x C-q)
   ;; before altering a backup file.
-  (if (backup-file-name-p buffer-file-name)
-      (setq buffer-read-only t))
-  (if nomodes
-      nil
-    (and view-read-only view-mode
-        (view-mode-disable))
+  (when (backup-file-name-p buffer-file-name)
+    (setq buffer-read-only t))
+  (unless nomodes
+    (when (and view-read-only view-mode)
+      (view-mode-disable))
     (normal-mode t)
-    (if (and buffer-read-only view-read-only
-            (not (eq (get major-mode 'mode-class) 'special)))
-       (view-mode-enter))
+    (when (and buffer-read-only
+              view-read-only
+              (not (eq (get major-mode 'mode-class) 'special)))
+      (view-mode-enter))
     (run-hooks 'find-file-hooks)))
 
 (defun normal-mode (&optional find-file)
@@ -1370,16 +1383,12 @@ in that case, this function acts as if `enable-local-variables' were t."
      ("\\(/\\|\\`\\)\\.\\(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)
+     ("\\.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
@@ -1434,17 +1443,24 @@ in that case, this function acts as if `enable-local-variables' were t."
      ("[:/]_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)
+     ("\\.\\(asn\\|mib\\|smi\\)\\'" . snmp-mode)
+     ("\\.\\(as\\|mi\\|sm\\)2\\'" . snmpv2-mode)
      ("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode)
-     ("\\.[eE]?[pP][sS]$" . ps-mode)
+     ("\\.\\(dif\\|pat\\)\\'" . diff-mode) ; for MSDOG
+     ("\\.[eE]?[pP][sS]\\'" . ps-mode)
      ("configure\\.in\\'" . autoconf-mode)
      ("BROWSE\\'" . ebrowse-tree-mode)
-     ("\\.ebrowse\\'" . ebrowse-tree-mode)))
+     ("\\.ebrowse\\'" . ebrowse-tree-mode)
+     ("#\\*mail\\*" . mail-mode)
+     ;; Get rid of any trailing .n.m and try again.
+     ;; This is for files saved by cvs-merge that look like .#<file>.<rev>
+     ;; or .#<file>.<rev>-<rev> or VC's <file>.~<rev>~
+     ("\\.~?[0-9]+\\.[0-9][-.0-9]*~?\\'" nil t)
+;;; The following should come after the ChangeLog pattern
+;;; for the sake of ChangeLog.1, etc.
+;;; and after the .scm.[0-9] and CVS' <file>.<rev> patterns too.
+     ("\\.[12345678]\\'" . nroff-mode)
+     ("\\.g\\'" . antlr-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.)
@@ -1513,6 +1529,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,
@@ -1584,18 +1611,20 @@ and we don't even do that unless it would come from the file name."
                       (forward-char -1)
                     (goto-char end))
                   (skip-chars-backward " \t")
-                  (setq modes (cons (intern (concat (downcase (buffer-substring beg (point))) "-mode"))
-                                    modes)))
+                  (push (intern (concat (downcase (buffer-substring beg (point))) "-mode"))
+                        modes))
               ;; Simple -*-MODE-*- case.
-              (setq modes (cons (intern (concat (downcase (buffer-substring beg end))
-                                                "-mode"))
-                                modes))))))
+              (push (intern (concat (downcase (buffer-substring beg end))
+                                    "-mode"))
+                    modes)))))
     ;; If we found modes to use, invoke them now,
     ;; outside the save-excursion.
-    (when modes
-      (unless just-from-file-name
-       (mapc 'funcall (nreverse modes)))
-      (setq done t))
+    (unless just-from-file-name
+      (dolist (mode (nreverse modes))
+       (if (not (functionp mode))
+           (message "Ignoring unknown mode `%s'" mode)
+         (setq done t)
+         (funcall mode))))
     ;; If we didn't find a mode from a -*- line, try using the file name.
     (if (and (not done) buffer-file-name)
        (let ((name buffer-file-name)
@@ -1634,8 +1663,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)
@@ -2218,7 +2246,7 @@ the value is \"\"."
   "A function to use instead of the default `make-backup-file-name'.
 A value of nil gives the default `make-backup-file-name' behaviour.
 
-This could be buffer-local to do something special for for specific
+This could be buffer-local to do something special for specific
 files.  If you define it, you may need to change `backup-file-name-p'
 and `file-name-sans-versions' too.
 
@@ -2299,12 +2327,8 @@ doesn't exist, it is created."
                  (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 file (expand-file-name (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_"
@@ -2359,7 +2383,11 @@ Uses `backup-directory-alist' in the same way as does
     ;; Run a handler for this function so that ange-ftp can refuse to do it.
     (if handler
        (funcall handler 'find-backup-file-name fn)
-      (if (eq version-control 'never)
+      (if (or (eq version-control 'never)
+             ;; We don't support numbered backups on plain MS-DOS
+             ;; when long file names are unavailable.
+             (and (eq system-type 'ms-dos)
+                  (not (msdos-long-file-names))))
          (list (make-backup-file-name fn))
        (let* ((basic-name (make-backup-file-name-1 fn))
               (base-versions (concat (file-name-nondirectory basic-name)
@@ -2562,6 +2590,7 @@ After saving the buffer, this function runs `after-save-hook'."
            (widen)
            (save-excursion
              (and (> (point-max) 1)
+                  (not find-file-literally)
                   (/= (char-after (1- (point-max))) ?\n)
                   (not (and (eq selective-display t)
                             (= (char-after (1- (point-max))) ?\r)))
@@ -2573,6 +2602,8 @@ After saving the buffer, this function runs `after-save-hook'."
                   (save-excursion
                     (goto-char (point-max))
                     (insert ?\n))))
+           ;; Support VC version backups.
+           (vc-before-save)
            (or (run-hook-with-args-until-success 'write-contents-hooks)
                (run-hook-with-args-until-success 'local-write-file-hooks)
                (run-hook-with-args-until-success 'write-file-hooks)
@@ -2984,7 +3015,7 @@ non-nil, it is called instead of rereading visited file contents."
                   (let ((coding-system-for-read
                          ;; Auto-saved file shoule be read without
                          ;; any code conversion.
-                         (if auto-save-p 'no-conversion
+                         (if auto-save-p 'emacs-mule-unix
                            coding-system-for-read)))
                     ;; Note that this preserves point in an intelligent way.
                     (insert-file-contents file-name (not auto-save-p)
@@ -3020,19 +3051,28 @@ 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)
+                  ;; Use insert-directory-safely, not insert-directory,
+                  ;; because these files might not exist.  In particular,
+                  ;; FILE might not exist if the auto-save file was for
+                  ;; a buffer that didn't visit a file, such as "*mail*".
+                  ;; The code in v20.x called `ls' directly, so we need
+                  ;; to emulate what `ls' did in that case.
+                  (insert-directory-safely file switches)
+                  (insert-directory-safely 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)
                 ;; Keep the current buffer-file-coding-system.
                 (coding-system buffer-file-coding-system)
                 ;; Auto-saved file shoule be read without any code conversion.
-                (coding-system-for-read 'no-conversion))
+                (coding-system-for-read 'emacs-mule-unix))
             (erase-buffer)
             (insert-file-contents file-name nil)
             (set-buffer-file-coding-system coding-system))
@@ -3455,7 +3495,7 @@ PATTERN that already quotes some of the special characters."
                        (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'.")
@@ -3490,9 +3530,9 @@ This works by running a directory listing program
 whose name is in the variable `insert-directory-program'.
 If WILDCARD, it also runs the shell specified by `shell-file-name'."
   ;; We need the directory in order to find the right handler.
-  (let* ((file (expand-file-name file))
-         (handler (find-file-name-handler file 'insert-directory)))
-    (if handler
+  (let ((handler (find-file-name-handler (expand-file-name file)
+                                        'insert-directory)))
+   (if handler
        (funcall handler 'insert-directory file switches
                 wildcard full-directory-p)
       (if (eq system-type 'vax-vms)
@@ -3506,19 +3546,22 @@ If WILDCARD, it also runs the shell specified by `shell-file-name'."
               (result
                (if wildcard
                    ;; Run ls in the directory of the file pattern we asked for
-                   (let ((default-directory (file-name-directory file))
+                   (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)))
                      (call-process
-                       shell-file-name nil t nil
-                       "-c" (concat (if (memq system-type '(ms-dos windows-nt))
+                      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 " "))
-                                    " -- "
+                                   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
@@ -3528,30 +3571,42 @@ If WILDCARD, it also runs the shell specified by `shell-file-name'."
                                    ;; people want to use them
                                    ;; explicitly to quote wildcard
                                    ;; characters.
-                                    (shell-quote-wildcard-pattern pattern))))
+                                   (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
-                          (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))))))))
+                        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 `insert-directory-program' failed.
-             ;; Access the file to get a suitable error.
-             (access-file file "Reading directory")
+             ;; 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
@@ -3571,6 +3626,17 @@ If WILDCARD, it also runs the shell specified by `shell-file-name'."
                      (setq available (buffer-substring (point) end))))
                  (insert " available " available))))))))))
 
+(defun insert-directory-safely (file switches
+                                    &optional wildcard full-directory-p)
+  "Insert directory listing for FILE, formatted according to SWITCHES.
+
+Like `insert-directory', but if FILE does not exist, it inserts a
+message to that effect instead of signaling an error."
+  (if (file-exists-p file)
+      (insert-directory file switches wildcard full-directory-p)
+    ;; Simulate the message printed by `ls'.
+    (insert (format "%s: No such file or directory\n" file))))
+
 (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.