;;; files.el --- file input and output commands for Emacs
-;; Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;; 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994, 1995, 1996,
+;; 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+;; 2006 Free Software Foundation, Inc.
;; Maintainer: FSF
(defcustom enable-local-variables t
"*Control use of local variables in files you visit.
-The value can be t, nil or something else.
-A value of t means file local variables specifications are obeyed;
-nil means they are ignored; anything else means query.
+The value can be t, nil, :safe, or something else.
+
+A value of t means file local variables specifications are obeyed
+if all the specified variable values are safe; if any values are
+not safe, Emacs queries you, once, whether to set them all.
+\(When you say yes to certain values, they are remembered as safe.)
+
+:safe means set the safe variables, and ignore the rest.
+:all means set all variables, whether safe or not.
+ (Don't set it permanently to :all.)
+nil means always ignore the file local variables.
+
+Any other value means always query you once whether to set them all.
+\(When you say yes to certain values, they are remembered as safe, but
+this has no effect when `enable-local-variables' is \"something else\".)
+
This variable also controls use of major modes specified in
a -*- line.
The command \\[normal-mode], when used interactively,
always obeys file local variable specifications and the -*- line,
and ignores this variable."
- :type '(choice (const :tag "Obey" t)
+ :type '(choice (const :tag "Query Unsafe" t)
+ (const :tag "Safe Only" :safe)
+ (const :tag "Do all" :all)
(const :tag "Ignore" nil)
(other :tag "Query" other))
:group 'find-file)
(interactive
(list (completing-read "Load library: "
'locate-file-completion
- (cons load-path load-suffixes))))
+ (cons load-path (get-load-suffixes)))))
(load library))
(defun file-remote-p (file)
(pop-to-buffer buffer t norecord)
(raise-frame (window-frame (selected-window)))))
+(defun display-buffer-other-frame (buffer)
+ "Switch to buffer BUFFER in another frame.
+This uses the function `display-buffer' as a subroutine; see its
+documentation for additional customization information."
+ (interactive "BDisplay buffer in other frame: ")
+ (let ((pop-up-frames t)
+ same-window-buffer-names same-window-regexps
+ (old-window (selected-window))
+ new-window)
+ (setq new-window (display-buffer buffer t))
+ (lower-frame (window-frame new-window))
+ (make-frame-invisible (window-frame old-window))
+ (make-frame-visible (window-frame old-window))))
+
(defvar find-file-default nil
"Used within `find-file-read-args'.")
Interactively, or if WILDCARDS is non-nil in a call from Lisp,
expand wildcards (if any) and visit multiple files. You can
-suppress wildcard expansion by setting `find-file-wildcards'.
+suppress wildcard expansion by setting `find-file-wildcards' to nil.
To visit a file without any kind of conversion and without
automatically choosing a major mode, use \\[find-file-literally]."
(defun find-file-existing (filename &optional wildcards)
"Edit the existing file FILENAME.
-Like \\[find-file] but only allow files that exists."
+Like \\[find-file] but only allow a file that exists."
(interactive (find-file-read-args "Find existing file: " t))
(unless (file-exists-p filename) (error "%s does not exist" filename))
(find-file filename wildcards)
This function is called automatically from `find-file'. In that case,
we may set up the file-specified mode and local variables,
-depending on the value of `enable-local-variables': if it is t, we do;
-if it is nil, we don't; otherwise, we query.
+depending on the value of `enable-local-variables'.
In addition, if `local-enable-local-variables' is nil, we do
not set local variables (though we do notice a mode specified with -*-.)
;; `auto-coding-alist' with `no-conversion' coding system.
("\\.\\(arc\\|zip\\|lzh\\|zoo\\|[jew]ar\\|xpi\\)\\'" . archive-mode)
("\\.\\(ARC\\|ZIP\\|LZH\\|ZOO\\|[JEW]AR\\|XPI\\)\\'" . archive-mode)
- ("\\.sx[dmicw]\\'" . archive-mode) ; OpenOffice.org
+ ("\\.\\(sx[dmicw]\\|odt\\)\\'" . archive-mode) ; OpenOffice.org
;; Mailer puts message to be edited in
;; /tmp/Re.... or Message
("\\`/tmp/Re" . text-mode)
If the file name matches `inhibit-first-line-modes-regexps',
then `auto-mode-alist' is not processed.
+The extensions whose FUNCTION is `archive-mode' should also
+appear in `auto-coding-alist' with `no-conversion' coding system.
+
See also `interpreter-mode-alist', which detects executable script modes
based on the interpreters they specify to run,
and `magic-mode-alist', which determines modes based on file contents.")
(defvar magic-mode-alist
`(;; The < comes before the groups (but the first) to reduce backtracking.
;; TODO: UTF-16 <?xml may be preceded by a BOM 0xff 0xfe or 0xfe 0xff.
+ ;; We use [ \t\n] instead of `\\s ' to make regex overflow less likely.
(,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
- (comment-re (concat "\\(?:!--" incomment-re "*-->\\s *<\\)")))
- (concat "\\(?:<\\?xml\\s +[^>]*>\\)?\\s *<"
+ (comment-re (concat "\\(?:!--" incomment-re "*-->[ \t\n]*<\\)")))
+ (concat "\\(?:<\\?xml[ \t\n]+[^>]*>\\)?[ \t\n]*<"
comment-re "*"
- "\\(?:!DOCTYPE\\s +[^>]*>\\s *<\\s *" comment-re "*\\)?"
+ "\\(?:!DOCTYPE[ \t\n]+[^>]*>[ \t\n]*<[ \t\n]*" comment-re "*\\)?"
"[Hh][Tt][Mm][Ll]"))
. html-mode)
;; These two must come after html, because they are more general:
("<\\?xml " . xml-mode)
(,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
- (comment-re (concat "\\(?:!--" incomment-re "*-->\\s *<\\)")))
- (concat "\\s *<" comment-re "*!DOCTYPE "))
+ (comment-re (concat "\\(?:!--" incomment-re "*-->[ \t\n]*<\\)")))
+ (concat "[ \t\n]*<" comment-re "*!DOCTYPE "))
. sgml-mode)
("%![^V]" . ps-mode)
("# xmcd " . conf-unix-mode))
(setq end (point))
(goto-char beg)
end))))
+\f
+;;; Handling file local variables
-(defun hack-local-variables-confirm (string flag-to-check)
- (or (eq flag-to-check t)
- (and flag-to-check
- (save-window-excursion
- (condition-case nil
- (switch-to-buffer (current-buffer))
- (error
- ;; If we fail to switch in the selected window,
- ;; it is probably a minibuffer or dedicated window.
- ;; So try another window.
- (let ((pop-up-frames nil))
- ;; Refrain from popping up frames since it can't
- ;; be undone by save-window-excursion.
- (pop-to-buffer (current-buffer)))))
- (save-excursion
- (beginning-of-line)
- (set-window-start (selected-window) (point)))
- (y-or-n-p (format string
- (if buffer-file-name
- (file-name-nondirectory buffer-file-name)
- (concat "buffer " (buffer-name)))))))))
+(defvar ignored-local-variables
+ '(ignored-local-variables safe-local-variable-values)
+ "Variables to be ignored in a file's local variable spec.")
+
+(defvar hack-local-variables-hook nil
+ "Normal hook run after processing a file's local variables specs.
+Major modes can use this to examine user-specified local variables
+in order to initialize other data structure based on them.")
+
+(defcustom safe-local-variable-values nil
+ "List variable-value pairs that are considered safe.
+Each element is a cons cell (VAR . VAL), where VAR is a variable
+symbol and VAL is a value that is considered safe."
+ :group 'find-file
+ :type 'alist)
+
+(defcustom safe-local-eval-forms nil
+ "*Expressions that are considered safe in an `eval:' local variable.
+Add expressions to this list if you want Emacs to evaluate them, when
+they appear in an `eval' local variable specification, without first
+asking you for confirmation."
+ :group 'find-file
+ :version "22.1"
+ :type '(repeat sexp))
+
+;; Risky local variables:
+(mapc (lambda (var) (put var 'risky-local-variable t))
+ '(after-load-alist
+ auto-mode-alist
+ buffer-auto-save-file-name
+ buffer-file-name
+ buffer-file-truename
+ buffer-undo-list
+ dabbrev-case-fold-search
+ dabbrev-case-replace
+ debugger
+ default-text-properties
+ display-time-string
+ enable-local-eval
+ enable-local-variables
+ eval
+ exec-directory
+ exec-path
+ file-name-handler-alist
+ font-lock-defaults
+ format-alist
+ frame-title-format
+ global-mode-string
+ header-line-format
+ icon-title-format
+ ignored-local-variables
+ imenu--index-alist
+ imenu-generic-expression
+ inhibit-quit
+ input-method-alist
+ load-path
+ max-lisp-eval-depth
+ max-specpdl-size
+ minor-mode-alist
+ minor-mode-map-alist
+ minor-mode-overriding-map-alist
+ mode-line-buffer-identification
+ mode-line-format
+ mode-line-modes
+ mode-line-modified
+ mode-line-mule-info
+ mode-line-position
+ mode-line-process
+ mode-name
+ outline-level
+ overriding-local-map
+ overriding-terminal-local-map
+ parse-time-rules
+ process-environment
+ rmail-output-file-alist
+ safe-local-variable-values
+ safe-local-eval-forms
+ save-some-buffers-action-alist
+ special-display-buffer-names
+ standard-input
+ standard-output
+ unread-command-events
+ vc-mode))
+
+;; Safe local variables:
+;;
+;; For variables defined by major modes, the safety declarations can go into
+;; the major mode's file, since that will be loaded before file variables are
+;; processed.
+;;
+;; For variables defined by minor modes, put the safety declarations in the
+;; file defining the minor mode after the defcustom/defvar using an autoload
+;; cookie, e.g.:
+;;
+;; ;;;###autoload(put 'variable 'safe-local-variable 'stringp)
+;;
+;; Otherwise, when Emacs visits a file specifying that local variable, the
+;; minor mode file may not be loaded yet.
+;;
+;; For variables defined in the C source code the declaration should go here:
+
+;; FIXME: Some variables should be moved according to the rules above.
+(let ((string-or-null (lambda (a) (or (stringp a) (null a)))))
+ (eval
+ `(mapc (lambda (pair)
+ (put (car pair) 'safe-local-variable (cdr pair)))
+ '((byte-compile-dynamic . booleanp)
+ (byte-compile-dynamic-docstrings . booleanp)
+ (byte-compile-warnings . booleanp)
+ (c-basic-offset . integerp)
+ (c-file-style . stringp)
+ (c-indent-level . integerp)
+ (comment-column . integerp)
+ (compile-command . string-or-null-p)
+ (find-file-visit-truename . booleanp)
+ (fill-column . integerp)
+ (fill-prefix . string-or-null-p)
+ (indent-tabs-mode . booleanp) ;; C source code
+ (kept-old-versions . integerp)
+ (kept-new-versions . integerp)
+ (left-margin . integerp)
+ (no-byte-compile . booleanp)
+ (no-update-autoloads . booleanp)
+ (outline-regexp . string-or-null-p)
+ (tab-width . integerp) ;; C source code
+ (truncate-lines . booleanp) ;; C source code
+ (version-control . symbolp)))))
+
+(put 'c-set-style 'safe-local-eval-function t)
+
+(defun hack-local-variables-confirm (vars unsafe-vars risky-vars)
+ (if noninteractive
+ nil
+ (let ((name (if buffer-file-name
+ (file-name-nondirectory buffer-file-name)
+ (concat "buffer " (buffer-name))))
+ (offer-save (and (eq enable-local-variables t) unsafe-vars))
+ prompt char)
+ (save-window-excursion
+ (let ((buf (get-buffer-create "*Local Variables*")))
+ (pop-to-buffer buf)
+ (set (make-local-variable 'cursor-type) nil)
+ (erase-buffer)
+ (if unsafe-vars
+ (insert "The local variables list in " name
+ "\ncontains values that may not be safe (*)"
+ (if risky-vars
+ ", and variables that are risky (**)."
+ "."))
+ (if risky-vars
+ (insert "The local variables list in " name
+ "\ncontains variables that are risky (**).")
+ (insert "A local variables list is specified in " name ".")))
+ (insert "\n\nDo you want to apply it? You can type
+y -- to apply the local variables list.
+n -- to ignore the local variables list.")
+ (if offer-save
+ (insert "
+! -- to apply the local variables list, and permanently mark these
+ values (*) as safe (in the future, they will be set automatically.)\n\n")
+ (insert "\n\n"))
+ (dolist (elt vars)
+ (cond ((member elt unsafe-vars)
+ (insert " * "))
+ ((member elt risky-vars)
+ (insert " ** "))
+ (t
+ (insert " ")))
+ (princ (car elt) buf)
+ (insert " : ")
+ (princ (cdr elt) buf)
+ (insert "\n"))
+ (setq prompt
+ (format "Please type %s%s: "
+ (if offer-save "y, n, or !" "y or n")
+ (if (< (line-number-at-pos) (window-body-height))
+ ""
+ ", or C-v to scroll")))
+ (goto-char (point-min))
+ (let ((cursor-in-echo-area t)
+ (exit-chars
+ (if offer-save '(?! ?y ?n ?\s ?\C-g) '(?y ?n ?\s ?\C-g)))
+ done)
+ (while (not done)
+ (message prompt)
+ (setq char (read-event))
+ (if (numberp char)
+ (if (eq char ?\C-v)
+ (condition-case nil
+ (scroll-up)
+ (error (goto-char (point-min))))
+ (setq done (memq (downcase char) exit-chars))))))
+ (setq char (downcase char))
+ (when (and offer-save (= char ?!) unsafe-vars)
+ (dolist (elt unsafe-vars)
+ (add-to-list 'safe-local-variable-values elt))
+ ;; When this is called from desktop-restore-file-buffer,
+ ;; coding-system-for-read may be non-nil. Reset it before
+ ;; writing to .emacs.
+ (if (or custom-file user-init-file)
+ (let ((coding-system-for-read nil))
+ (customize-save-variable
+ 'safe-local-variable-values
+ safe-local-variable-values))))
+ (kill-buffer buf)
+ (or (= char ?!)
+ (= char ?\s)
+ (= char ?y)))))))
(defun hack-local-variables-prop-line (&optional mode-only)
- "Set local variables specified in the -*- line.
+ "Return local variables specified in the -*- line.
Ignore any specification for `mode:' and `coding:';
`set-auto-mode' should already have handled `mode:',
`set-auto-coding' should already have handled `coding:'.
-If MODE-ONLY is non-nil, all we do is check whether the major mode
-is specified, returning t if it is specified."
+
+If MODE-ONLY is non-nil, all we do is check whether the major
+mode is specified, returning t if it is specified. Otherwise,
+return an alist of elements (VAR . VAL), where VAR is a variable
+and VAL is the specified value."
(save-excursion
(goto-char (point-min))
- (let ((result nil)
- (end (set-auto-mode-1))
- mode-specified
- (enable-local-variables
- (and local-enable-local-variables enable-local-variables)))
+ (let ((end (set-auto-mode-1))
+ result mode-specified)
;; Parse the -*- line into the RESULT alist.
;; Also set MODE-SPECIFIED if we see a spec or `mode'.
(cond ((not end)
;; so we must do that here as well.
;; That is inconsistent, but we're stuck with it.
;; The same can be said for `coding' in set-auto-coding.
- (or (equal (downcase (symbol-name key)) "mode")
+ (or (and (equal (downcase (symbol-name key)) "mode")
+ (setq mode-specified t))
(equal (downcase (symbol-name key)) "coding")
- (setq result (cons (cons key val) result)))
- (if (equal (downcase (symbol-name key)) "mode")
- (setq mode-specified t))
- (skip-chars-forward " \t;")))
- (setq result (nreverse result))))
-
- (if mode-only mode-specified
- (if (and result
- (or mode-only
- (hack-local-variables-confirm
- "Set local variables as specified in -*- line of %s? "
- enable-local-variables)))
- (let ((enable-local-eval enable-local-eval))
- (while result
- (hack-one-local-variable (car (car result)) (cdr (car result)))
- (setq result (cdr result)))))
- nil))))
-
-(defvar hack-local-variables-hook nil
- "Normal hook run after processing a file's local variables specs.
-Major modes can use this to examine user-specified local variables
-in order to initialize other data structure based on them.")
+ (condition-case nil
+ (push (cons (if (eq key 'eval)
+ 'eval
+ (indirect-variable key))
+ val) result)
+ (error nil)))
+ (skip-chars-forward " \t;")))))
+
+ (if mode-only
+ mode-specified
+ result))))
(defun hack-local-variables (&optional mode-only)
"Parse and put into effect this buffer's local variables spec.
If MODE-ONLY is non-nil, all we do is check whether the major mode
is specified, returning t if it is specified."
- (let ((mode-specified
- ;; If MODE-ONLY is t, we check here for specifying the mode
- ;; in the -*- line. If MODE-ONLY is nil, we process
- ;; the -*- line here.
- (hack-local-variables-prop-line mode-only))
- (enable-local-variables
- (and local-enable-local-variables enable-local-variables)))
- ;; Look for "Local variables:" line in last page.
- (save-excursion
- (goto-char (point-max))
- (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
- (when (let ((case-fold-search t))
- (and (search-forward "Local Variables:" nil t)
- (or mode-only
- (hack-local-variables-confirm
- "Set local variables as specified at end of %s? "
- enable-local-variables))))
- (skip-chars-forward " \t")
- (let ((enable-local-eval enable-local-eval)
- ;; suffix is what comes after "local variables:" in its line.
- (suffix
- (concat
- (regexp-quote (buffer-substring (point) (line-end-position)))
- "$"))
- ;; prefix is what comes before "local variables:" in its line.
- (prefix
- (concat "^" (regexp-quote
- (buffer-substring (line-beginning-position)
- (match-beginning 0)))))
- beg)
-
- (forward-line 1)
- (let ((startpos (point))
- endpos
- (thisbuf (current-buffer)))
- (save-excursion
- (unless (let ((case-fold-search t))
- (re-search-forward
- (concat prefix "[ \t]*End:[ \t]*" suffix)
- nil t))
- (error "Local variables list is not properly terminated"))
- (beginning-of-line)
- (setq endpos (point)))
-
- (with-temp-buffer
- (insert-buffer-substring thisbuf startpos endpos)
- (goto-char (point-min))
- (subst-char-in-region (point) (point-max) ?\^m ?\n)
- (while (not (eobp))
- ;; Discard the prefix.
- (if (looking-at prefix)
- (delete-region (point) (match-end 0))
- (error "Local variables entry is missing the prefix"))
- (end-of-line)
- ;; Discard the suffix.
- (if (looking-back suffix)
- (delete-region (match-beginning 0) (point))
- (error "Local variables entry is missing the suffix"))
- (forward-line 1))
- (goto-char (point-min))
-
- (while (not (eobp))
- ;; Find the variable name; strip whitespace.
- (skip-chars-forward " \t")
- (setq beg (point))
- (skip-chars-forward "^:\n")
- (if (eolp) (error "Missing colon in local variables entry"))
- (skip-chars-backward " \t")
- (let* ((str (buffer-substring beg (point)))
- (var (read str))
- val)
- ;; Read the variable value.
- (skip-chars-forward "^:")
- (forward-char 1)
- (setq val (read (current-buffer)))
- (if mode-only
- (if (eq var 'mode)
- (setq mode-specified t))
- ;; Set the variable. "Variables" mode and eval are funny.
- (with-current-buffer thisbuf
- (hack-one-local-variable var val))))
- (forward-line 1)))))))
- (unless mode-only
- (run-hooks 'hack-local-variables-hook))
- mode-specified))
-
-(defvar ignored-local-variables ()
- "Variables to be ignored in a file's local variable spec.")
-
-;; Get confirmation before setting these variables as locals in a file.
-(put 'debugger 'risky-local-variable t)
-(put 'enable-local-eval 'risky-local-variable t)
-(put 'ignored-local-variables 'risky-local-variable t)
-(put 'eval 'risky-local-variable t)
-(put 'file-name-handler-alist 'risky-local-variable t)
-(put 'inhibit-quit 'risky-local-variable t)
-(put 'minor-mode-alist 'risky-local-variable t)
-(put 'minor-mode-map-alist 'risky-local-variable t)
-(put 'minor-mode-overriding-map-alist 'risky-local-variable t)
-(put 'overriding-local-map 'risky-local-variable t)
-(put 'overriding-terminal-local-map 'risky-local-variable t)
-(put 'auto-mode-alist 'risky-local-variable t)
-(put 'after-load-alist 'risky-local-variable t)
-(put 'buffer-file-name 'risky-local-variable t)
-(put 'buffer-undo-list 'risky-local-variable t)
-(put 'buffer-auto-save-file-name 'risky-local-variable t)
-(put 'buffer-file-truename 'risky-local-variable t)
-(put 'default-text-properties 'risky-local-variable t)
-(put 'exec-path 'risky-local-variable t)
-(put 'load-path 'risky-local-variable t)
-(put 'exec-directory 'risky-local-variable t)
-(put 'process-environment 'risky-local-variable t)
-(put 'dabbrev-case-fold-search 'risky-local-variable t)
-(put 'dabbrev-case-replace 'risky-local-variable t)
-;; Don't wait for outline.el to be loaded, for the sake of outline-minor-mode.
-(put 'outline-level 'risky-local-variable t)
-(put 'rmail-output-file-alist 'risky-local-variable t)
-(put 'font-lock-defaults 'risky-local-variable t)
-(put 'special-display-buffer-names 'risky-local-variable t)
-(put 'frame-title-format 'risky-local-variable t)
-(put 'global-mode-string 'risky-local-variable t)
-(put 'header-line-format 'risky-local-variable t)
-(put 'icon-title-format 'risky-local-variable t)
-(put 'input-method-alist 'risky-local-variable t)
-(put 'format-alist 'risky-local-variable t)
-(put 'vc-mode 'risky-local-variable t)
-(put 'imenu-generic-expression 'risky-local-variable t)
-(put 'imenu--index-alist 'risky-local-variable t)
-(put 'standard-input 'risky-local-variable t)
-(put 'standard-output 'risky-local-variable t)
-(put 'unread-command-events 'risky-local-variable t)
-(put 'max-lisp-eval-depth 'risky-local-variable t)
-(put 'max-specpdl-size 'risky-local-variable t)
-(put 'mode-line-format 'risky-local-variable t)
-(put 'mode-line-modified 'risky-local-variable t)
-(put 'mode-line-mule-info 'risky-local-variable t)
-(put 'mode-line-buffer-identification 'risky-local-variable t)
-(put 'mode-line-modes 'risky-local-variable t)
-(put 'mode-line-position 'risky-local-variable t)
-(put 'mode-line-process 'risky-local-variable t)
-(put 'mode-name 'risky-local-variable t)
-(put 'display-time-string 'risky-local-variable t)
-(put 'parse-time-rules 'risky-local-variable t)
-
-;; This case is safe because the user gets to check it before it is used.
-(put 'compile-command 'safe-local-variable 'stringp)
-
-(defun risky-local-variable-p (sym &optional val)
- "Non-nil if SYM could be dangerous as a file-local variable with value VAL.
-If VAL is nil or omitted, the question is whether any value might be
-dangerous."
+ (let ((enable-local-variables
+ (and local-enable-local-variables enable-local-variables))
+ result)
+ (when (or mode-only enable-local-variables)
+ (setq result (hack-local-variables-prop-line mode-only))
+ ;; Look for "Local variables:" line in last page.
+ (save-excursion
+ (goto-char (point-max))
+ (search-backward "\n\^L" (max (- (point-max) 3000) (point-min))
+ 'move)
+ (when (let ((case-fold-search t))
+ (search-forward "Local Variables:" nil t))
+ (skip-chars-forward " \t")
+ ;; suffix is what comes after "local variables:" in its line.
+ ;; prefix is what comes before "local variables:" in its line.
+ (let ((suffix
+ (concat
+ (regexp-quote (buffer-substring (point)
+ (line-end-position)))
+ "$"))
+ (prefix
+ (concat "^" (regexp-quote
+ (buffer-substring (line-beginning-position)
+ (match-beginning 0)))))
+ beg)
+
+ (forward-line 1)
+ (let ((startpos (point))
+ endpos
+ (thisbuf (current-buffer)))
+ (save-excursion
+ (unless (let ((case-fold-search t))
+ (re-search-forward
+ (concat prefix "[ \t]*End:[ \t]*" suffix)
+ nil t))
+ (error "Local variables list is not properly terminated"))
+ (beginning-of-line)
+ (setq endpos (point)))
+
+ (with-temp-buffer
+ (insert-buffer-substring thisbuf startpos endpos)
+ (goto-char (point-min))
+ (subst-char-in-region (point) (point-max) ?\^m ?\n)
+ (while (not (eobp))
+ ;; Discard the prefix.
+ (if (looking-at prefix)
+ (delete-region (point) (match-end 0))
+ (error "Local variables entry is missing the prefix"))
+ (end-of-line)
+ ;; Discard the suffix.
+ (if (looking-back suffix)
+ (delete-region (match-beginning 0) (point))
+ (error "Local variables entry is missing the suffix"))
+ (forward-line 1))
+ (goto-char (point-min))
+
+ (while (not (eobp))
+ ;; Find the variable name; strip whitespace.
+ (skip-chars-forward " \t")
+ (setq beg (point))
+ (skip-chars-forward "^:\n")
+ (if (eolp) (error "Missing colon in local variables entry"))
+ (skip-chars-backward " \t")
+ (let* ((str (buffer-substring beg (point)))
+ (var (read str))
+ val)
+ ;; Read the variable value.
+ (skip-chars-forward "^:")
+ (forward-char 1)
+ (setq val (read (current-buffer)))
+ (if mode-only
+ (if (eq var 'mode)
+ (setq result t))
+ (unless (eq var 'coding)
+ (condition-case nil
+ (push (cons (if (eq var 'eval)
+ 'eval
+ (indirect-variable var))
+ val) result)
+ (error nil)))))
+ (forward-line 1)))))))
+
+ ;; We've read all the local variables. Now, return whether the
+ ;; mode is specified (if MODE-ONLY is non-nil), or set the
+ ;; variables (if MODE-ONLY is nil.)
+ (if mode-only
+ result
+ (dolist (ignored ignored-local-variables)
+ (setq result (assq-delete-all ignored result)))
+ (if (null enable-local-eval)
+ (setq result (assq-delete-all 'eval result)))
+ (when result
+ (setq result (nreverse result))
+ ;; Find those variables that we may want to save to
+ ;; `safe-local-variable-values'.
+ (let (risky-vars unsafe-vars)
+ (dolist (elt result)
+ (let ((var (car elt))
+ (val (cdr elt)))
+ (or (eq var 'mode)
+ (and (eq var 'eval)
+ (or (eq enable-local-eval t)
+ (hack-one-local-variable-eval-safep
+ (eval (quote val)))))
+ (safe-local-variable-p var val)
+ (and (risky-local-variable-p var val)
+ (push elt risky-vars))
+ (push elt unsafe-vars))))
+ (if (eq enable-local-variables :safe)
+ ;; If caller wants only the safe variables,
+ ;; install only them.
+ (dolist (elt result)
+ (unless (or (memq (car elt) unsafe-vars)
+ (memq (car elt) risky-vars))
+ (hack-one-local-variable (car elt) (cdr elt))))
+ ;; Query, except in the case where all are known safe
+ ;; if the user wants no quuery in that case.
+ (if (or (and (eq enable-local-variables t)
+ (null unsafe-vars)
+ (null risky-vars))
+ (eq enable-local-variables :all)
+ (hack-local-variables-confirm
+ result unsafe-vars risky-vars))
+ (dolist (elt result)
+ (hack-one-local-variable (car elt) (cdr elt))))))
+ (run-hooks 'hack-local-variables-hook))))))
+
+(defun safe-local-variable-p (sym val)
+ "Non-nil if SYM is safe as a file-local variable with value VAL.
+It is safe if any of these conditions are met:
+
+ * There is a matching entry (SYM . VAL) in the
+ `safe-local-variable-values' user option.
+
+ * The `safe-local-variable' property of SYM is a function that
+ evaluates to a non-nil value with VAL as an argument."
+ (or (member (cons sym val) safe-local-variable-values)
+ (let ((safep (get sym 'safe-local-variable)))
+ (and (functionp safep) (funcall safep val)))))
+
+(defun risky-local-variable-p (sym &optional ignored)
+ "Non-nil if SYM could be dangerous as a file-local variable.
+It is dangerous if either of these conditions are met:
+
+ * Its `risky-local-variable' property is non-nil.
+
+ * Its name ends with \"hook(s)\", \"function(s)\", \"form(s)\", \"map\",
+ \"program\", \"command(s)\", \"predicate(s)\", \"frame-alist\",
+ \"mode-alist\", \"font-lock-(syntactic-)keyword*\", or
+ \"map-alist\"."
;; If this is an alias, check the base name.
(condition-case nil
(setq sym (indirect-variable sym))
(error nil))
- (let ((safep (get sym 'safe-local-variable)))
- (or (get sym 'risky-local-variable)
- (and (string-match "-hooks?$\\|-functions?$\\|-forms?$\\|-program$\\|-commands?$\\|-predicates?$\\|font-lock-keywords$\\|font-lock-keywords-[0-9]+$\\|font-lock-syntactic-keywords$\\|-frame-alist$\\|-mode-alist$\\|-map$\\|-map-alist$"
- (symbol-name sym))
- (not safep))
- ;; If the safe-local-variable property isn't t or nil,
- ;; then it must return non-nil on the proposed value to be safe.
- (and (not (memq safep '(t nil)))
- (or (null val)
- (not (funcall safep val)))))))
-
-(defcustom safe-local-eval-forms nil
- "*Expressions that are considered \"safe\" in an `eval:' local variable.
-Add expressions to this list if you want Emacs to evaluate them, when
-they appear in an `eval' local variable specification, without first
-asking you for confirmation."
- :group 'find-file
- :version "22.1"
- :type '(repeat sexp))
-
-(put 'c-set-style 'safe-local-eval-function t)
+ (or (get sym 'risky-local-variable)
+ (string-match "-hooks?$\\|-functions?$\\|-forms?$\\|-program$\\|\
+-commands?$\\|-predicates?$\\|font-lock-keywords$\\|font-lock-keywords\
+-[0-9]+$\\|font-lock-syntactic-keywords$\\|-frame-alist$\\|-mode-alist$\\|\
+-map$\\|-map-alist$" (symbol-name sym))))
(defun hack-one-local-variable-quotep (exp)
(and (consp exp) (eq (car exp) 'quote) (consp (cdr exp))))
(and (eq (car exp) 'put)
(hack-one-local-variable-quotep (nth 1 exp))
(hack-one-local-variable-quotep (nth 2 exp))
- (memq (nth 1 (nth 2 exp))
- '(lisp-indent-hook))
- ;; Only allow safe values of lisp-indent-hook;
- ;; not functions.
- (or (numberp (nth 3 exp))
- (equal (nth 3 exp) ''defun)))
+ (let ((prop (nth 1 (nth 2 exp))) (val (nth 3 exp)))
+ (cond ((eq prop 'lisp-indent-hook)
+ ;; Only allow safe values of lisp-indent-hook;
+ ;; not functions.
+ (or (numberp val) (equal val ''defun)))
+ ((eq prop 'edebug-form-spec)
+ ;; Only allow indirect form specs.
+ (edebug-basic-spec val)))))
;; Allow expressions that the user requested.
(member exp safe-local-eval-forms)
;; Certain functions can be allowed with safe arguments
ok)))))))
(defun hack-one-local-variable (var val)
- "\"Set\" one variable in a local variables spec.
-A few patterns are specified so that any name which matches one
-is considered risky."
+ "Set local variable VAR with value VAL."
(cond ((eq var 'mode)
(funcall (intern (concat (downcase (symbol-name val))
"-mode"))))
- ((eq var 'coding)
- ;; We have already handled coding: tag in set-auto-coding.
- nil)
- ((memq var ignored-local-variables)
- nil)
- ;; "Setting" eval means either eval it or do nothing.
- ;; Likewise for setting hook variables.
- ((risky-local-variable-p var val)
- ;; Permit evalling a put of a harmless property.
- ;; if the args do nothing tricky.
- (if (or (and (eq var 'eval)
- (hack-one-local-variable-eval-safep val))
- ;; Permit eval if not root and user says ok.
- (and (not (zerop (user-uid)))
- (hack-local-variables-confirm
- "Process `eval' or hook local variables in %s? "
- enable-local-eval)))
- (if (eq var 'eval)
- (save-excursion (eval val))
- (make-local-variable var)
- (set var val))
- (message "Ignoring risky spec in the local variables list")))
- ;; Ordinary variable, really set it.
+ ((eq var 'eval)
+ (save-excursion (eval val)))
(t (make-local-variable var)
;; Make sure the string has no text properties.
;; Some text properties can get evaluated in various ways,
(?d diff-buffer-with-file
"view changes in file"))
"ACTION-ALIST argument used in call to `map-y-or-n-p'.")
-(put 'save-some-buffers-action-alist 'risky-local-variable t)
(defvar buffer-save-without-query nil
"Non-nil means `save-some-buffers' should save this buffer without asking.")
to nil.
Optional second argument NOCONFIRM means don't ask for confirmation at
-all. (The local variable `revert-without-query', if non-nil, prevents
-confirmation.)
+all. \(The variable `revert-without-query' offers another way to
+revert buffers without querying for confirmation.)
Optional third argument PRESERVE-MODES non-nil means don't alter
the files modes. Normally we reinitialize them using `normal-mode'.
(error "Buffer does not seem to be associated with any file"))
((or noconfirm
(and (not (buffer-modified-p))
- (let ((tail revert-without-query)
- (found nil))
- (while tail
- (if (string-match (car tail) file-name)
- (setq found t))
- (setq tail (cdr tail)))
- found))
+ (catch 'found
+ (dolist (regexp revert-without-query)
+ (when (string-match regexp file-name)
+ (throw 'found t)))))
(yes-or-no-p (format "Revert buffer from file %s? "
file-name)))
(run-hooks 'before-revert-hook)
(and (not auto-save-p)
(not (verify-visited-file-modtime (current-buffer)))
(setq buffer-backed-up nil))
- ;; Get rid of all undo records for this buffer.
- (or (eq buffer-undo-list t)
- (setq buffer-undo-list nil))
;; Effectively copy the after-revert-hook status,
;; since after-find-file will clobber it.
(let ((global-hook (default-value 'after-revert-hook))
- (local-hook-p (local-variable-p 'after-revert-hook))
- (local-hook (and (local-variable-p 'after-revert-hook)
- after-revert-hook)))
- (let (buffer-read-only
- ;; Don't make undo records for the reversion.
- (buffer-undo-list t))
- (if revert-buffer-insert-file-contents-function
- (funcall revert-buffer-insert-file-contents-function
- file-name auto-save-p)
- (if (not (file-exists-p file-name))
- (error (if buffer-file-number
- "File %s no longer exists!"
- "Cannot revert nonexistent file %s")
- file-name))
- ;; Bind buffer-file-name to nil
- ;; so that we don't try to lock the file.
- (let ((buffer-file-name nil))
- (or auto-save-p
- (unlock-buffer)))
- (widen)
- (let ((coding-system-for-read
- ;; Auto-saved file shoule be read by Emacs'
- ;; internal coding.
- (if auto-save-p 'auto-save-coding
- (or coding-system-for-read
- buffer-file-coding-system-explicit))))
- ;; This force after-insert-file-set-coding
- ;; (called from insert-file-contents) to set
- ;; buffer-file-coding-system to a proper value.
- (kill-local-variable 'buffer-file-coding-system)
-
- ;; Note that this preserves point in an intelligent way.
- (if preserve-modes
- (let ((buffer-file-format buffer-file-format))
- (insert-file-contents file-name (not auto-save-p)
- nil nil t))
- (insert-file-contents file-name (not auto-save-p)
- nil nil t)))))
+ (local-hook (when (local-variable-p 'after-revert-hook)
+ after-revert-hook))
+ (inhibit-read-only t))
+ (cond
+ (revert-buffer-insert-file-contents-function
+ (unless (eq buffer-undo-list t)
+ ;; Get rid of all undo records for this buffer.
+ (setq buffer-undo-list nil))
+ ;; Don't make undo records for the reversion.
+ (let ((buffer-undo-list t))
+ (funcall revert-buffer-insert-file-contents-function
+ file-name auto-save-p)))
+ ((not (file-exists-p file-name))
+ (error (if buffer-file-number
+ "File %s no longer exists!"
+ "Cannot revert nonexistent file %s")
+ file-name))
+ (t
+ ;; Bind buffer-file-name to nil
+ ;; so that we don't try to lock the file.
+ (let ((buffer-file-name nil))
+ (or auto-save-p
+ (unlock-buffer)))
+ (widen)
+ (let ((coding-system-for-read
+ ;; Auto-saved file should be read by Emacs'
+ ;; internal coding.
+ (if auto-save-p 'auto-save-coding
+ (or coding-system-for-read
+ buffer-file-coding-system-explicit))))
+ ;; This force after-insert-file-set-coding
+ ;; (called from insert-file-contents) to set
+ ;; buffer-file-coding-system to a proper value.
+ (kill-local-variable 'buffer-file-coding-system)
+
+ ;; Note that this preserves point in an intelligent way.
+ (if preserve-modes
+ (let ((buffer-file-format buffer-file-format))
+ (insert-file-contents file-name (not auto-save-p)
+ nil nil t))
+ (insert-file-contents file-name (not auto-save-p)
+ nil nil t)))))
;; Recompute the truename in case changes in symlinks
;; have changed the truename.
(setq buffer-file-truename
(after-find-file nil nil t t preserve-modes)
;; Run after-revert-hook as it was before we reverted.
(setq-default revert-buffer-internal-hook global-hook)
- (if local-hook-p
+ (if local-hook
(set (make-local-variable 'revert-buffer-internal-hook)
local-hook)
(kill-local-variable 'revert-buffer-internal-hook))
(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)
+ (let ((inhibit-read-only t)
;; Keep the current buffer-file-coding-system.
(coding-system buffer-file-coding-system)
;; Auto-saved file shoule be read with special coding.
(define-key ctl-x-5-map "f" 'find-file-other-frame)
(define-key ctl-x-5-map "\C-f" 'find-file-other-frame)
(define-key ctl-x-5-map "r" 'find-file-read-only-other-frame)
+(define-key ctl-x-5-map "\C-o" 'display-buffer-other-frame)
;; arch-tag: bc68d3ea-19ca-468b-aac6-3a4a7766101f
;;; files.el ends here