+\f
+;;; Handling file local variables
+
+(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)))))))