]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/c-mode.el
(easy-menu-define-key): Fixed bug with BEFORE
[gnu-emacs] / lisp / progmodes / c-mode.el
index e057a4a4ca44ac36938677b1f3c7f433364fd50e..ab9cf8dc9920281cb92fa68750f0b1b9ae310694 100644 (file)
@@ -1,5 +1,6 @@
 ;;; c-mode.el --- C code editing commands for Emacs
-;; Copyright (C) 1985, 1986, 1987, 1992, 1994 Free Software Foundation, Inc.
+
+;; Copyright (C) 1985, 86, 87, 92, 94, 95 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: c
 ;; 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; 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.
 
 ;;; Commentary:
 
 ;; A smart editing mode for C code.  It knows a lot about C syntax and tries
-;; to position the curser according to C layout conventions.  You can
+;; to position the cursor according to C layout conventions.  You can
 ;; change the details of the layout style with option variables.  Load it
 ;; and do M-x describe-mode for details.
 
 ;;; Code:
+(defgroup old-c nil
+  "Old C code editing commands for Emacs."
+  :prefix "c-"
+  :group 'languages)
+
 
 (defvar c-mode-abbrev-table nil
   "Abbrev table in use in C mode.")
@@ -45,7 +52,6 @@
 (define-key c-mode-map "\e\C-q" 'indent-c-exp)
 (define-key c-mode-map "\ea" 'c-beginning-of-statement)
 (define-key c-mode-map "\ee" 'c-end-of-statement)
-(define-key c-mode-map "\eq" 'c-fill-paragraph)
 (define-key c-mode-map "\C-c\C-n" 'c-forward-conditional)
 (define-key c-mode-map "\C-c\C-p" 'c-backward-conditional)
 (define-key c-mode-map "\C-c\C-u" 'c-up-conditional)
 
 (define-key c-mode-map [menu-bar] (make-sparse-keymap))
 
+;; "C-mode" is not strictly the right punctuation--it should be "C
+;; mode"--but that would look like two menu items.  "C-mode" is the
+;; best alternative I can think of.
 (define-key c-mode-map [menu-bar c]
-  (cons "C" (make-sparse-keymap "C")))
+  (cons "C-mode" (make-sparse-keymap "C-mode")))
 
 (define-key c-mode-map [menu-bar c comment-region]
   '("Comment Out Region" . comment-region))
@@ -69,6 +78,8 @@
   '("Indent Line" . c-indent-command))
 (define-key c-mode-map [menu-bar c fill]
   '("Fill Comment Paragraph" . c-fill-paragraph))
+(define-key c-mode-map [menu-bar c cpp-highlight-buffer]
+  '("Highlight Conditionals" . cpp-highlight-buffer))
 (define-key c-mode-map [menu-bar c up]
   '("Up Conditional" . c-up-conditional))
 (define-key c-mode-map [menu-bar c backward]
 (define-key c-mode-map [menu-bar c forward-stmt]
   '("Forward Statement" . c-end-of-statement))
 
+(put 'comment-region 'menu-enable 'mark-active)
+(put 'c-macro-expand 'menu-enable 'mark-active)
+(put 'c-backslash-region 'menu-enable 'mark-active)
+
 (autoload 'c-macro-expand "cmacexp"
   "Display the result of expanding all C macros occurring in the region.
 The expansion is entirely correct because it uses the C preprocessor."
@@ -104,68 +119,187 @@ The expansion is entirely correct because it uses the C preprocessor."
   (modify-syntax-entry ?| "." c-mode-syntax-table)
   (modify-syntax-entry ?\' "\"" c-mode-syntax-table))
 
-(defconst c-indent-level 2
-  "*Indentation of C statements with respect to containing block.")
-(defconst c-brace-imaginary-offset 0
-  "*Imagined indentation of a C open brace that actually follows a statement.")
-(defconst c-brace-offset 0
-  "*Extra indentation for braces, compared with other text in same context.")
-(defconst c-argdecl-indent 5
-  "*Indentation level of declarations of C function arguments.")
-(defconst c-label-offset -2
-  "*Offset of C label lines and case statements relative to usual indentation.")
-(defconst c-continued-statement-offset 2
-  "*Extra indent for lines not starting new statements.")
-(defconst c-continued-brace-offset 0
+(defcustom c-indent-level 2
+  "*Indentation of C statements with respect to containing block."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-brace-imaginary-offset 0
+  "*Imagined indentation of a C open brace that actually follows a statement."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-brace-offset 0
+  "*Extra indentation for braces, compared with other text in same context."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-argdecl-indent 5
+  "*Indentation level of declarations of C function arguments."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-label-offset -2
+  "*Offset of C label lines and case statements relative to usual indentation."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-continued-statement-offset 2
+  "*Extra indent for lines not starting new statements."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-continued-brace-offset 0
   "*Extra indent for substatements that start with open-braces.
-This is in addition to c-continued-statement-offset.")
+This is in addition to `c-continued-statement-offset'."
+  :type 'integer
+  :group 'old-c)
 (defconst c-style-alist
   '(("GNU"
      (c-indent-level               .  2)
      (c-argdecl-indent             .  5)
      (c-brace-offset               .  0)
+     (c-continued-brace-offset     .  0)
      (c-label-offset               . -2)
      (c-continued-statement-offset .  2))
     ("K&R"
      (c-indent-level               .  5)
      (c-argdecl-indent             .  0)
-     (c-brace-offset               . -5)
+     (c-brace-offset               .  0)
+     (c-continued-brace-offset     . -5)
      (c-label-offset               . -5)
      (c-continued-statement-offset .  5))
     ("BSD"
      (c-indent-level               .  4)
      (c-argdecl-indent             .  4)
-     (c-brace-offset               . -4)
+     (c-brace-offset               .  0)
+     (c-continued-brace-offset     . -4)
      (c-label-offset               . -4)
      (c-continued-statement-offset .  4))
     ("C++"
-     (c-indent-level               . 4)
-     (c-continued-statement-offset . 4)
-     (c-brace-offset               . -4)
-     (c-argdecl-indent             . 0)
+     (c-indent-level               .  4)
+     (c-argdecl-indent             .  0)
+     (c-brace-offset               .  0)
+     (c-continued-brace-offset     . -4)
      (c-label-offset               . -4)
-     (c-auto-newline               . t))
+     (c-continued-statement-offset .  4)
+     (c-auto-newline               .  t))
     ("Whitesmith"
      (c-indent-level               .  4)
      (c-argdecl-indent             .  4)
      (c-brace-offset               .  0)
+     (c-continued-brace-offset     .  0)
      (c-label-offset               . -4)
      (c-continued-statement-offset .  4))))
 
-(defconst c-auto-newline nil
+(defcustom c-auto-newline nil
   "*Non-nil means automatically newline before and after braces,
 and after colons and semicolons, inserted in C code.
 If you do not want a leading newline before braces then use:
-  (define-key c-mode-map \"{\" 'electric-c-semi)")
+  (define-key c-mode-map \"{\" 'electric-c-semi)"
+  :type 'boolean
+  :group 'old-c)
 
-(defconst c-tab-always-indent t
+(defcustom c-tab-always-indent t
   "*Non-nil means TAB in C mode should always reindent the current line,
-regardless of where in the line point is when the TAB command is used.")
+regardless of where in the line point is when the TAB command is used."
+  :type 'boolean
+  :group 'old-c)
 
 ;;; Regular expression used internally to recognize labels in switch
 ;;; statements.
-(defconst c-switch-label-regexp "case[ \t'/(]\\|default\\(\\S_\\|'\\)")
+(defconst c-switch-label-regexp "case[ \t'/(]\\|default[ \t]*:")
+
+;; This is actually the expression for C++ mode, but it's used for C too.
+(defvar c-imenu-generic-expression
+  (`
+   ((nil
+     (,
+      (concat
+       "^"                               ; beginning of line is required
+       "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"     ; type specs; there can be no
+       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"     ; more than 3 tokens, right?
+
+       "\\("                             ; last type spec including */&
+       "[a-zA-Z0-9_:]+"
+       "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)"        ; either pointer/ref sign or whitespace
+       "\\)?"                            ; if there is a last type spec
+       "\\("                         ; name; take that into the imenu entry
+       "[a-zA-Z0-9_:~]+"                     ; member function, ctor or dtor...
+                                       ; (may not contain * because then
+                                       ; "a::operator char*" would become "char*"!)
+       "\\|"
+       "\\([a-zA-Z0-9_:~]*::\\)?operator"
+       "[^a-zA-Z1-9_][^(]*"          ; ...or operator
+       " \\)"
+       "[ \t]*([^)]*)[ \t\n]*[^              ;]" ; require something other than a ; after
+                                       ; the (...) to avoid prototypes.  Can't
+                                       ; catch cases with () inside the parentheses
+                                       ; surrounding the parameters
+                                       ; (like "int foo(int a=bar()) {...}"
+
+       )) 6)
+    ("Class"
+     (, (concat
+        "^"                               ; beginning of line is required
+        "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+        "class[ \t]+"
+        "\\([a-zA-Z0-9_]+\\)"                ; this is the string we want to get
+        "[ \t]*[:{]"
+        )) 2)
+;; Example of generic expression for finding prototypes, structs, unions, enums.
+;; Uncomment if you want to find these too.  It will be a bit slower gathering
+;; the indexes.
+;    ("Prototypes"
+;     (,
+;      (concat
+;       "^"                              ; beginning of line is required
+;       "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+;       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"    ; type specs; there can be no
+;       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"    ; more than 3 tokens, right?
 
+;       "\\("                            ; last type spec including */&
+;       "[a-zA-Z0-9_:]+"
+;       "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)"       ; either pointer/ref sign or whitespace
+;       "\\)?"                           ; if there is a last type spec
+;       "\\("                        ; name; take that into the imenu entry
+;       "[a-zA-Z0-9_:~]+"                    ; member function, ctor or dtor...
+;                                      ; (may not contain * because then
+;                                      ; "a::operator char*" would become "char*"!)
+;       "\\|"
+;       "\\([a-zA-Z0-9_:~]*::\\)?operator"
+;       "[^a-zA-Z1-9_][^(]*"         ; ...or operator
+;       " \\)"
+;       "[ \t]*([^)]*)[ \t\n]*;"       ; require ';' after
+;                                      ; the (...) Can't
+;                                      ; catch cases with () inside the parentheses
+;                                      ; surrounding the parameters
+;                                      ; (like "int foo(int a=bar());"
+;       )) 6)
+;    ("Struct"
+;     (, (concat
+;       "^"                            ; beginning of line is required
+;       "\\(static[ \t]+\\)?"          ; there may be static or const.
+;       "\\(const[ \t]+\\)?"
+;       "struct[ \t]+"
+;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
+;       "[ \t]*[{]"
+;       )) 3)
+;    ("Enum"
+;     (, (concat
+;       "^"                            ; beginning of line is required
+;       "\\(static[ \t]+\\)?"          ; there may be static or const.
+;       "\\(const[ \t]+\\)?"
+;       "enum[ \t]+"
+;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
+;       "[ \t]*[{]"
+;       )) 3)
+;    ("Union"
+;     (, (concat
+;       "^"                            ; beginning of line is required
+;       "\\(static[ \t]+\\)?"          ; there may be static or const.
+;       "\\(const[ \t]+\\)?"
+;       "union[ \t]+"
+;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
+;       "[ \t]*[{]"
+;       )) 3)
+    ))
+  "Imenu generic expression for C mode.  See `imenu-generic-expression'.")
 \f
 (defun c-mode ()
   "Major mode for editing C code.
@@ -219,17 +353,23 @@ if that value is non-nil."
   (setq local-abbrev-table c-mode-abbrev-table)
   (set-syntax-table c-mode-syntax-table)
   (make-local-variable 'paragraph-start)
-  (setq paragraph-start (concat "^$\\|" page-delimiter))
+  (setq paragraph-start (concat "$\\|" page-delimiter))
   (make-local-variable 'paragraph-separate)
   (setq paragraph-separate paragraph-start)
   (make-local-variable 'paragraph-ignore-fill-prefix)
   (setq paragraph-ignore-fill-prefix t)
+  (make-local-variable 'fill-paragraph-function)
+  (setq fill-paragraph-function 'c-fill-paragraph)
   (make-local-variable 'indent-line-function)
   (setq indent-line-function 'c-indent-line)
   (make-local-variable 'indent-region-function)
   (setq indent-region-function 'c-indent-region)
   (make-local-variable 'require-final-newline)
   (setq require-final-newline t)
+  (make-local-variable 'outline-regexp)
+  (setq outline-regexp "[^#\n\^M]")
+  (make-local-variable 'outline-level)
+  (setq outline-level 'c-outline-level)
   (make-local-variable 'comment-start)
   (setq comment-start "/* ")
   (make-local-variable 'comment-end)
@@ -240,9 +380,19 @@ if that value is non-nil."
   (setq comment-start-skip "/\\*+ *")
   (make-local-variable 'comment-indent-function)
   (setq comment-indent-function 'c-comment-indent)
+  (make-local-variable 'comment-multi-line)
+  (setq comment-multi-line t)
   (make-local-variable 'parse-sexp-ignore-comments)
   (setq parse-sexp-ignore-comments t)
+  (make-local-variable 'imenu-generic-expression)
+  (setq imenu-generic-expression c-imenu-generic-expression)
+  (setq imenu-case-fold-search nil)
   (run-hooks 'c-mode-hook))
+
+(defun c-outline-level ()
+  (save-excursion
+    (skip-chars-forward "\t ")
+    (current-column)))
 \f
 ;; This is used by indent-for-comment
 ;; to decide how much to indent a comment in C code
@@ -294,13 +444,13 @@ preserving the comment indentation or line-starting decorations."
              (paragraph-start
               ;; Lines containing just a comment start or just an end
               ;; should not be filled into paragraphs they are next to.
-              (concat 
+              (concat
                paragraph-start
-               "\\|^[ \t]*/\\*[ \t]*$\\|^[ \t]*\\*/[ \t]*$\\|^[ \t/*]*$"))
+               "\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$"))
              (paragraph-separate
               (concat
                paragraph-separate
-               "\\|^[ \t]*/\\*[ \t]*$\\|^[ \t]*\\*/[ \t]*$\\|^[ \t/*]*$")))
+               "\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$")))
          (save-excursion
            (beginning-of-line)
            ;; Move up to first line of this comment.
@@ -377,6 +527,11 @@ preserving the comment indentation or line-starting decorations."
                                     (point))))
                              (beginning-of-line)
                              (skip-chars-forward " \t*" max-prefix-end)
+                             ;; Don't include part of comment terminator
+                             ;; in the fill-prefix.
+                             (and (eq (following-char) ?/)
+                                  (eq (preceding-char) ?*)
+                                  (backward-char 1))
                              (point)))
 
                         ;; If the comment is only one line followed by a blank
@@ -400,13 +555,13 @@ preserving the comment indentation or line-starting decorations."
                (paragraph-start
                 ;; Lines containing just a comment start or just an end
                 ;; should not be filled into paragraphs they are next to.
-                (concat 
+                (concat
                  paragraph-start
-                 "\\|^[ \t]*/\\*[ \t]*$\\|^[ \t]*\\*/[ \t]*$\\|^[ \t/*]*$"))
+                 "\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$"))
                (paragraph-separate
                 (concat
                  paragraph-separate
-                 "\\|^[ \t]*/\\*[ \t]*$\\|^[ \t]*\\*/[ \t]*$\\|^[ \t/*]*$"))
+                 "\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$"))
                (chars-to-delete 0))
            (save-restriction
              ;; Don't fill the comment together with the code following it.
@@ -418,8 +573,8 @@ preserving the comment indentation or line-starting decorations."
                                  (if comment-start-place
                                      (goto-char comment-start-place)
                                    (search-backward "/*"))
-                                 ;; Protect text before the comment start 
-                                 ;; by excluding it.  Add spaces to bring back 
+                                 ;; Protect text before the comment start
+                                 ;; by excluding it.  Add spaces to bring back
                                  ;; proper indentation of that point.
                                  (let ((column (current-column)))
                                    (prog1 (point)
@@ -431,6 +586,16 @@ preserving the comment indentation or line-starting decorations."
                                  (search-forward "*/" nil 'move)
                                  (forward-line 1)
                                  (point)))
+             (save-excursion
+               (goto-char (point-max))
+               (forward-line -1)
+               ;; And comment terminator was on a separate line before,
+               ;; keep it that way.
+               ;; This also avoids another problem:
+               ;; if the fill-prefix ends in a *, it could eat up
+               ;; the * of the comment terminator.
+               (if (looking-at "[ \t]*\\*/")
+                   (narrow-to-region (point-min) (point))))
              (fill-paragraph arg)
              (save-excursion
                ;; Delete the chars we inserted to avoid clobbering
@@ -440,14 +605,19 @@ preserving the comment indentation or line-starting decorations."
                    (delete-region (point) (+ (point) chars-to-delete)))
                ;; Find the comment ender (should be on last line of buffer,
                ;; given the narrowing) and don't leave it on its own line.
+               ;; Do this with a fill command, so as to preserve sentence
+               ;; boundaries.
                (goto-char (point-max))
                (forward-line -1)
                (search-forward "*/" nil 'move)
                (beginning-of-line)
                (if (looking-at "[ \t]*\\*/")
-                   (delete-indentation)))))
+                   (let ((fill-column (+ fill-column 9999)))
+                     (forward-line -1)
+                     (fill-region-as-paragraph (point) (point-max)))))))
        ;; Outside of comments: do ordinary filling.
-       (fill-paragraph arg)))))
+       (fill-paragraph arg)))
+    t))
 
 (defun electric-c-brace (arg)
   "Insert character and correct line's indentation."
@@ -610,13 +780,15 @@ Return the amount the indentation changed by."
                  (setq indent (save-excursion
                                 (c-backward-to-start-of-if)
                                 (current-indentation))))
-                ((looking-at "}[ \t]*else")
+                ((and (looking-at "}[ \t]*else\\b")
+                      (not (looking-at "}[ \t]*else\\s_")))
                  (setq indent (save-excursion
                                 (forward-char)
                                 (backward-sexp)
                                 (c-backward-to-start-of-if)
                                 (current-indentation))))
                 ((and (looking-at "while\\b")
+                      (not (looking-at "while\\s_"))
                       (save-excursion
                         (c-backward-to-start-of-do)))
                  ;; This is a `while' that ends a do-while.
@@ -698,11 +870,17 @@ Returns nil if line starts inside a string, t if in a comment."
                                     (looking-at "[^\"\n=(]*(")
                                     (progn
                                       (goto-char (1- (match-end 0)))
-                                      (setq lim (point))
-                                      (condition-case nil
-                                          (forward-sexp 1)
-                                        (error))
-                                      (skip-chars-forward " \t\f")
+                                      ;; Skip any number of paren-groups.
+                                      ;; Consider typedef int (*fcn) (int);
+                                      (while (= (following-char) ?\()
+                                        (setq lim (point))
+                                        (condition-case nil
+                                            (forward-sexp 1)
+                                          (error))
+                                        (skip-chars-forward " \t\f"))
+                                      ;; Have we reached something
+                                      ;; that shows this isn't a function
+                                      ;; definition?
                                       (and (< (point) indent-point)
                                            (not (memq (following-char)
                                                       '(?\, ?\;)))))
@@ -753,23 +931,28 @@ Returns nil if line starts inside a string, t if in a comment."
               (beginning-of-line)
               (c-backward-to-noncomment containing-sexp))
             ;; Check for a preprocessor statement or its continuation lines.
-            ;; Move back to end of previous non-preprocessor line.
+            ;; Move back to end of previous non-preprocessor line,
+            ;; or possibly beginning of buffer.
             (let ((found (point)) stop)
               (while (not stop)
-                (cond ((save-excursion (end-of-line 0)
+                (beginning-of-line)
+                (cond ((bobp)
+                       (setq found (point)
+                             stop t))
+                      ((save-excursion (forward-char -1)
                                        (= (preceding-char) ?\\))
-                       (end-of-line 0))
+                       (forward-char -1))
                       ;; This line is not preceded by a backslash.
                       ;; So either it starts a preprocessor command
                       ;; or any following continuation lines
                       ;; should not be skipped.
-                      ((progn (beginning-of-line) (= (following-char) ?#))
-                       (end-of-line 0)
+                      ((= (following-char) ?#)
+                       (forward-char -1)
                        (setq found (point)))
                       (t (setq stop t))))
               (goto-char found))
             ;; Now we get the answer.
-            (if (and (not (memq (preceding-char) '(nil ?\, ?\; ?\} ?\{)))
+            (if (and (not (memq (preceding-char) '(0 ?\, ?\; ?\} ?\{)))
                      ;; But don't treat a line with a close-brace
                      ;; as a continuation.  It is probably the
                      ;; end of an enum type declaration.
@@ -812,7 +995,7 @@ Returns nil if line starts inside a string, t if in a comment."
                     ;; The first following code counts
                     ;; if it is before the line we want to indent.
                     (and (< (point) indent-point)
-                         (- 
+                         (-
                           (if (> colon-line-end (point))
                               (- (current-indentation) c-label-offset)
                             (current-column))
@@ -823,27 +1006,32 @@ Returns nil if line starts inside a string, t if in a comment."
                           (if (= (following-char) ?\{) c-brace-offset 0)))))
                 ;; If no previous statement,
                 ;; indent it relative to line brace is on.
-                ;; For open brace in column zero, don't let statement
-                ;; start there too.  If c-indent-level is zero,
-                ;; use c-brace-offset + c-continued-statement-offset instead.
-                ;; For open-braces not the first thing in a line,
-                ;; add in c-brace-imaginary-offset.
-                (+ (if (and (bolp) (zerop c-indent-level))
-                       (+ c-brace-offset c-continued-statement-offset)
-                     c-indent-level)
-                   ;; Move back over whitespace before the openbrace.
-                   ;; If openbrace is not first nonwhite thing on the line,
-                   ;; add the c-brace-imaginary-offset.
-                   (progn (skip-chars-backward " \t")
-                          (if (bolp) 0 c-brace-imaginary-offset))
-                   ;; If the openbrace is preceded by a parenthesized exp,
-                   ;; move to the beginning of that;
-                   ;; possibly a different line
-                   (progn
-                     (if (eq (preceding-char) ?\))
-                         (forward-sexp -1))
-                     ;; Get initial indentation of the line we are on.
-                     (current-indentation))))))))))
+                (calculate-c-indent-after-brace))))))))
+
+(defun calculate-c-indent-after-brace ()
+  "Return the proper C indent for the first line after an open-brace.
+This function is called with point before the brace."
+  ;; For open brace in column zero, don't let statement
+  ;; start there too.  If c-indent-level is zero,
+  ;; use c-brace-offset + c-continued-statement-offset instead.
+  ;; For open-braces not the first thing in a line,
+  ;; add in c-brace-imaginary-offset.
+  (+ (if (and (bolp) (zerop c-indent-level))
+        (+ c-brace-offset c-continued-statement-offset)
+       c-indent-level)
+     ;; Move back over whitespace before the openbrace.
+     ;; If openbrace is not first nonwhite thing on the line,
+     ;; add the c-brace-imaginary-offset.
+     (progn (skip-chars-backward " \t")
+           (if (bolp) 0 c-brace-imaginary-offset))
+     ;; If the openbrace is preceded by a parenthesized exp,
+     ;; move to the beginning of that;
+     ;; possibly a different line
+     (progn
+       (if (eq (preceding-char) ?\))
+          (forward-sexp -1))
+       ;; Get initial indentation of the line we are on.
+       (current-indentation))))
 
 (defun calculate-c-indent-within-comment (&optional after-star)
   "Return the indentation amount for line inside a block comment.
@@ -902,9 +1090,11 @@ return the indentation of the text that would follow this star."
        (case-fold-search nil))
     (while (and (not (bobp)) (not (zerop if-level)))
       (backward-sexp 1)
-      (cond ((looking-at "else\\b")
+      (cond ((and (looking-at "else\\b")
+                 (not (looking-at "else\\s_")))
             (setq if-level (1+ if-level)))
-           ((looking-at "if\\b")
+           ((and (looking-at "if\\b")
+                 (not (looking-at "if\\s_")))
             (setq if-level (1- if-level)))
            ((< (point) limit)
             (setq if-level 0)
@@ -1008,7 +1198,7 @@ If within a string or comment, move by sentences instead of statements."
                          (not (re-search-forward "[;{}]" end t)))))))
        (re-search-backward "[;}]")
        (forward-char 1))
-    (error 
+    (error
      (let ((beg (point)))
        (backward-up-list -1)
        (let ((end (point)))
@@ -1147,55 +1337,66 @@ If within a string or comment, move by sentences instead of statements."
          ;; past the region.)
          (if (or (eolp) (and endpos (>= (point) endpos)))
              nil
+           ;; Is this line in a new nesting level?
+           ;; In other words, is this the first line that
+           ;; starts in the new level?
            (if (and (car indent-stack)
                     (>= (car indent-stack) 0))
-               ;; Line is on an existing nesting level.
-               ;; Lines inside parens are handled specially.
-               (if (/= (char-after (car contain-stack)) ?{)
-                   (setq this-indent (car indent-stack))
-                 ;; Line is at statement level.
-                 ;; Is it a new statement?  Is it an else?
-                 ;; Find last non-comment character before this line
-                 (save-excursion
-                   (setq this-point (point))
-                   (setq at-else (looking-at "else\\W"))
-                   (setq at-brace (= (following-char) ?{))
-                   (setq at-while (looking-at "while\\b"))
-                   (if (= (following-char) ?})
-                       (setq this-indent (car indent-stack))
-                     (c-backward-to-noncomment opoint)
-                     (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?{)))
-                         ;; Preceding line did not end in comma or semi;
-                         ;; indent this line  c-continued-statement-offset
-                         ;; more than previous.
-                         (progn
-                           (c-backward-to-start-of-continued-exp (car contain-stack))
-                           (setq this-indent
-                                 (+ c-continued-statement-offset (current-column)
-                                    (if at-brace c-continued-brace-offset 0))))
-                       ;; Preceding line ended in comma or semi;
-                       ;; use the standard indent for this level.
-                       (cond (at-else (progn (c-backward-to-start-of-if opoint)
-                                             (setq this-indent
-                                                   (current-indentation))))
-                             ((and at-while (c-backward-to-start-of-do opoint))
-                              (setq this-indent (current-indentation)))
-                             ((eq (preceding-char) ?\,)
-                              (goto-char this-point)
-                              (setq this-indent (calculate-c-indent)))
-                             (t (setq this-indent (car indent-stack))))))))
-             ;; Just started a new nesting level.
+               nil
+             ;; Yes.
              ;; Compute the standard indent for this level.
-             (let ((val (calculate-c-indent
-                          (if (car indent-stack)
-                              (- (car indent-stack))
-                            opoint))))
+             (let (val)
+               (if (= (char-after (car contain-stack)) ?{)
+                   (save-excursion
+                     (goto-char (car contain-stack))
+                     (setq val (calculate-c-indent-after-brace)))
+                 (setq val (calculate-c-indent
+                            (if (car indent-stack)
+                                (- (car indent-stack))
+                              opoint))))
                ;; t means we are in a block comment and should
                ;; calculate accordingly.
                (if (eq val t)
                    (setq val (calculate-c-indent-within-comment)))
-               (setcar indent-stack
-                       (setq this-indent val))))
+               (setcar indent-stack val)))
+           ;; Adjust indent of this individual line
+           ;; based on its predecessor.
+           ;; Handle continuation lines, if, else, while, and so on.
+           (if (/= (char-after (car contain-stack)) ?{)
+               (setq this-indent (car indent-stack))
+             ;; Line is at statement level.
+             ;; Is it a new statement?  Is it an else?
+             ;; Find last non-comment character before this line
+             (save-excursion
+               (setq this-point (point))
+               (setq at-else (and (looking-at "else\\b")
+                                  (not (looking-at "else\\s_"))))
+               (setq at-brace (= (following-char) ?{))
+               (setq at-while (and (looking-at "while\\b")
+                                   (not (looking-at "while\\s_"))))
+               (if (= (following-char) ?})
+                   (setq this-indent (car indent-stack))
+                 (c-backward-to-noncomment opoint)
+                 (if (not (memq (preceding-char) '(0 ?\, ?\; ?} ?: ?{)))
+                     ;; Preceding line did not end in comma or semi;
+                     ;; indent this line  c-continued-statement-offset
+                     ;; more than previous.
+                     (progn
+                       (c-backward-to-start-of-continued-exp (car contain-stack))
+                       (setq this-indent
+                             (+ c-continued-statement-offset (current-column)
+                                (if at-brace c-continued-brace-offset 0))))
+                   ;; Preceding line ended in comma or semi;
+                   ;; use the standard indent for this level.
+                   (cond (at-else (progn (c-backward-to-start-of-if opoint)
+                                         (setq this-indent
+                                               (current-indentation))))
+                         ((and at-while (c-backward-to-start-of-do opoint))
+                          (setq this-indent (current-indentation)))
+                         ((eq (preceding-char) ?\,)
+                          (goto-char this-point)
+                          (setq this-indent (calculate-c-indent)))
+                         (t (setq this-indent (car indent-stack))))))))
            ;; Adjust line indentation according to its contents
            (if (or (looking-at c-switch-label-regexp)
                    (and (looking-at "[A-Za-z]")
@@ -1226,17 +1427,18 @@ If within a string or comment, move by sentences instead of statements."
                  (indent-to this-indent)))
            ;; Indent any comment following the text.
            (or (looking-at comment-start-skip)
-               (let ((beg (point)))
-                 (and (re-search-forward
-                       comment-start-skip
-                       (save-excursion (end-of-line) (point)) t)
-                      ;; Make sure the comment starter we found
-                      ;; is not actually in a string or quoted.
-                      (let ((new-state
-                             (parse-partial-sexp beg (point)
-                                                 nil nil state)))
-                        (and (not (nth 3 new-state)) (not (nth 5 new-state))))
-                     (progn (indent-for-comment) (beginning-of-line)))))))))))
+               (save-excursion
+                 (let ((beg (point)))
+                   (and (re-search-forward
+                         comment-start-skip
+                         (save-excursion (end-of-line) (point)) t)
+                        ;; Make sure the comment starter we found
+                        ;; is not actually in a string or quoted.
+                        (let ((new-state
+                               (parse-partial-sexp beg (point)
+                                                   nil nil state)))
+                          (and (not (nth 3 new-state)) (not (nth 5 new-state))))
+                        (indent-for-comment)))))))))))
 
 ;; Look at all comment-start strings in the current line after point.
 ;; Return t if one of them starts a real comment.
@@ -1310,8 +1512,9 @@ The arguments are a string representing the desired style
 and a flag which, if non-nil, means to set the style globally.
 \(Interactively, the flag comes from the prefix argument.)
 Available styles are GNU, K&R, BSD and Whitesmith."
-  (interactive (list (completing-read "Use which C indentation style? "
-                                      c-style-alist nil t)
+  (interactive (list (let ((completion-ignore-case t))
+                      (completing-read "Use which C indentation style? "
+                                       c-style-alist nil t))
                     current-prefix-arg))
   (let ((vars (cdr (assoc style c-style-alist))))
     (or vars
@@ -1324,15 +1527,17 @@ Available styles are GNU, K&R, BSD and Whitesmith."
 \f
 ;;; This page handles insertion and removal of backslashes for C macros.
 
-(defvar c-backslash-column 48
-  "*Minimum column for end-of-line backslashes of macro definitions.")
+(defcustom c-backslash-column 48
+  "*Minimum column for end-of-line backslashes of macro definitions."
+  :type 'integer
+  :group 'old-c)
 
 (defun c-backslash-region (from to delete-flag)
   "Insert, align, or delete end-of-line backslashes on the lines in the region.
 With no argument, inserts backslashes and aligns existing backslashes.
 With an argument, deletes the backslashes.
 
-This function does not modify the last line of the region if the region ends 
+This function does not modify the last line of the region if the region ends
 right at the start of the following line; it does not modify blank lines
 at the start of the region.  So you can put the region around an entire macro
 definition and conveniently use this command."
@@ -1456,12 +1661,16 @@ move backward across a preprocessor conditional."
                    (if forward (forward-line 1))
                    ;; If this line exits a level of conditional, exit inner loop.
                    (if (< depth 0)
-                       (setq found (point)))))))
+                       (setq found (point))))
+               ;; If the line is not really a conditional, skip past it.
+               (if forward (end-of-line)))))
          (or found
              (error "No containing preprocessor conditional"))
          (goto-char (setq new found)))
        (setq count (+ count increment))))
     (push-mark)
     (goto-char new)))
+\f
+(provide 'c-mode)
 
 ;;; c-mode.el ends here