* hl-line.el (hl-line): New face.
[bpt/emacs.git] / lisp / progmodes / cc-mode.el
index eaa7982..eb5ae4b 100644 (file)
@@ -1,6 +1,7 @@
 ;;; cc-mode.el --- major mode for editing C and similar languages
 
-;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc.
+;; Copyright (C) 1985,1987,1992-2003, 2004, 2005, 2006 Free Software
+;; Foundation, Inc.
 
 ;; Authors:    2003- Alan Mackenzie
 ;;             1998- Martin Stjernholm
@@ -24,9 +25,9 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with this program; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
 (cc-require 'cc-align)
 (cc-require 'cc-menus)
 
-;; SILENCE the compiler.
-(cc-bytecomp-defvar comment-line-break-function) ; (X)Emacs 20+
-(cc-bytecomp-defvar adaptive-fill-first-line-regexp) ; Emacs 20+
+;; Silence the compiler.
+(cc-bytecomp-defvar adaptive-fill-first-line-regexp) ; Emacs
 (cc-bytecomp-defun set-keymap-parents) ; XEmacs
+(cc-bytecomp-defun run-mode-hooks)     ; Emacs 21.1
+(cc-bytecomp-obsolete-fun make-local-hook) ; Marked obsolete in Emacs 21.1.
 
 ;; We set these variables during mode init, yet we don't require
 ;; font-lock.
 ;; with your version of Emacs, you are incompatible!
 (cc-external-require 'easymenu)
 
+;; Autoload directive for emacsen that doesn't have an older CC Mode
+;; version in the dist.
+(autoload 'c-subword-mode "cc-subword"
+  "Mode enabling subword movement and editing keys." t)
+
 ;; Load cc-fonts first after font-lock is loaded, since it isn't
 ;; necessary until font locking is requested.
-(eval-after-load "font-lock"
-  '(require 'cc-fonts))
+; (eval-after-load "font-lock" ; 2006-07-09: font-lock is now preloaded.
+;   '
+(require 'cc-fonts) ;)
 
 ;; cc-langs isn't loaded when we're byte compiled, so add autoload
 ;; directives for the interface functions.
 (defun c-leave-cc-mode-mode ()
   (setq c-buffer-is-cc-mode nil))
 
+;; Make the `c-lang-setvar' variables buffer local in the current buffer.
+;; These are typically standard emacs variables such as `comment-start'.
+(defmacro c-make-emacs-variables-local ()
+  `(progn
+     ,@(mapcan (lambda (init)
+                `((make-local-variable ',(car init))))
+              (cdr c-emacs-variable-inits))))
+
 (defun c-init-language-vars-for (mode)
   "Initialize the language variables for one of the language modes
 directly supported by CC Mode.  This can be used instead of the
 `c-init-language-vars' macro if the language you want to use is one of
 those, rather than a derived language defined through the language
 variable system (see \"cc-langs.el\")."
-  ;; This function does not do any hidden buffer changes.
+  (c-make-emacs-variables-local)
   (cond ((eq mode 'c-mode)    (c-init-language-vars c-mode))
        ((eq mode 'c++-mode)  (c-init-language-vars c++-mode))
        ((eq mode 'objc-mode) (c-init-language-vars objc-mode))
@@ -169,8 +185,6 @@ initialization to run CC Mode for the C language is done.  Otherwise
 only some basic setup is done, and a call to `c-init-language-vars' or
 `c-init-language-vars-for' is necessary too (which gives more
 control).  See \"cc-mode.el\" for more info."
-  ;;
-  ;; This function does not do any hidden buffer changes.
 
   (setq c-buffer-is-cc-mode t)
 
@@ -201,12 +215,15 @@ control).  See \"cc-mode.el\" for more info."
 
 (defun c-make-inherited-keymap ()
   (let ((map (make-sparse-keymap)))
+    ;; Necessary to use `cc-bytecomp-fboundp' below since this
+    ;; function is called from top-level forms that are evaluated
+    ;; while cc-bytecomp is active when one does M-x eval-buffer.
     (cond
      ;; XEmacs
-     ((fboundp 'set-keymap-parents)
+     ((cc-bytecomp-fboundp 'set-keymap-parents)
       (set-keymap-parents map c-mode-base-map))
      ;; Emacs
-     ((fboundp 'set-keymap-parent)
+     ((cc-bytecomp-fboundp 'set-keymap-parent)
       (set-keymap-parent map c-mode-base-map))
      ;; incompatible
      (t (error "CC Mode is incompatible with this version of Emacs")))
@@ -215,7 +232,7 @@ control).  See \"cc-mode.el\" for more info."
 (defun c-define-abbrev-table (name defs)
   ;; Compatibility wrapper for `define-abbrev' which passes a non-nil
   ;; sixth argument for SYSTEM-FLAG in emacsen that support it
-  ;; (currently only Emacs 21.2).
+  ;; (currently only Emacs >= 21.2).
   (let ((table (or (symbol-value name)
                   (progn (define-abbrev-table name nil)
                          (symbol-value name)))))
@@ -227,20 +244,25 @@ control).  See \"cc-mode.el\" for more info."
       (setq defs (cdr defs)))))
 (put 'c-define-abbrev-table 'lisp-indent-function 1)
 
+(defun c-bind-special-erase-keys ()
+  ;; Only used in Emacs to bind C-c C-<delete> and C-c C-<backspace>
+  ;; to the proper keys depending on `normal-erase-is-backspace'.
+  (if normal-erase-is-backspace
+      (progn
+       (define-key c-mode-base-map (kbd "C-c C-<delete>")
+         'c-hungry-delete-forward)
+       (define-key c-mode-base-map (kbd "C-c C-<backspace>")
+         'c-hungry-delete-backwards))
+    (define-key c-mode-base-map (kbd "C-c C-<delete>")
+      'c-hungry-delete-backwards)
+    (define-key c-mode-base-map (kbd "C-c C-<backspace>")
+      'c-hungry-delete-forward)))
+
 (if c-mode-base-map
     nil
-  ;; TBD: should we even worry about naming this keymap. My vote: no,
-  ;; because Emacs and XEmacs do it differently.
+
   (setq c-mode-base-map (make-sparse-keymap))
-  ;; put standard keybindings into MAP
-  ;; the following mappings correspond more or less directly to BOCM
-  (define-key c-mode-base-map "{"         'c-electric-brace)
-  (define-key c-mode-base-map "}"         'c-electric-brace)
-  (define-key c-mode-base-map ";"         'c-electric-semi&comma)
-  (define-key c-mode-base-map "#"         'c-electric-pound)
-  (define-key c-mode-base-map ":"         'c-electric-colon)
-  (define-key c-mode-base-map "("         'c-electric-paren)
-  (define-key c-mode-base-map ")"         'c-electric-paren)
+
   ;; Separate M-BS from C-M-h.  The former should remain
   ;; backward-kill-word.
   (define-key c-mode-base-map [(control meta h)] 'c-mark-function)
@@ -254,21 +276,23 @@ control).  See \"cc-mode.el\" for more info."
   (substitute-key-definition 'indent-new-comment-line
                             'c-indent-new-comment-line
                             c-mode-base-map global-map)
+  (substitute-key-definition 'indent-for-tab-command
+                            'c-indent-command
+                            c-mode-base-map global-map)
   (when (fboundp 'comment-indent-new-line)
     ;; indent-new-comment-line has changed name to
     ;; comment-indent-new-line in Emacs 21.
     (substitute-key-definition 'comment-indent-new-line
                               'c-indent-new-comment-line
                               c-mode-base-map global-map))
+
   ;; RMS says don't make these the default.
 ;;  (define-key c-mode-base-map "\e\C-a"    'c-beginning-of-defun)
 ;;  (define-key c-mode-base-map "\e\C-e"    'c-end-of-defun)
+
   (define-key c-mode-base-map "\C-c\C-n"  'c-forward-conditional)
   (define-key c-mode-base-map "\C-c\C-p"  'c-backward-conditional)
   (define-key c-mode-base-map "\C-c\C-u"  'c-up-conditional)
-  (substitute-key-definition 'indent-for-tab-command
-                            'c-indent-command
-                            c-mode-base-map global-map)
 
   ;; It doesn't suffice to put `c-fill-paragraph' on
   ;; `fill-paragraph-function' since `c-fill-paragraph' must be called
@@ -285,34 +309,77 @@ control).  See \"cc-mode.el\" for more info."
   (substitute-key-definition 'fill-paragraph-or-region 'c-fill-paragraph
                             c-mode-base-map global-map)
 
+  ;; We bind the forward deletion key and (implicitly) C-d to
+  ;; `c-electric-delete-forward', and the backward deletion key to
+  ;; `c-electric-backspace'.  The hungry variants are bound to the
+  ;; same keys but prefixed with C-c.  This implies that C-c C-d is
+  ;; `c-hungry-delete-forward'.  For consistency, we bind not only C-c
+  ;; <backspace> to `c-hungry-delete-backwards' but also
+  ;; C-c C-<backspace>, so that the Ctrl key can be held down during
+  ;; the whole sequence regardless of the direction.  This in turn
+  ;; implies that we bind C-c C-<delete> to `c-hungry-delete-forward',
+  ;; for the same reason.
+
   ;; Bind the electric deletion functions to C-d and DEL.  Emacs 21
   ;; automatically maps the [delete] and [backspace] keys to these two
   ;; depending on window system and user preferences.  (In earlier
   ;; versions it's possible to do the same by using `function-key-map'.)
   (define-key c-mode-base-map "\C-d" 'c-electric-delete-forward)
   (define-key c-mode-base-map "\177" 'c-electric-backspace)
-  (when (boundp 'delete-key-deletes-forward)
-    ;; In XEmacs 20 and later we fix the forward and backward deletion
-    ;; behavior by binding the keysyms for the [delete] and
-    ;; [backspace] keys directly, and use `delete-forward-p' or
-    ;; `delete-key-deletes-forward' to decide what [delete] should do.
+  (define-key c-mode-base-map "\C-c\C-d"     'c-hungry-delete-forward)
+  (define-key c-mode-base-map [?\C-c ?\d]    'c-hungry-delete-backwards)
+  (define-key c-mode-base-map [?\C-c ?\C-\d] 'c-hungry-delete-backwards)
+  (define-key c-mode-base-map [?\C-c deletechar] 'c-hungry-delete-forward) ; C-c <delete> on a tty.
+  (define-key c-mode-base-map [?\C-c (control deletechar)] ; C-c C-<delete> on a tty.
+    'c-hungry-delete-forward)
+  (when (boundp 'normal-erase-is-backspace)
+    ;; The automatic C-d and DEL mapping functionality doesn't extend
+    ;; to special combinations like C-c C-<delete>, so we have to hook
+    ;; into the `normal-erase-is-backspace' system to bind it directly
+    ;; as appropriate.
+    (add-hook 'normal-erase-is-backspace-hook 'c-bind-special-erase-keys)
+    (c-bind-special-erase-keys))
+
+  (when (fboundp 'delete-forward-p)
+    ;; In XEmacs we fix the forward and backward deletion behavior by
+    ;; binding the keysyms for the [delete] and [backspace] keys
+    ;; directly, and use `delete-forward-p' to decide what [delete]
+    ;; should do.  That's done in the XEmacs specific
+    ;; `c-electric-delete' and `c-hungry-delete' functions.
     (define-key c-mode-base-map [delete]    'c-electric-delete)
-    (define-key c-mode-base-map [backspace] 'c-electric-backspace))
-  (define-key c-mode-base-map ","         'c-electric-semi&comma)
-  (define-key c-mode-base-map "*"         'c-electric-star)
+    (define-key c-mode-base-map [backspace] 'c-electric-backspace)
+    (define-key c-mode-base-map (kbd "C-c <delete>") 'c-hungry-delete)
+    (define-key c-mode-base-map (kbd "C-c C-<delete>") 'c-hungry-delete)
+    (define-key c-mode-base-map (kbd "C-c <backspace>")
+      'c-hungry-delete-backwards)
+    (define-key c-mode-base-map (kbd "C-c C-<backspace>")
+      'c-hungry-delete-backwards))
+
+  (define-key c-mode-base-map "#"         'c-electric-pound)
+  (define-key c-mode-base-map "{"         'c-electric-brace)
+  (define-key c-mode-base-map "}"         'c-electric-brace)
   (define-key c-mode-base-map "/"         'c-electric-slash)
-  (define-key c-mode-base-map "\C-c\C-q"  'c-indent-defun)
+  (define-key c-mode-base-map "*"         'c-electric-star)
+  (define-key c-mode-base-map ";"         'c-electric-semi&comma)
+  (define-key c-mode-base-map ","         'c-electric-semi&comma)
+  (define-key c-mode-base-map ":"         'c-electric-colon)
+  (define-key c-mode-base-map "("         'c-electric-paren)
+  (define-key c-mode-base-map ")"         'c-electric-paren)
+
   (define-key c-mode-base-map "\C-c\C-\\" 'c-backslash-region)
-  (define-key c-mode-base-map "\C-c\C-a"  'c-toggle-auto-state)
+  (define-key c-mode-base-map "\C-c\C-a"  'c-toggle-auto-newline)
   (define-key c-mode-base-map "\C-c\C-b"  'c-submit-bug-report)
   (define-key c-mode-base-map "\C-c\C-c"  'comment-region)
-  (define-key c-mode-base-map "\C-c\C-d"  'c-toggle-hungry-state)
+  (define-key c-mode-base-map "\C-c\C-l"  'c-toggle-electric-state)
   (define-key c-mode-base-map "\C-c\C-o"  'c-set-offset)
+  (define-key c-mode-base-map "\C-c\C-q"  'c-indent-defun)
   (define-key c-mode-base-map "\C-c\C-s"  'c-show-syntactic-information)
-  (define-key c-mode-base-map "\C-c\C-t"  'c-toggle-auto-hungry-state)
+  ;; (define-key c-mode-base-map "\C-c\C-t"  'c-toggle-auto-hungry-state)  Commented out by ACM, 2005-03-05.
   (define-key c-mode-base-map "\C-c."     'c-set-style)
   ;; conflicts with OOBR
   ;;(define-key c-mode-base-map "\C-c\C-v"  'c-version)
+  ;; (define-key c-mode-base-map "\C-c\C-y"  'c-toggle-hungry-state)  Commented out by ACM, 2005-11-22.
+  (define-key c-mode-base-map "\C-c\C-w" 'c-subword-mode)
   )
 
 ;; We don't require the outline package, but we configure it a bit anyway.
@@ -336,32 +403,48 @@ preferably use the `c-mode-menu' language constant directly."
     (let ((f (symbol-function 'c-populate-syntax-table)))
       (if (byte-code-function-p f) f (byte-compile f)))))
 
+;; CAUTION: Try to avoid installing things on
+;; `before-change-functions'.  The macro `combine-after-change-calls'
+;; is used and it doesn't work if there are things on that hook.  That
+;; can cause font lock functions to run in inconvenient places during
+;; temporary changes in some font lock support modes, causing extra
+;; unnecessary work and font lock glitches due to interactions between
+;; various text properties.
+
 (defun c-after-change (beg end len)
-  ;; Function put on `after-change-functions' to adjust various
-  ;; caches.  Prefer speed to finesse here, since there will be an
-  ;; order of magnitude more calls to this function than any of the
+  ;; Function put on `after-change-functions' to adjust various caches
+  ;; etc.  Prefer speed to finesse here, since there will be an order
+  ;; of magnitude more calls to this function than any of the
   ;; functions that use the caches.
   ;;
   ;; Note that care must be taken so that this is called before any
   ;; font-lock callbacks since we might get calls to functions using
   ;; these caches from inside them, and we must thus be sure that this
   ;; has already been executed.
-  ;;
-  ;; This function does not do any hidden buffer changes.
 
   (c-save-buffer-state ()
-    (when (> end (point-max))
-      ;; Some emacsen might return positions past the end. This has been
-      ;; observed in Emacs 20.7 when rereading a buffer changed on disk
-      ;; (haven't been able to minimize it, but Emacs 21.3 appears to
-      ;; work).
-      (setq end (point-max))
-      (when (> beg end)
-       (setq beg end)))
-
-    (c-invalidate-sws-region-after beg end)
-    (c-invalidate-state-cache beg)
-    (c-invalidate-find-decl-cache beg)))
+    ;; When `combine-after-change-calls' is used we might get calls
+    ;; with regions outside the current narrowing.  This has been
+    ;; observed in Emacs 20.7.
+    (save-restriction
+      (save-match-data           ; c-recognize-<>-arglists changes match-data
+       (widen)
+
+       (when (> end (point-max))
+         ;; Some emacsen might return positions past the end. This has been
+         ;; observed in Emacs 20.7 when rereading a buffer changed on disk
+         ;; (haven't been able to minimize it, but Emacs 21.3 appears to
+         ;; work).
+         (setq end (point-max))
+         (when (> beg end)
+           (setq beg end)))
+
+       (c-invalidate-sws-region-after beg end)
+       (c-invalidate-state-cache beg)
+       (c-invalidate-find-decl-cache beg)
+
+       (when c-recognize-<>-arglists
+         (c-after-change-check-<>-operators beg end))))))
 
 (defun c-basic-common-init (mode default-style)
   "Do the necessary initialization for the syntax handling routines
@@ -375,8 +458,6 @@ same format as `c-default-style'.
 Note that `c-init-language-vars' must be called before this function.
 This function cannot do that since `c-init-language-vars' is a macro
 that requires a literal mode spec at compile time."
-  ;;
-  ;; This function does not do any hidden buffer changes.
 
   (setq c-buffer-is-cc-mode mode)
 
@@ -390,6 +471,7 @@ that requires a literal mode spec at compile time."
   (make-local-variable 'comment-end)
   (make-local-variable 'comment-start-skip)
   (make-local-variable 'comment-multi-line)
+  (make-local-variable 'comment-line-break-function)
   (make-local-variable 'paragraph-start)
   (make-local-variable 'paragraph-separate)
   (make-local-variable 'paragraph-ignore-fill-prefix)
@@ -401,7 +483,8 @@ that requires a literal mode spec at compile time."
        indent-line-function 'c-indent-line
        indent-region-function 'c-indent-region
        normal-auto-fill-function 'c-do-auto-fill
-       comment-multi-line t)
+       comment-multi-line t
+       comment-line-break-function 'c-indent-new-comment-line)
 
   ;; Install `c-fill-paragraph' on `fill-paragraph-function' so that a
   ;; direct call to `fill-paragraph' behaves better.  This still
@@ -409,21 +492,25 @@ that requires a literal mode spec at compile time."
   (make-local-variable 'fill-paragraph-function)
   (setq fill-paragraph-function 'c-fill-paragraph)
 
-  ;; (X)Emacs 20 and later.
-  (when (boundp 'comment-line-break-function)
-    (make-local-variable 'comment-line-break-function)
-    (setq comment-line-break-function
-         'c-indent-new-comment-line))
-
-  ;; Emacs 20 and later.
-  (when (boundp 'parse-sexp-lookup-properties)
-    (make-local-variable 'parse-sexp-lookup-properties)
-    (setq parse-sexp-lookup-properties t))
-
-  ;; Same as above for XEmacs 21 (although currently undocumented).
-  (when (boundp 'lookup-syntax-properties)
-    (make-local-variable 'lookup-syntax-properties)
-    (setq lookup-syntax-properties t))
+  (when (or c-recognize-<>-arglists
+           (c-major-mode-is 'awk-mode))
+    ;; We'll use the syntax-table text property to change the syntax
+    ;; of some chars for this language, so do the necessary setup for
+    ;; that.
+    ;;
+    ;; Note to other package developers: It's ok to turn this on in CC
+    ;; Mode buffers when CC Mode doesn't, but it's not ok to turn it
+    ;; off if CC Mode has turned it on.
+
+    ;; Emacs.
+    (when (boundp 'parse-sexp-lookup-properties)
+      (make-local-variable 'parse-sexp-lookup-properties)
+      (setq parse-sexp-lookup-properties t))
+
+    ;; Same as above for XEmacs.
+    (when (boundp 'lookup-syntax-properties)
+      (make-local-variable 'lookup-syntax-properties)
+      (setq lookup-syntax-properties t)))
 
   ;; Use this in Emacs 21 to avoid meddling with the rear-nonsticky
   ;; property on each character.
@@ -441,18 +528,12 @@ that requires a literal mode spec at compile time."
 
   ;; In Emacs 21 and later it's possible to turn off the ad-hoc
   ;; heuristic that open parens in column 0 are defun starters.  Since
-  ;; we have c-state-cache that isn't useful and only causes trouble
-  ;; so turn it off.
+  ;; we have c-state-cache, that heuristic isn't useful and only causes
+  ;; trouble, so turn it off.
   (when (memq 'col-0-paren c-emacs-features)
     (make-local-variable 'open-paren-in-column-0-is-defun-start)
     (setq open-paren-in-column-0-is-defun-start nil))
 
-  ;; The `c-type' text property with `c-decl-end' is used to mark the
-  ;; ends of access keys to make interactive refontification work
-  ;; better.
-  (when c-opt-access-key
-    (setq c-type-decl-end-used t))
-
   (c-clear-found-types)
 
   ;; now set the mode style based on default-style
@@ -483,14 +564,16 @@ that requires a literal mode spec at compile time."
   (make-local-variable 'comment-indent-function)
   (setq comment-indent-function 'c-comment-indent)
 
-  ;; put auto-hungry designators onto minor-mode-alist, but only once
-  (or (assq 'c-auto-hungry-string minor-mode-alist)
-      (setq minor-mode-alist
-           (cons '(c-auto-hungry-string c-auto-hungry-string)
-                 minor-mode-alist)))
+;;   ;; Put submode indicators onto minor-mode-alist, but only once.
+;;   (or (assq 'c-submode-indicators minor-mode-alist)
+;;       (setq minor-mode-alist
+;;         (cons '(c-submode-indicators c-submode-indicators)
+;;               minor-mode-alist)))
+  (c-update-modeline)
 
   ;; Install the functions that ensure that various internal caches
   ;; don't become invalid due to buffer changes.
+  (make-local-hook 'after-change-functions)
   (add-hook 'after-change-functions 'c-after-change nil t))
 
 (defun c-after-font-lock-init ()
@@ -505,7 +588,7 @@ This does not load the font-lock package.  Use after
 
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults
-       `(,(if (c-mode-is-new-awk-p)
+       `(,(if (c-major-mode-is 'awk-mode)
               ;; awk-mode currently has only one font lock level.
               'awk-font-lock-keywords
             (mapcar 'c-mode-symbol
@@ -514,8 +597,11 @@ This does not load the font-lock package.  Use after
          nil nil
          ,c-identifier-syntax-modifications
          c-beginning-of-syntax
+         (font-lock-lines-before . 1)
          (font-lock-mark-block-function
           . c-mark-function)))
+
+  (make-local-hook 'font-lock-mode-hook)
   (add-hook 'font-lock-mode-hook 'c-after-font-lock-init nil t))
 
 (defun c-setup-doc-comment-style ()
@@ -535,9 +621,7 @@ Mode to operate correctly.
 
 MODE is the symbol for the mode to initialize, like 'c-mode.  See
 `c-basic-common-init' for details.  It's only optional to be
-compatible with old code; callers should always specify it.
-
-This function does not do any hidden buffer changes."
+compatible with old code; callers should always specify it."
 
   (unless mode
     ;; Called from an old third party package.  The fallback is to
@@ -560,6 +644,51 @@ This function does not do any hidden buffer changes."
       (and (cdr rfn)
           (setq require-final-newline mode-require-final-newline)))))
 
+(defun c-remove-any-local-eval-or-mode-variables ()
+  ;; If the buffer specifies `mode' or `eval' in its File Local Variable list
+  ;; or on the first line, remove all occurrences.  See
+  ;; `c-postprocess-file-styles' for justification.  There is no need to save
+  ;; point here, or even bother too much about the buffer contents.
+  ;;
+  ;; Most of the code here is derived from Emacs 21.3's `hack-local-variables'
+  ;; in files.el.
+  (goto-char (point-max))
+  (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
+  (let (lv-point (prefix "") (suffix ""))
+    (when (let ((case-fold-search t))
+           (search-forward "Local Variables:" nil t))
+      (setq lv-point (point))
+      ;; The prefix is what comes before "local variables:" in its line.
+      ;; The suffix is what comes after "local variables:" in its line.
+      (skip-chars-forward " \t")
+      (or (eolp)
+         (setq suffix (buffer-substring (point)
+                                        (progn (end-of-line) (point)))))
+      (goto-char (match-beginning 0))
+      (or (bolp)
+         (setq prefix
+               (buffer-substring (point)
+                                 (progn (beginning-of-line) (point)))))
+
+      (while (search-forward-regexp
+             (concat "^[ \t]*"
+                     (regexp-quote prefix)
+                     "\\(mode\\|eval\\):.*"
+                     (regexp-quote suffix)
+                     "$")
+             nil t)
+       (beginning-of-line)
+       (kill-line 1)))
+
+    ;; Delete the first line, if we've got one, in case it contains a mode spec.
+    (unless (and lv-point
+                (progn (goto-char lv-point)
+                       (forward-line 0)
+                       (bobp)))
+      (goto-char (point-min))
+      (unless (eobp)
+       (kill-line 1)))))
+
 (defun c-postprocess-file-styles ()
   "Function that post processes relevant file local variables in CC Mode.
 Currently, this function simply applies any style and offset settings
@@ -568,8 +697,6 @@ setting found in `c-file-style', then it applies any offset settings
 it finds in `c-file-offsets'.
 
 Note that the style variables are always made local to the buffer."
-  ;;
-  ;; This function does not do any hidden buffer changes.
 
   ;; apply file styles and offsets
   (when c-buffer-is-cc-mode
@@ -583,10 +710,36 @@ Note that the style variables are always made local to the buffer."
            (let ((langelem (car langentry))
                  (offset (cdr langentry)))
              (c-set-offset langelem offset)))
-         c-file-offsets))))
+         c-file-offsets))
+    ;; Problem: The file local variable block might have explicitly set a
+    ;; style variable.  The `c-set-style' or `mapcar' call might have
+    ;; overwritten this.  So we run `hack-local-variables' again to remedy
+    ;; this.  There are no guarantees this will work properly, particularly as
+    ;; we have no control over what the other hook functions on
+    ;; `hack-local-variables-hook' would have done.  We now (2006/2/1) remove
+    ;; any `eval' or `mode' expressions before we evaluate again (see below).
+    ;; ACM, 2005/11/2.
+    ;;
+    ;; Problem (bug reported by Gustav Broberg): if one of the variables is
+    ;; `mode', this will invoke c-mode (etc.) again, setting up the style etc.
+    ;; We prevent this by temporarily removing `mode' from the Local Variables
+    ;; section.
+    (if (or c-file-style c-file-offsets)
+       (c-tentative-buffer-changes
+         (let ((hack-local-variables-hook nil))
+           (c-remove-any-local-eval-or-mode-variables)
+           (hack-local-variables))
+         nil))))
 
 (add-hook 'hack-local-variables-hook 'c-postprocess-file-styles)
 
+(defmacro c-run-mode-hooks (&rest hooks)
+  ;; Emacs 21.1 has introduced a system with delayed mode hooks that
+  ;; require the use of the new function `run-mode-hooks'.
+  (if (cc-bytecomp-fboundp 'run-mode-hooks)
+      `(run-mode-hooks ,@hooks)
+    `(progn ,@(mapcar (lambda (hook) `(run-hooks ,hook)) hooks))))
+
 \f
 ;; Support for C
 
@@ -667,7 +820,7 @@ Key bindings:
   (c-common-init 'c-mode)
   (easy-menu-add c-c-menu)
   (cc-imenu-init cc-imenu-c-generic-expression)
-  (run-mode-hooks 'c-mode-common-hook 'c-mode-hook)
+  (c-run-mode-hooks 'c-mode-common-hook 'c-mode-hook)
   (c-update-modeline))
 
 \f
@@ -730,7 +883,7 @@ Key bindings:
   (c-common-init 'c++-mode)
   (easy-menu-add c-c++-menu)
   (cc-imenu-init cc-imenu-c++-generic-expression)
-  (run-mode-hooks 'c-mode-common-hook 'c++-mode-hook)
+  (c-run-mode-hooks 'c-mode-common-hook 'c++-mode-hook)
   (c-update-modeline))
 
 \f
@@ -786,15 +939,12 @@ Key bindings:
        mode-name "ObjC"
        local-abbrev-table objc-mode-abbrev-table
        abbrev-mode t)
-  ;; The `c-type' text property with `c-decl-end' is used to mark the
-  ;; end of the @-style directives.
-  (setq c-type-decl-end-used t)
   (use-local-map objc-mode-map)
   (c-init-language-vars-for 'objc-mode)
   (c-common-init 'objc-mode)
   (easy-menu-add c-objc-menu)
   (cc-imenu-init nil 'cc-imenu-objc-function)
-  (run-mode-hooks 'c-mode-common-hook 'objc-mode-hook)
+  (c-run-mode-hooks 'c-mode-common-hook 'objc-mode-hook)
   (c-update-modeline))
 
 \f
@@ -864,7 +1014,7 @@ Key bindings:
   (c-common-init 'java-mode)
   (easy-menu-add c-java-menu)
   (cc-imenu-init cc-imenu-java-generic-expression)
-  (run-mode-hooks 'c-mode-common-hook 'java-mode-hook)
+  (c-run-mode-hooks 'c-mode-common-hook 'java-mode-hook)
   (c-update-modeline))
 
 \f
@@ -922,7 +1072,7 @@ Key bindings:
   (c-common-init 'idl-mode)
   (easy-menu-add c-idl-menu)
   ;;(cc-imenu-init cc-imenu-idl-generic-expression) ;TODO
-  (run-mode-hooks 'c-mode-common-hook 'idl-mode-hook)
+  (c-run-mode-hooks 'c-mode-common-hook 'idl-mode-hook)
   (c-update-modeline))
 
 \f
@@ -984,12 +1134,11 @@ Key bindings:
   (c-common-init 'pike-mode)
   (easy-menu-add c-pike-menu)
   ;;(cc-imenu-init cc-imenu-pike-generic-expression) ;TODO
-  (run-mode-hooks 'c-mode-common-hook 'pike-mode-hook)
+  (c-run-mode-hooks 'c-mode-common-hook 'pike-mode-hook)
   (c-update-modeline))
 
 \f
-;; Support for awk.  This is purposely disabled for older (X)Emacsen which
-;; don't support syntax-table properties.
+;; Support for AWK
 
 ;;;###autoload (add-to-list 'auto-mode-alist '("\\.awk\\'" . awk-mode))
 ;;;###autoload (add-to-list 'interpreter-mode-alist '("awk" . awk-mode))
@@ -1001,37 +1150,34 @@ Key bindings:
 ;;; autoload form instead.
 ;;;###autoload (autoload 'awk-mode "cc-mode" "Major mode for editing AWK code." t)
 
-(if (not (memq 'syntax-properties c-emacs-features))
-    (autoload 'awk-mode "awk-mode" "Major mode for editing AWK code."  t)
-
-  (defvar awk-mode-abbrev-table nil
-    "Abbreviation table used in awk-mode buffers.")
-  (c-define-abbrev-table 'awk-mode-abbrev-table
-    '(("else" "else" c-electric-continued-statement 0)
-      ("while" "while" c-electric-continued-statement 0)))
-
-  (defvar awk-mode-map ()
-    "Keymap used in awk-mode buffers.")
-  (if awk-mode-map
-      nil
-    (setq awk-mode-map (c-make-inherited-keymap))
-    ;; add bindings which are only useful for awk.
-    (define-key awk-mode-map "#" 'self-insert-command)
-    (define-key awk-mode-map "/" 'self-insert-command)
-    (define-key awk-mode-map "*" 'self-insert-command)
-    (define-key awk-mode-map "\C-c\C-n" 'undefined) ; #if doesn't exist in awk.
-    (define-key awk-mode-map "\C-c\C-p" 'undefined)
-    (define-key awk-mode-map "\C-c\C-u" 'undefined)
-    (define-key awk-mode-map "\M-a" 'undefined) ; c-awk-beginning-of-statement isn't yet implemented.
-    (define-key awk-mode-map "\M-e" 'undefined) ; c-awk-end-of-statement isn't yet implemented.
-    (define-key awk-mode-map "\C-\M-a" 'c-awk-beginning-of-defun)
-    (define-key awk-mode-map "\C-\M-e" 'c-awk-end-of-defun))
-
-  (easy-menu-define c-awk-menu awk-mode-map "AWK Mode Commands"
-    (cons "AWK" (c-lang-const c-mode-menu awk)))
-
-  (defun awk-mode ()
-    "Major mode for editing AWK code.
+(defvar awk-mode-abbrev-table nil
+  "Abbreviation table used in awk-mode buffers.")
+(c-define-abbrev-table 'awk-mode-abbrev-table
+  '(("else" "else" c-electric-continued-statement 0)
+    ("while" "while" c-electric-continued-statement 0)))
+
+(defvar awk-mode-map ()
+  "Keymap used in awk-mode buffers.")
+(if awk-mode-map
+    nil
+  (setq awk-mode-map (c-make-inherited-keymap))
+  ;; add bindings which are only useful for awk.
+  (define-key awk-mode-map "#" 'self-insert-command)
+  (define-key awk-mode-map "/" 'self-insert-command)
+  (define-key awk-mode-map "*" 'self-insert-command)
+  (define-key awk-mode-map "\C-c\C-n" 'undefined) ; #if doesn't exist in awk.
+  (define-key awk-mode-map "\C-c\C-p" 'undefined)
+  (define-key awk-mode-map "\C-c\C-u" 'undefined)
+  (define-key awk-mode-map "\M-a" 'c-beginning-of-statement) ; 2003/10/7
+  (define-key awk-mode-map "\M-e" 'c-end-of-statement) ; 2003/10/7
+  (define-key awk-mode-map "\C-\M-a" 'c-awk-beginning-of-defun)
+  (define-key awk-mode-map "\C-\M-e" 'c-awk-end-of-defun))
+
+(easy-menu-define c-awk-menu awk-mode-map "AWK Mode Commands"
+                 (cons "AWK" (c-lang-const c-mode-menu awk)))
+
+(defun awk-mode ()
+  "Major mode for editing AWK code.
 To submit a problem report, enter `\\[c-submit-bug-report]' from an
 awk-mode buffer.  This automatically sets up a mail buffer with version
 information already added.  You just need to add a description of the
@@ -1044,41 +1190,40 @@ initialization, then `awk-mode-hook'.
 
 Key bindings:
 \\{awk-mode-map}"
-    (interactive)
-    (require 'cc-awk)                   ; Added 2003/6/10.
-    (kill-all-local-variables)
-    (c-initialize-cc-mode t)
-    (set-syntax-table awk-mode-syntax-table)
-    (setq major-mode 'awk-mode
-          mode-name "AWK"
-          local-abbrev-table awk-mode-abbrev-table
-          abbrev-mode t)
-    (use-local-map awk-mode-map)
-    (c-init-language-vars-for 'awk-mode)
-    (c-common-init 'awk-mode)
-    ;; The rest of CC Mode does not (yet) use `font-lock-syntactic-keywords',
-    ;; so it's not set by `c-font-lock-init'.
-    (make-local-variable 'font-lock-syntactic-keywords)
-    (setq font-lock-syntactic-keywords
-          '((c-awk-set-syntax-table-properties
-             0 (0)                      ; Everything on this line is a dummy.
-             nil t)))
-    (c-awk-unstick-NL-prop)
-    (add-hook 'before-change-functions 'c-awk-before-change nil t)
-    (add-hook 'after-change-functions 'c-awk-after-change nil t)
-    (c-save-buffer-state nil
-      (save-restriction
-        (widen)
-        (c-awk-clear-NL-props (point-min) (point-max))
-        (c-awk-after-change (point-min) (point-max) 0))) ; Set syntax-table props.
-
-    ;; Prevent Xemacs's buffer-syntactic-context being used.  See the comment
-    ;; in cc-engine.el, just before (defun c-fast-in-literal ...
-    (defalias 'c-in-literal 'c-slow-in-literal)
-
-    (run-mode-hooks 'c-mode-common-hook 'awk-mode-hook)
-    (c-update-modeline))
-) ;; closes the (if (not (memq 'syntax-properties c-emacs-features))
+  (interactive)
+  (require 'cc-awk)                    ; Added 2003/6/10.
+  (kill-all-local-variables)
+  (c-initialize-cc-mode t)
+  (set-syntax-table awk-mode-syntax-table)
+  (setq major-mode 'awk-mode
+       mode-name "AWK"
+       local-abbrev-table awk-mode-abbrev-table
+       abbrev-mode t)
+  (use-local-map awk-mode-map)
+  (c-init-language-vars-for 'awk-mode)
+  (c-common-init 'awk-mode)
+  ;; The rest of CC Mode does not (yet) use `font-lock-syntactic-keywords',
+  ;; so it's not set by `c-font-lock-init'.
+  (make-local-variable 'font-lock-syntactic-keywords)
+  (setq font-lock-syntactic-keywords
+       '((c-awk-set-syntax-table-properties
+          0 (0)                        ; Everything on this line is a dummy.
+          nil t)))
+  (c-awk-unstick-NL-prop)
+  (add-hook 'before-change-functions 'c-awk-before-change nil t)
+  (add-hook 'after-change-functions 'c-awk-after-change nil t)
+  (c-save-buffer-state nil
+    (save-restriction
+      (widen)
+      (c-awk-clear-NL-props (point-min) (point-max))
+      (c-awk-after-change (point-min) (point-max) 0))) ; Set syntax-table props.
+
+  ;; Prevent Xemacs's buffer-syntactic-context being used.  See the comment
+  ;; in cc-engine.el, just before (defun c-fast-in-literal ...
+  (defalias 'c-in-literal 'c-slow-in-literal)
+
+  (c-run-mode-hooks 'c-mode-common-hook 'awk-mode-hook)
+  (c-update-modeline))
 
 \f
 ;; bug reporting