Add arch taglines
[bpt/emacs.git] / lisp / progmodes / cc-cmds.el
index 70195e4..f786153 100644 (file)
@@ -1,10 +1,9 @@
 ;;; cc-cmds.el --- user level commands for CC Mode
 
-;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc.
+;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc.
 
-;; Authors:    2000- Martin Stjernholm
-;;            1998-1999 Barry A. Warsaw and Martin Stjernholm
-;;             1992-1997 Barry A. Warsaw
+;; Authors:    1998- Martin Stjernholm
+;;             1992-1999 Barry A. Warsaw
 ;;             1987 Dave Detlefs and Stewart Clamen
 ;;             1985 Richard M. Stallman
 ;; Maintainer: bug-cc-mode@gnu.org
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with this program; see the file COPYING.  If not, write to
+;; 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:
+
+;;; Code:
+
 (eval-when-compile
   (let ((load-path
         (if (and (boundp 'byte-compile-dest-file)
                  (stringp byte-compile-dest-file))
             (cons (file-name-directory byte-compile-dest-file) load-path)
           load-path)))
-    (require 'cc-bytecomp)))
+    (load "cc-bytecomp" nil t)))
 
 (cc-require 'cc-defs)
 (cc-require 'cc-vars)
-(cc-require 'cc-langs)
 (cc-require 'cc-engine)
 
 ;; Silence the compiler.
                                        ; which looks at this.
 
 \f
-(defun c-calculate-state (arg prevstate)
-  ;; Calculate the new state of PREVSTATE, t or nil, based on arg. If
-  ;; arg is nil or zero, toggle the state. If arg is negative, turn
-  ;; the state off, and if arg is positive, turn the state on
-  (if (or (not arg)
-         (zerop (setq arg (prefix-numeric-value arg))))
-      (not prevstate)
-    (> arg 0)))
-
-;; Auto-newline and hungry-delete
+(defvar c-fix-backslashes t)
+
+(defun c-shift-line-indentation (shift-amt)
+  ;; This function does not do any hidden buffer changes.
+  (let ((pos (- (point-max) (point)))
+       (c-macro-start c-macro-start)
+       tmp-char-inserted)
+    (if (zerop shift-amt)
+       nil
+      (when (and (c-query-and-set-macro-start)
+                (looking-at "[ \t]*\\\\$")
+                (save-excursion
+                  (skip-chars-backward " \t")
+                  (bolp)))
+       (insert ?x)
+       (backward-char)
+       (setq tmp-char-inserted t))
+      (unwind-protect
+         (let ((col (current-indentation)))
+           (delete-region (c-point 'bol) (c-point 'boi))
+           (beginning-of-line)
+           (indent-to (+ col shift-amt)))
+       (when tmp-char-inserted
+         (delete-char 1))))
+    ;; If initial point was within line's indentation and we're not on
+    ;; a line with a line continuation in a macro, position after the
+    ;; indentation.  Else stay at same point in text.
+    (if (and (< (point) (c-point 'boi))
+            (not tmp-char-inserted))
+       (back-to-indentation)
+      (if (> (- (point-max) pos) (point))
+         (goto-char (- (point-max) pos))))))
+
+(defun c-indent-line (&optional syntax quiet ignore-point-pos)
+  "Indent the current line according to the syntactic context,
+if `c-syntactic-indentation' is non-nil.  Optional SYNTAX is the
+syntactic information for the current line.  Be silent about syntactic
+errors if the optional argument QUIET is non-nil, even if
+`c-report-syntactic-errors' is non-nil.  Normally the position of
+point is used to decide where the old indentation is on a lines that
+is otherwise empty \(ignoring any line continuation backslash), but
+that's not done if IGNORE-POINT-POS is non-nil.  Returns the amount of
+indentation change \(in columns)."
+  ;;
+  ;; This function does not do any hidden buffer changes.
+
+  (let ((line-cont-backslash (save-excursion
+                              (end-of-line)
+                              (eq (char-before) ?\\)))
+       (c-fix-backslashes c-fix-backslashes)
+       bs-col
+       shift-amt)
+    (when (and (not ignore-point-pos)
+              (save-excursion
+                (beginning-of-line)
+                (looking-at (if line-cont-backslash
+                                "\\(\\s *\\)\\\\$"
+                              "\\(\\s *\\)$")))
+              (<= (point) (match-end 1)))
+      ;; Delete all whitespace after point if there's only whitespace
+      ;; on the line, so that any code that does back-to-indentation
+      ;; or similar gets the current column in this case.  If this
+      ;; removes a line continuation backslash it'll be restored
+      ;; at the end.
+      (unless c-auto-align-backslashes
+       ;; Should try to keep the backslash alignment
+       ;; in this case.
+       (save-excursion
+         (goto-char (match-end 0))
+         (setq bs-col (1- (current-column)))))
+      (delete-region (point) (match-end 0))
+      (setq c-fix-backslashes t))
+    (if c-syntactic-indentation
+       (setq c-parsing-error
+             (or (let ((c-parsing-error nil)
+                       (c-syntactic-context
+                        (or syntax
+                            (and (boundp 'c-syntactic-context)
+                                 c-syntactic-context))))
+                   (c-save-buffer-state (indent)
+                     (unless c-syntactic-context
+                       (setq c-syntactic-context (c-guess-basic-syntax)))
+                     (setq indent (c-get-syntactic-indentation
+                                   c-syntactic-context))
+                     (and (not (c-echo-parsing-error quiet))
+                          c-echo-syntactic-information-p
+                          (message "syntax: %s, indent: %d"
+                                   c-syntactic-context indent))
+                     (setq shift-amt (- indent (current-indentation))))
+                   (c-shift-line-indentation shift-amt)
+                   (run-hooks 'c-special-indent-hook)
+                   c-parsing-error)
+                 c-parsing-error))
+      (let ((indent 0))
+       (save-excursion
+         (while (and (= (forward-line -1) 0)
+                     (if (looking-at "\\s *\\\\?$")
+                         t
+                       (setq indent (current-indentation))
+                       nil))))
+       (setq shift-amt (- indent (current-indentation)))
+       (c-shift-line-indentation shift-amt)))
+    (when (and c-fix-backslashes line-cont-backslash)
+      (if bs-col
+         (save-excursion
+           (indent-to bs-col)
+           (insert ?\\))
+       (when c-auto-align-backslashes
+         ;; Realign the line continuation backslash.
+         (c-backslash-region (point) (point) nil t))))
+    shift-amt))
+
+(defun c-newline-and-indent (&optional newline-arg)
+  "Inserts a newline and indents the new line.
+This function fixes line continuation backslashes if inside a macro,
+and takes care to set the indentation before calling
+`indent-according-to-mode', so that lineup functions like
+`c-lineup-dont-change' works better."
+  ;;
+  ;; This function does not do any hidden buffer changes.
+
+  ;; TODO: Backslashes before eol in comments and literals aren't
+  ;; kept intact.
+  (let ((c-macro-start (c-query-macro-start))
+       ;; Avoid calling c-backslash-region from c-indent-line if it's
+       ;; called during the newline call, which can happen due to
+       ;; c-electric-continued-statement, for example.  We also don't
+       ;; want any backslash alignment from indent-according-to-mode.
+       (c-fix-backslashes nil)
+       has-backslash insert-backslash
+       start col)
+    (save-excursion
+      (beginning-of-line)
+      (setq start (point))
+      (while (and (looking-at "[ \t]*\\\\?$")
+                 (= (forward-line -1) 0)))
+      (setq col (current-indentation)))
+    (when c-macro-start
+      (if (and (eolp) (eq (char-before) ?\\))
+         (setq insert-backslash t
+               has-backslash t)
+       (setq has-backslash (eq (char-before (c-point 'eol)) ?\\))))
+    (newline newline-arg)
+    (indent-to col)
+    (when c-macro-start
+      (if insert-backslash
+         (progn
+           ;; The backslash stayed on the previous line.  Insert one
+           ;; before calling c-backslash-region, so that
+           ;; bs-col-after-end in it works better.  Fixup the
+           ;; backslashes on the newly inserted line.
+           (insert ?\\)
+           (backward-char)
+           (c-backslash-region (point) (point) nil t))
+       ;; The backslash moved to the new line, if there was any.  Let
+       ;; c-backslash-region fix a backslash on the previous line,
+       ;; and the one that might be on the new line.
+       ;; c-auto-align-backslashes is intentionally ignored here;
+       ;; maybe the moved backslash should be left alone if it's set,
+       ;; but we fix both lines on the grounds that the old backslash
+       ;; has been moved anyway and is now in a different context.
+       (c-backslash-region start (if has-backslash (point) start) nil t)))
+    (when c-syntactic-indentation
+      ;; Reindent syntactically.  The indentation done above is not
+      ;; wasted, since c-indent-line might look at the current
+      ;; indentation.
+      (let ((c-syntactic-context (c-save-buffer-state nil
+                                  (c-guess-basic-syntax))))
+       ;; We temporarily insert another line break, so that the
+       ;; lineup functions will see the line as empty.  That makes
+       ;; e.g. c-lineup-cpp-define more intuitive since it then
+       ;; proceeds to the preceding line in this case.
+       (insert ?\n)
+       (delete-horizontal-space)
+       (setq start (- (point-max) (point)))
+       (unwind-protect
+           (progn
+             (backward-char)
+             (indent-according-to-mode))
+         (goto-char (- (point-max) start))
+         (delete-char -1)))
+      (when has-backslash
+       ;; Must align the backslash again after reindentation.  The
+       ;; c-backslash-region call above can't be optimized to ignore
+       ;; this line, since it then won't align correctly with the
+       ;; lines below if the first line in the macro is broken.
+       (c-backslash-region (point) (point) nil t)))))
+
+(defun c-show-syntactic-information (arg)
+  "Show syntactic information for current line.
+With universal argument, inserts the analysis as a comment on that line."
+  (interactive "P")
+  (let* ((c-parsing-error nil)
+        (syntax (if (boundp 'c-syntactic-context)
+                    ;; Use `c-syntactic-context' in the same way as
+                    ;; `c-indent-line', to be consistent.
+                    c-syntactic-context
+                  (c-save-buffer-state nil
+                    (c-guess-basic-syntax)))))
+    (if (not (consp arg))
+       (message "syntactic analysis: %s" syntax)
+      (indent-for-comment)
+      (insert-and-inherit (format "%s" syntax))
+      ))
+  (c-keep-region-active))
+
+(defun c-syntactic-information-on-region (from to)
+  "Inserts a comment with the syntactic analysis on every line in the region."
+  (interactive "*r")
+  (save-excursion
+    (save-restriction
+      (narrow-to-region from to)
+      (goto-char (point-min))
+      (while (not (eobp))
+       (c-show-syntactic-information '(0))
+       (forward-line)))))
+
+\f
+(defun c-toggle-syntactic-indentation (&optional arg)
+  "Toggle syntactic indentation.
+Optional numeric ARG, if supplied, turns on syntactic indentation when
+positive, turns it off when negative, and just toggles it when zero or
+left out.
+
+When syntactic indentation is turned on (the default), the indentation
+functions and the electric keys indent according to the syntactic
+context keys, when applicable.
+
+When it's turned off, the electric keys does no reindentation, the
+indentation functions indents every new line to the same level as the
+previous nonempty line, and \\[c-indent-command] adjusts the
+indentation in seps specified `c-basic-offset'.  The indentation style
+has no effect in this mode, nor any of the indentation associated
+variables, e.g. `c-special-indent-hook'.
+
+This command sets the variable `c-syntactic-indentation'."
+  (interactive "P")
+  (setq c-syntactic-indentation
+       (c-calculate-state arg c-syntactic-indentation))
+  (c-keep-region-active))
+
 (defun c-toggle-auto-state (&optional arg)
   "Toggle auto-newline feature.
 Optional numeric ARG, if supplied, turns on auto-newline when
@@ -105,77 +338,96 @@ See `c-toggle-auto-state' and `c-toggle-hungry-state' for details."
 \f
 ;; Electric keys
 
-;; Note: In XEmacs 20.3 the Delete and BackSpace keysyms have been
-;; separated and "\177" is no longer an alias for both keys.  Also,
-;; the variable delete-key-deletes-forward controls in which direction
-;; the Delete keysym deletes characters.  The functions
-;; c-electric-delete and c-electric-backspace attempt to deal with
-;; this new functionality.  For Emacs 19 and XEmacs 19 backwards
-;; compatibility, the old behavior has moved to c-electric-backspace
-;; and c-backspace-function.
-
 (defun c-electric-backspace (arg)
-  "Deletes preceding character or whitespace.
+  "Delete the preceding character or whitespace.
 If `c-hungry-delete-key' is non-nil, as evidenced by the \"/h\" or
 \"/ah\" string on the mode line, then all preceding whitespace is
-consumed.  If however an ARG is supplied, or `c-hungry-delete-key' is
-nil, or point is inside a literal then the function in the variable
-`c-backspace-function' is called.
-
-See also \\[c-electric-delete]."
+consumed.  If however a prefix argument is supplied, or
+`c-hungry-delete-key' is nil, or point is inside a literal then the
+function in the variable `c-backspace-function' is called."
   (interactive "*P")
   (if (or (not c-hungry-delete-key)
          arg
          (c-in-literal))
       (funcall c-backspace-function (prefix-numeric-value arg))
-    (let ((here (point)))
-      (skip-chars-backward " \t\n")
-      (if (/= (point) here)
-         (delete-region (point) here)
-       (funcall c-backspace-function 1)
-       ))))
+    (c-hungry-backspace)))
 
-(defun c-electric-delete (arg)
-  "Deletes preceding or following character or whitespace.
+(defun c-hungry-backspace ()
+  "Delete the preceding character or all preceding whitespace
+back to the previous non-whitespace character.
+See also \\[c-hungry-delete-forward]."
+  (interactive)
+  (let ((here (point)))
+    (c-skip-ws-backward)
+    (if (/= (point) here)
+       (delete-region (point) here)
+      (funcall c-backspace-function 1))))
+
+(defun c-electric-delete-forward (arg)
+  "Delete the following character or whitespace.
+If `c-hungry-delete-key' is non-nil, as evidenced by the \"/h\" or
+\"/ah\" string on the mode line, then all following whitespace is
+consumed.  If however a prefix argument is supplied, or
+`c-hungry-delete-key' is nil, or point is inside a literal then the
+function in the variable `c-delete-function' is called."
+  (interactive "*P")
+  (if (or (not c-hungry-delete-key)
+         arg
+         (c-in-literal))
+      (funcall c-delete-function (prefix-numeric-value arg))
+    (c-hungry-delete-forward)))
 
-The behavior of this function depends on the variable
-`delete-key-deletes-forward'.  If this variable is nil (or does not
-exist, as in older Emacsen), then this function behaves identical to
-\\[c-electric-backspace].
+(defun c-hungry-delete-forward ()
+  "Delete the following character or all following whitespace
+up to the next non-whitespace character.
+See also \\[c-hungry-backspace]."
+  (interactive)
+  (let ((here (point)))
+    (c-skip-ws-forward)
+    (if (/= (point) here)
+       (delete-region (point) here)
+      (funcall c-delete-function 1))))
 
-If `delete-key-deletes-forward' is non-nil and is supported in your
-Emacs, then deletion occurs in the forward direction.  So if
-`c-hungry-delete-key' is non-nil, as evidenced by the \"/h\" or
-\"/ah\" string on the mode line, then all following whitespace is
-consumed.  If however an ARG is supplied, or `c-hungry-delete-key' is
-nil, or point is inside a literal then the function in the variable
-`c-delete-function' is called."
+;; This function is only used in XEmacs.
+(defun c-electric-delete (arg)
+  "Deletes preceding or following character or whitespace.
+This function either deletes forward as `c-electric-delete-forward' or
+backward as `c-electric-backspace', depending on the configuration:
+
+If the function `delete-forward-p' is defined (XEmacs 21) and returns
+non-nil, it deletes forward.  Else, if the variable
+`delete-key-deletes-forward' is defined (XEmacs 20) and is set to
+non-nil, it deletes forward.  Otherwise it deletes backward.
+
+Note: This is the way in XEmacs 20 and later to choose the correct
+action for the [delete] key, whichever key that means.  In other
+flavors this function isn't used, instead it's left to the user to
+bind [delete] to either \\[c-electric-delete-forward] or \\[c-electric-backspace] as appropriate
+\(the keymap `function-key-map' is useful for that).  Emacs 21 handles
+that automatically, though."
   (interactive "*P")
   (if (or (and (fboundp 'delete-forward-p) ;XEmacs 21
               (delete-forward-p))
          (and (boundp 'delete-key-deletes-forward) ;XEmacs 20
               delete-key-deletes-forward))
-      (if (or (not c-hungry-delete-key)
-             arg
-             (c-in-literal))
-         (funcall c-delete-function (prefix-numeric-value arg))
-       (let ((here (point)))
-         (skip-chars-forward " \t\n")
-         (if (/= (point) here)
-             (delete-region (point) here)
-           (funcall c-delete-function 1))))
-    ;; act just like c-electric-backspace
+      (c-electric-delete-forward arg)
     (c-electric-backspace arg)))
 
 (defun c-electric-pound (arg)
   "Electric pound (`#') insertion.
 Inserts a `#' character specially depending on the variable
 `c-electric-pound-behavior'.  If a numeric ARG is supplied, or if
-point is inside a literal, nothing special happens."
+point is inside a literal or a macro, nothing special happens."
   (interactive "*P")
   (if (or arg
          (not (memq 'alignleft c-electric-pound-behavior))
-         (save-excursion (skip-chars-backward " \t") (not (bolp)))
+         (save-excursion
+           (skip-chars-backward " \t")
+           (not (bolp)))
+         (save-excursion
+           (and (= (forward-line -1) 0)
+                (progn (end-of-line)
+                       (eq (char-before) ?\\))))
          (c-in-literal))
       ;; do nothing special
       (self-insert-command (prefix-numeric-value arg))
@@ -184,7 +436,7 @@ point is inside a literal, nothing special happens."
          (bolp (bolp)))
       (beginning-of-line)
       (delete-horizontal-space)
-      (insert-char last-command-char 1)
+      (insert last-command-char)
       (and (not bolp)
           (goto-char (- (point-max) pos)))
       )))
@@ -196,24 +448,27 @@ If the auto-newline feature is turned on, as evidenced by the \"/a\"
 or \"/ah\" string on the mode line, newlines are inserted before and
 after braces based on the value of `c-hanging-braces-alist'.
 
-Also, the line is re-indented unless a numeric ARG is supplied, there
-are non-whitespace characters present on the line after the brace, the
+Also, the line is re-indented unless a numeric ARG is supplied, the
 brace is inserted inside a literal, or `c-syntactic-indentation' is
 nil.
 
 This function does various newline cleanups based on the value of
 `c-cleanup-list'."
   (interactive "*P")
-  (let* ((c-state-cache (c-parse-state))
-        (safepos (c-safe-position (point) c-state-cache))
-        (literal (c-in-literal safepos)))
-    ;; if we're in a literal, or we're not at the end of the line, or
-    ;; a numeric arg is provided, or auto-newlining is turned off,
-    ;; then just insert the character.
-    (if (or literal
-           arg
-           (not (looking-at "[ \t]*$")))
-       (self-insert-command (prefix-numeric-value arg))
+  (let* ((safepos (c-safe-position (point) (c-parse-state)))
+        (literal (c-in-literal safepos))
+        ;; We want to inhibit blinking the paren since this will be
+        ;; most disruptive.  We'll blink it ourselves later on.
+        (old-blink-paren blink-paren-function)
+        blink-paren-function)
+    (cond
+     ((or literal arg)
+      (self-insert-command (prefix-numeric-value arg)))
+     ((not (looking-at "[ \t]*\\\\?$"))
+      (self-insert-command (prefix-numeric-value arg))
+      (if c-syntactic-indentation
+         (indent-according-to-mode)))
+     (t
       (let* ((syms
              ;; This is the list of brace syntactic symbols that can
              ;; hang.  If any new ones are added to c-offsets-alist,
@@ -226,133 +481,133 @@ This function does various newline cleanups based on the value of
                substatement-open statement-case-open
                extern-lang-open extern-lang-close
                namespace-open namespace-close
+               module-open module-close
+                composition-open composition-close
                inexpr-class-open inexpr-class-close
-               ))
-           ;; we want to inhibit blinking the paren since this will
-           ;; be most disruptive. we'll blink it ourselves later on
-           (old-blink-paren blink-paren-function)
-           blink-paren-function
-           (insertion-point (point))
-           delete-temp-newline
-           (preserve-p (and (not (bobp))
-                            (eq ?\  (char-syntax (char-before)))))
-           ;; shut this up too
-           (c-echo-syntactic-information-p nil)
-           (syntax (progn
-                     ;; only insert a newline if there is
-                     ;; non-whitespace behind us
-                     (if (save-excursion
-                           (skip-chars-backward " \t")
-                           (not (bolp)))
-                         (progn (newline)
-                                (setq delete-temp-newline t)))
-                     (if (eq last-command-char ?{)
-                         (setq c-state-cache (cons (point) c-state-cache)))
-                     (self-insert-command (prefix-numeric-value arg))
-                     ;; state cache doesn't change
-                     (c-guess-basic-syntax)))
-           (newlines (and
-                      c-auto-newline
-                      (or (c-lookup-lists
-                           syms
-                           ;; Substitute inexpr-class and class-open
-                           ;; or class-close with inexpr-class-open
-                           ;; or inexpr-class-close.
-                           (if (assq 'inexpr-class syntax)
-                               (cond ((assq 'class-open syntax)
-                                      '((inexpr-class-open)))
-                                     ((assq 'class-close syntax)
-                                      '((inexpr-class-close)))
-                                     (t syntax))
-                             syntax)
-                           c-hanging-braces-alist)
-                          '(ignore before after)))))
-       ;; Do not try to insert newlines around a special (Pike-style)
-       ;; brace list.
-       (if (and c-special-brace-lists
-                (save-excursion
-                  (c-safe (if (= (char-before) ?{)
-                              (forward-char -1)
-                            (c-forward-sexp -1))
-                          (c-looking-at-special-brace-list))))
-           (setq newlines nil))
-       ;; If syntax is a function symbol, then call it using the
-       ;; defined semantics.
-       (if (and (not (consp (cdr newlines)))
-                (functionp (cdr newlines)))
-           (let ((c-syntactic-context syntax))
+               ;; `statement-cont' is here for the case with a brace
+               ;; list opener inside a statement.  C.f. CASE B.2 in
+               ;; `c-guess-continued-construct'.
+               statement-cont))
+            (insertion-point (point))
+            (preserve-p (and (not (bobp))
+                             (eq ?\  (char-syntax (char-before)))))
+            ;; shut this up too
+            (c-echo-syntactic-information-p nil)
+            delete-temp-newline syntax newlines)
+       ;; only insert a newline if there is non-whitespace behind us
+       (when (save-excursion
+               (skip-chars-backward " \t")
+               (not (bolp)))
+         (c-newline-and-indent)
+         ;; Set markers around the newline and indention inserted
+         ;; above.  We insert the start marker here and not before
+         ;; the call to kludge around a misfeature in expand-abbrev:
+         ;; If the line contains e.g. "else" then expand-abbrev will
+         ;; be called when c-newline-and-indent inserts the newline.
+         ;; That function first removes the abbrev "else" and then
+         ;; inserts the expansion, which is an identical "else" in
+         ;; this case.  So the marker that we put after "else" would
+         ;; end up before it.
+         (setq delete-temp-newline
+               (cons (copy-marker (c-point 'eopl) t)
+                     (point-marker))))
+       (unwind-protect
+           (progn
+             (if (eq last-command-char ?{)
+                 (setq c-state-cache (cons (point) c-state-cache)))
+             (self-insert-command (prefix-numeric-value arg))
+             (c-save-buffer-state ((c-syntactic-indentation-in-macros t)
+                                   (c-auto-newline-analysis t))
+               ;; Turn on syntactic macro analysis to help with auto
+               ;; newlines only.
+               (setq syntax (c-guess-basic-syntax)))
              (setq newlines
-                   (funcall (cdr newlines) (car newlines) insertion-point))))
-       ;; does a newline go before the open brace?
-       (if (memq 'before newlines)
-           ;; we leave the newline we've put in there before,
-           ;; but we need to re-indent the line above
-           (let (old-ind
-                 (old-point-max (point-max))
-                 (pos (- (point-max) (point)))
-                 (here (point)))
-             (forward-line -1)
-             (setq old-ind (c-point 'boi))
-             (let ((c-state-cache (c-whack-state (point) c-state-cache)))
-               ;; we may need to update the cache. this should
-               ;; still be faster than recalculating the state
-               ;; in many cases
-               (save-excursion
-                 (save-restriction
-                   (narrow-to-region here (point))
-                   (if (and (c-safe (progn (backward-up-list -1) t))
-                            (memq (char-before) '(?\) ?}))
-                            (progn (widen)
-                                   (c-safe (progn (c-forward-sexp -1)
-                                                  t))))
-                       (setq c-state-cache
-                             (c-hack-state (point) 'open c-state-cache)))))
-               (if c-syntactic-indentation
-                   (indent-according-to-mode)))
-             (setq c-state-cache (c-adjust-state (c-point 'bol) old-point-max
-                                                 (- (c-point 'boi) old-ind)
-                                                 c-state-cache))
-             (goto-char (- (point-max) pos))
-             ;; if the buffer has changed due to the indentation, we
-             ;; need to recalculate syntax for the current line, but
-             ;; we won't need to update the state cache.
-             (if (/= (point) here)
-                 (setq syntax (c-guess-basic-syntax))))
+                   (and
+                    c-auto-newline
+                    (or (c-lookup-lists
+                         syms
+                         ;; Substitute inexpr-class and class-open or
+                         ;; class-close with inexpr-class-open or
+                         ;; inexpr-class-close.
+                         (if (assq 'inexpr-class syntax)
+                             (cond ((assq 'class-open syntax)
+                                    '((inexpr-class-open)))
+                                   ((assq 'class-close syntax)
+                                    '((inexpr-class-close)))
+                                   (t syntax))
+                           syntax)
+                         c-hanging-braces-alist)
+                        '(ignore before after))))
+             ;; Do not try to insert newlines around a special
+             ;; (Pike-style) brace list.
+             (if (and c-special-brace-lists
+                      (save-excursion
+                        (c-save-buffer-state nil
+                          (c-safe (if (= (char-before) ?{)
+                                      (forward-char -1)
+                                    (c-forward-sexp -1))
+                                  (c-looking-at-special-brace-list)))))
+                 (setq newlines nil))
+             ;; If syntax is a function symbol, then call it using the
+             ;; defined semantics.
+             (if (and (not (consp (cdr newlines)))
+                      (functionp (cdr newlines)))
+                 (let ((c-syntactic-context syntax))
+                   (setq newlines
+                         (funcall (cdr newlines)
+                                  (car newlines)
+                                  insertion-point))))
+             ;; does a newline go before the open brace?
+             (when (memq 'before newlines)
+               ;; we leave the newline we've put in there before,
+               ;; but we need to re-indent the line above
+               (when delete-temp-newline
+                 (set-marker (car delete-temp-newline) nil)
+                 (set-marker (cdr delete-temp-newline) nil)
+                 (setq delete-temp-newline nil))
+               (when c-syntactic-indentation
+                 (let ((pos (- (point-max) (point)))
+                       (here (point)))
+                   (forward-line -1)
+                   (indent-according-to-mode)
+                   (goto-char (- (point-max) pos))
+                   ;; if the buffer has changed due to the
+                   ;; indentation, we need to recalculate syntax for
+                   ;; the current line.
+                   (if (/= (point) here)
+                       (c-save-buffer-state
+                           ((c-syntactic-indentation-in-macros t)
+                            (c-auto-newline-analysis t))
+                         ;; Turn on syntactic macro analysis to help
+                         ;; with auto newlines only.
+                         (setq syntax (c-guess-basic-syntax))))))))
          ;; must remove the newline we just stuck in (if we really did it)
-         (and delete-temp-newline
-              (save-excursion
-                ;; if there is whitespace before point, then preserve
-                ;; at least one space.
-                (delete-indentation)
-                (just-one-space)
-                (setq c-state-cache (c-whack-state (point) c-state-cache))
-                (if (not preserve-p)
-                    (delete-char -1))))
-         ;; since we're hanging the brace, we need to recalculate
-         ;; syntax.  Update the state to accurately reflect the
-         ;; beginning of the line.  We punt if we cross any open or
-         ;; closed parens because its just too hard to modify the
-         ;; known state.  This limitation will be fixed in v5.
-         (save-excursion
-           (let ((bol (c-point 'bol)))
-             (if (zerop (car (parse-partial-sexp bol (1- (point)))))
-                 (setq syntax (c-guess-basic-syntax))
-               ;; gotta punt. this requires some horrible kludgery
-               (beginning-of-line)
-               (setq c-state-cache nil
-                     c-state-cache (c-parse-state)
-                     syntax nil))))
-         )
-       ;; Now adjust the line's indentation.  Don't update the state
-       ;; cache since c-guess-basic-syntax isn't called when
-       ;; c-syntactic-context is set.
-       (let* ((old-ind (c-point 'boi))
-              (old-point-max (point-max))
-              (c-syntactic-context syntax))
-         (indent-according-to-mode)
-         (setq c-state-cache (c-adjust-state (c-point 'bol) old-point-max
-                                             (- (c-point 'boi) old-ind)
-                                             c-state-cache)))
+         (when delete-temp-newline
+           (save-excursion
+             (delete-region (car delete-temp-newline)
+                            (cdr delete-temp-newline))
+             (goto-char (car delete-temp-newline))
+             (set-marker (car delete-temp-newline) nil)
+             (set-marker (cdr delete-temp-newline) nil)
+             ;; if there is whitespace before point, then preserve
+             ;; at least one space.
+             (just-one-space)
+             (if (not preserve-p)
+                 (delete-char -1)))))
+       (if (not (memq 'before newlines))
+           ;; since we're hanging the brace, we need to recalculate
+           ;; syntax.
+           (c-save-buffer-state ((c-syntactic-indentation-in-macros t)
+                                 (c-auto-newline-analysis t))
+             ;; Turn on syntactic macro analysis to help with auto
+             ;; newlines only.
+             (setq syntax (c-guess-basic-syntax))))
+       (when c-syntactic-indentation
+         ;; Now adjust the line's indentation.  Don't update the state
+         ;; cache since c-guess-basic-syntax isn't called when
+         ;; c-syntactic-context is set.
+         (let* ((c-syntactic-context syntax))
+           (indent-according-to-mode)))
        ;; Do all appropriate clean ups
        (let ((here (point))
              (pos (- (point-max) (point)))
@@ -365,59 +620,66 @@ This function does various newline cleanups based on the value of
                                      syntax)
                   (progn
                     (forward-char -1)
-                    (skip-chars-backward " \t\n")
+                    (c-skip-ws-backward)
                     (eq (char-before) ?\{))
                   ;; make sure matching open brace isn't in a comment
                   (not (c-in-literal)))
              (delete-region (point) (1- here)))
          ;; clean up brace-else-brace and brace-elseif-brace
          (when (and c-auto-newline
-                    (eq last-command-char ?\{)
-                    (not (c-in-literal)))
+                    (eq last-command-char ?\{))
            (cond
             ((and (memq 'brace-else-brace c-cleanup-list)
-                  (re-search-backward "}[ \t\n]*else[ \t\n]*{" nil t)
+                  (re-search-backward
+                   (concat "}"
+                           "\\([ \t\n]\\|\\\\\n\\)*"
+                           "else"
+                           "\\([ \t\n]\\|\\\\\n\\)*"
+                           "{")
+                   nil t)
                   (progn
                     (setq mbeg (match-beginning 0)
                           mend (match-end 0))
                     (eq (match-end 0) here)))
              (delete-region mbeg mend)
-             (insert "} else {"))
+             (insert-and-inherit "} else {"))
             ((and (memq 'brace-elseif-brace c-cleanup-list)
                   (progn
                     (goto-char (1- here))
                     (setq mend (point))
-                    (skip-chars-backward " \t\n")
+                    (c-skip-ws-backward)
                     (setq mbeg (point))
                     (eq (char-before) ?\)))
-                  (= (c-backward-token-1 1 t) 0)
+                  (zerop (c-save-buffer-state nil (c-backward-token-2 1 t)))
                   (eq (char-after) ?\()
                   (progn
                     (setq tmp (point))
-                    (re-search-backward "}[ \t\n]*else[ \t\n]+if[ \t\n]*"
-                                        nil t))
+                    (re-search-backward
+                     (concat "}"
+                             "\\([ \t\n]\\|\\\\\n\\)*"
+                             "else"
+                             "\\([ \t\n]\\|\\\\\n\\)+"
+                             "if"
+                             "\\([ \t\n]\\|\\\\\n\\)*")
+                     nil t))
                   (eq (match-end 0) tmp))
              (delete-region mbeg mend)
              (goto-char mbeg)
-             (insert " "))))
+             (insert ?\ ))))
          (goto-char (- (point-max) pos))
          )
        ;; does a newline go after the brace?
        (if (memq 'after newlines)
-           (progn
-             (newline)
-             ;; update on c-state-cache
-             (let* ((bufpos (- (point) 2))
-                    (which (if (eq (char-after bufpos) ?{) 'open 'close))
-                    (c-state-cache (c-hack-state bufpos which c-state-cache)))
-               (indent-according-to-mode))))
-       ;; blink the paren
-       (and (eq last-command-char ?\})
-            old-blink-paren
-            (save-excursion
-              (c-backward-syntactic-ws safepos)
-              (funcall old-blink-paren)))
-       ))))
+           (c-newline-and-indent))
+       )))
+    ;; blink the paren
+    (and (eq last-command-char ?\})
+        (not executing-kbd-macro)
+        old-blink-paren
+        (save-excursion
+          (c-save-buffer-state nil
+            (c-backward-syntactic-ws safepos))
+          (funcall old-blink-paren)))))
 
 (defun c-electric-slash (arg)
   "Insert a slash character.
@@ -434,13 +696,14 @@ If a numeric ARG is supplied, point is inside a literal, or
 `c-syntactic-indentation' is nil, indentation is inhibited."
   (interactive "*P")
   (let* ((ch (char-before))
+        (literal (c-in-literal))
         (indentp (and c-syntactic-indentation
                       (not arg)
                       (eq last-command-char ?/)
                       (or (and (eq ch ?/)
-                               (not (c-in-literal)))
+                               (not literal))
                           (and (eq ch ?*)
-                               (c-in-literal)))
+                               literal))
                       ))
         ;; shut this up
         (c-echo-syntactic-information-p nil))
@@ -460,7 +723,7 @@ If a numeric ARG is supplied, point is inside a literal, or
   ;; current line, unless this star introduces a comment-only line.
   (if (and c-syntactic-indentation
           (not arg)
-          (memq (c-in-literal) '(c))
+          (eq (c-in-literal) 'c)
           (eq (char-before) ?*)
           (save-excursion
             (forward-char -1)
@@ -480,9 +743,8 @@ or \"/ah\" string on the mode line, a newline might be inserted.  See
 the variable `c-hanging-semi&comma-criteria' for how newline insertion
 is determined.
 
-When semicolon is inserted, the line is re-indented unless a numeric
-arg is supplied, point is inside a literal, or there are
-non-whitespace characters on the line following the semicolon, or
+When a semicolon is inserted, the line is re-indented unless a numeric
+arg is supplied, point is inside a literal, or
 `c-syntactic-indentation' is nil.
 
 Based on the value of `c-cleanup-list', this function cleans up commas
@@ -493,15 +755,14 @@ following brace lists and semicolons following defuns."
         (here (point))
         ;; shut this up
         (c-echo-syntactic-information-p nil))
-    (if (or literal
-           arg
-           (not (looking-at "[ \t]*$")))
+    (if (or literal arg)
        (self-insert-command (prefix-numeric-value arg))
       ;; do some special stuff with the character
       (self-insert-command (prefix-numeric-value arg))
       ;; do all cleanups and newline insertions if c-auto-newline is
       ;; turned on
-      (if (not c-auto-newline)
+      (if (or (not c-auto-newline)
+             (not (looking-at "[ \t]*\\\\?$")))
          (if c-syntactic-indentation
              (indent-according-to-mode))
        ;; clean ups
@@ -514,7 +775,7 @@ following brace lists and semicolons following defuns."
                        (memq 'defun-close-semi c-cleanup-list)))
                   (progn
                     (forward-char -1)
-                    (skip-chars-backward " \t\n")
+                    (c-skip-ws-backward)
                     (eq (char-before) ?}))
                   ;; make sure matching open brace isn't in a comment
                   (not (c-in-literal lim)))
@@ -536,8 +797,7 @@ following brace lists and semicolons following defuns."
              (setq add-newline-p (not (eq answer 'stop)))
              ))
          (if add-newline-p
-             (progn (newline)
-                    (indent-according-to-mode)))
+             (c-newline-and-indent))
          )))))
 
 (defun c-electric-colon (arg)
@@ -547,8 +807,7 @@ If the auto-newline feature is turned on, as evidenced by the \"/a\"
 or \"/ah\" string on the mode line, newlines are inserted before and
 after colons based on the value of `c-hanging-colons-alist'.
 
-Also, the line is re-indented unless a numeric ARG is supplied, there
-are non-whitespace characters present on the line after the colon, the
+Also, the line is re-indented unless a numeric ARG is supplied, the
 colon is inserted inside a literal, or `c-syntactic-indentation' is
 nil.
 
@@ -557,13 +816,17 @@ value of `c-cleanup-list'."
   (interactive "*P")
   (let* ((bod (c-point 'bod))
         (literal (c-in-literal bod))
-        syntax newlines is-scope-op
+        newlines is-scope-op
         ;; shut this up
         (c-echo-syntactic-information-p nil))
-    (if (or literal
-           arg
-           (not (looking-at "[ \t]*$")))
-       (self-insert-command (prefix-numeric-value arg))
+    (cond
+     ((or literal arg)
+      (self-insert-command (prefix-numeric-value arg)))
+     ((not (looking-at "[ \t]*\\\\?$"))
+      (self-insert-command (prefix-numeric-value arg))
+      (if c-syntactic-indentation
+         (indent-according-to-mode)))
+     (t
       ;; insert the colon, then do any specified cleanups
       (self-insert-command (prefix-numeric-value arg))
       (let ((pos (- (point-max) (point)))
@@ -573,7 +836,7 @@ value of `c-cleanup-list'."
                 (eq (char-before) ?:)
                 (progn
                   (forward-char -1)
-                  (skip-chars-backward " \t\n")
+                  (c-skip-ws-backward)
                   (eq (char-before) ?:))
                 (not (c-in-literal))
                 (not (eq (char-after (- (point) 2)) ?:)))
@@ -581,27 +844,38 @@ value of `c-cleanup-list'."
              (delete-region (point) (1- here))
              (setq is-scope-op t)))
        (goto-char (- (point-max) pos)))
-      ;; lets do some special stuff with the colon character
-      (setq syntax (c-guess-basic-syntax)
-           ;; some language elements can only be determined by
-           ;; checking the following line.  Lets first look for ones
-           ;; that can be found when looking on the line with the
-           ;; colon
-           newlines
-           (and c-auto-newline
-                (or (c-lookup-lists '(case-label label access-label)
-                                    syntax c-hanging-colons-alist)
-                    (c-lookup-lists '(member-init-intro inher-intro)
-                                    (let ((buffer-undo-list t))
-                                      (insert "\n")
-                                      (unwind-protect
-                                          (c-guess-basic-syntax)
-                                        (delete-char -1)))
-                                    c-hanging-colons-alist))))
       ;; indent the current line if it's done syntactically.
       (if c-syntactic-indentation
-         (let ((c-syntactic-context syntax))
-           (indent-according-to-mode)))
+         ;; Cannot use the same syntax analysis as we find below,
+         ;; since that's made with c-syntactic-indentation-in-macros
+         ;; always set to t.
+         (indent-according-to-mode))
+      (c-save-buffer-state
+           ((c-syntactic-indentation-in-macros t)
+            (c-auto-newline-analysis t)
+            ;; Turn on syntactic macro analysis to help with auto newlines
+            ;; only.
+            (syntax (c-guess-basic-syntax))
+            (elem syntax))
+       ;; Translate substatement-label to label for this operation.
+       (while elem
+         (if (eq (car (car elem)) 'substatement-label)
+             (setcar (car elem) 'label))
+         (setq elem (cdr elem)))
+       ;; some language elements can only be determined by checking
+       ;; the following line.  Lets first look for ones that can be
+       ;; found when looking on the line with the colon
+       (setq newlines
+             (and c-auto-newline
+                  (or (c-lookup-lists '(case-label label access-label)
+                                      syntax c-hanging-colons-alist)
+                      (c-lookup-lists '(member-init-intro inher-intro)
+                                      (progn
+                                        (insert ?\n)
+                                        (unwind-protect
+                                            (c-guess-basic-syntax)
+                                          (delete-char -1)))
+                                      c-hanging-colons-alist)))))
       ;; does a newline go before the colon?  Watch out for already
       ;; non-hung colons.  However, we don't unhang them because that
       ;; would be a cleanup (and anti-social).
@@ -612,16 +886,13 @@ value of `c-cleanup-list'."
                 (not (bolp))))
          (let ((pos (- (point-max) (point))))
            (forward-char -1)
-           (newline)
-           (indent-according-to-mode)
+           (c-newline-and-indent)
            (goto-char (- (point-max) pos))))
       ;; does a newline go after the colon?
       (if (and (memq 'after (cdr-safe newlines))
               (not is-scope-op))
-         (progn
-           (newline)
-           (indent-according-to-mode)))
-      )))
+         (c-newline-and-indent))
+      ))))
 
 (defun c-electric-lt-gt (arg)
   "Insert a less-than, or greater-than character.
@@ -647,15 +918,14 @@ will not be re-indented."
 Some newline cleanups are done if appropriate; see the variable
 `c-cleanup-list'.
 
-Also, the line is re-indented unless a numeric ARG is supplied, there
-are non-whitespace characters present on the line after the
-parenthesis, the parenthesis is inserted inside a literal, or
-`c-syntactic-indentation' is nil."
+Also, the line is re-indented unless a numeric ARG is supplied, the
+parenthesis is inserted inside a literal, or `c-syntactic-indentation'
+is nil."
   (interactive "*P")
-  (let (;; shut this up
+  (let ((literal (c-in-literal (c-point 'bod)))
+       ;; shut this up
        (c-echo-syntactic-information-p nil))
-    (if (or arg
-           (c-in-literal (c-point 'bod)))
+    (if (or arg literal)
        (self-insert-command (prefix-numeric-value arg))
       ;; do some special stuff with the character
       (let* (;; We want to inhibit blinking the paren since this will
@@ -664,9 +934,9 @@ parenthesis, the parenthesis is inserted inside a literal, or
             (old-blink-paren blink-paren-function)
             blink-paren-function)
        (self-insert-command (prefix-numeric-value arg))
-       (when (looking-at "[ \t]*$")
-         (if c-syntactic-indentation
-             (indent-according-to-mode))
+       (if c-syntactic-indentation
+           (indent-according-to-mode))
+       (when (looking-at "[ \t]*\\\\?$")
          (when c-auto-newline
            ;; Do all appropriate clean ups
            (let ((here (point))
@@ -675,8 +945,15 @@ parenthesis, the parenthesis is inserted inside a literal, or
              ;; clean up brace-elseif-brace
              (if (and (memq 'brace-elseif-brace c-cleanup-list)
                       (eq last-command-char ?\()
-                      (re-search-backward "}[ \t\n]*else[ \t\n]+if[ \t\n]*("
-                                          nil t)
+                      (re-search-backward
+                       (concat "}"
+                               "\\([ \t\n]\\|\\\\\n\\)*"
+                               "else"
+                               "\\([ \t\n]\\|\\\\\n\\)+"
+                               "if"
+                               "\\([ \t\n]\\|\\\\\n\\)*"
+                               "(")
+                       nil t)
                       (save-excursion
                         (setq mbeg (match-beginning 0)
                               mend (match-end 0))
@@ -684,19 +961,26 @@ parenthesis, the parenthesis is inserted inside a literal, or
                       (not (c-in-literal)))
                  (progn
                    (delete-region mbeg mend)
-                   (insert "} else if (")))
-             ;; clean up brace-catch-brace
-             (if (and (memq 'brace-catch-brace c-cleanup-list)
-                      (eq last-command-char ?\()
-                      (re-search-backward "}[ \t\n]*catch[ \t\n]*(" nil t)
-                      (save-excursion
-                        (setq mbeg (match-beginning 0)
-                              mend (match-end 0))
-                        (= mend here))
-                      (not (c-in-literal)))
-                 (progn
-                   (delete-region mbeg mend)
-                   (insert "} catch (")))
+                   (insert-and-inherit "} else if ("))
+               ;; clean up brace-catch-brace
+               (goto-char here)
+               (if (and (memq 'brace-catch-brace c-cleanup-list)
+                        (eq last-command-char ?\()
+                        (re-search-backward
+                         (concat "}"
+                                 "\\([ \t\n]\\|\\\\\n\\)*"
+                                 "catch"
+                                 "\\([ \t\n]\\|\\\\\n\\)*"
+                                 "(")
+                         nil t)
+                        (save-excursion
+                          (setq mbeg (match-beginning 0)
+                                mend (match-end 0))
+                          (= mend here))
+                        (not (c-in-literal)))
+                   (progn
+                     (delete-region mbeg mend)
+                     (insert-and-inherit "} catch ("))))
              (goto-char (- (point-max) pos))
              )))
        (let (beg (end (1- (point))))
@@ -710,7 +994,7 @@ parenthesis, the parenthesis is inserted inside a literal, or
                 (save-excursion
                   (delete-region beg end)
                   (goto-char beg)
-                  (insert " ")))
+                  (insert ?\ )))
                ((and (memq 'compact-empty-funcall c-cleanup-list)
                      (eq last-command-char ?\))
                      (save-excursion
@@ -721,8 +1005,9 @@ parenthesis, the parenthesis is inserted inside a literal, or
                          (setq beg (point))
                          (c-on-identifier))))
                 (delete-region beg end))))
-       (if old-blink-paren
-           (funcall old-blink-paren))))))
+       (and (not executing-kbd-macro)
+            old-blink-paren
+            (funcall old-blink-paren))))))
 
 (defun c-electric-continued-statement ()
   "Reindent the current line if appropriate.
@@ -743,21 +1028,35 @@ keyword on the line, the keyword is not inserted inside a literal, and
                    (point))
                  (c-point 'boi))
               (not (c-in-literal (c-point 'bod))))
-      (indent-according-to-mode))))
+      ;; Have to temporarily insert a space so that
+      ;; c-guess-basic-syntax recognizes the keyword.  Follow the
+      ;; space with a nonspace to avoid messing up any whitespace
+      ;; sensitive meddling that might be done, e.g. by
+      ;; `c-backslash-region'.
+      (insert-and-inherit " x")
+      (unwind-protect
+         (indent-according-to-mode)
+       (delete-char -2)))))
 
 \f
 ;; better movement routines for ThisStyleOfVariablesCommonInCPlusPlus
 ;; originally contributed by Terry_Glanfield.Southern@rxuk.xerox.com
 (defun c-forward-into-nomenclature (&optional arg)
   "Move forward to end of a nomenclature section or word.
-With arg, to it arg times."
+With arg, do it arg times."
   (interactive "p")
   (let ((case-fold-search nil))
     (if (> arg 0)
-       (re-search-forward "\\W*\\([A-Z]*[a-z0-9]*\\)" (point-max) t arg)
+       (re-search-forward
+        (cc-eval-when-compile
+          (concat "\\W*\\([" c-upper "]*[" c-lower c-digit "]*\\)"))
+        (point-max) t arg)
       (while (and (< arg 0)
                  (re-search-backward
-                  "\\(\\(\\W\\|[a-z0-9]\\)[A-Z]+\\|\\W\\w+\\)"
+                  (cc-eval-when-compile
+                    (concat
+                     "\\(\\(\\W\\|[" c-lower c-digit "]\\)[" c-upper "]+"
+                     "\\|\\W\\w+\\)"))
                   (point-min) 0))
        (forward-char 1)
        (setq arg (1+ arg)))))
@@ -775,72 +1074,323 @@ forward."
   "Insert a double colon scope operator at point.
 No indentation or other \"electric\" behavior is performed."
   (interactive "*")
-  (insert "::"))
+  (insert-and-inherit "::"))
 
 (defun c-beginning-of-defun (&optional arg)
   "Move backward to the beginning of a defun.
-With argument, do it that many times.  Negative arg -N
-means move forward to Nth following beginning of defun.
-Returns t unless search stops due to beginning or end of buffer.
+Every top level declaration that contains a brace paren block is
+considered to be a defun.
+
+With a positive argument, move backward that many defuns.  A negative
+argument -N means move forward to the Nth following beginning.  Return
+t unless search stops due to beginning or end of buffer.
 
 Unlike the built-in `beginning-of-defun' this tries to be smarter
 about finding the char with open-parenthesis syntax that starts the
 defun."
+
   (interactive "p")
-  (unless arg (setq arg 1))
+  (or arg (setq arg 1))
+
   (if (< arg 0)
-      (c-end-of-defun (- arg))
-    (while (> arg 0)
-      (let ((state (nreverse (c-parse-state)))
-           prevbod bod)
-       (while (and state (not bod))
-         (setq bod (car state)
-               state (cdr state))
-         (if (consp bod)
-             (setq prevbod (car bod)
-                   bod nil)))
-       (cond
-        (bod (goto-char bod))
-        (prevbod (goto-char prevbod))
-        (t (goto-char (point-min))
-           (setq arg 0)))
-       (setq arg (1- arg))))
+      (when (c-end-of-defun (- arg))
+       (c-save-buffer-state nil (c-forward-syntactic-ws))
+       t)
+
+    (c-save-buffer-state (paren-state lim pos)
+      (catch 'exit
+       (while (> arg 0)
+         ;; Note: Partial code duplication in `c-end-of-defun' and
+         ;; `c-declaration-limits'.
+
+         (setq paren-state (c-parse-state))
+         (unless (c-safe
+                   (goto-char (c-least-enclosing-brace paren-state))
+                   ;; If we moved to the outermost enclosing paren
+                   ;; then we can use c-safe-position to set the
+                   ;; limit.  Can't do that otherwise since the
+                   ;; earlier paren pair on paren-state might very
+                   ;; well be part of the declaration we should go
+                   ;; to.
+                   (setq lim (c-safe-position (point) paren-state))
+                   t)
+           ;; At top level.  Make sure we aren't inside a literal.
+           (setq pos (c-literal-limits
+                      (c-safe-position (point) paren-state)))
+           (if pos (goto-char (car pos))))
+
+         (while (let ((start (point)))
+                  (c-beginning-of-decl-1 lim)
+                  (if (= (point) start)
+                      ;; Didn't move.  Might be due to bob or unbalanced
+                      ;; parens.  Try to continue if it's the latter.
+                      (unless (c-safe (goto-char
+                                       (c-down-list-backward (point))))
+                        ;; Didn't work, so it's bob then.
+                        (goto-char (point-min))
+                        (throw 'exit nil)))
+
+                  (save-excursion
+                    ;; Check if the declaration contains a brace
+                    ;; block.  If not, we try another one.
+                    (setq pos (point))
+                    (not (and (c-syntactic-re-search-forward "[;{]" nil t t)
+                              (or (eq (char-before) ?{)
+                                  (and c-recognize-knr-p
+                                       ;; Might have stopped on the
+                                       ;; ';' in a K&R argdecl.  In
+                                       ;; that case the declaration
+                                       ;; should contain a block.
+                                       (c-in-knr-argdecl pos)))))))
+           (setq lim nil))
+
+         ;; Check if `c-beginning-of-decl-1' put us after the block
+         ;; in a declaration that doesn't end there.  We're searching
+         ;; back and forth over the block here, which can be
+         ;; expensive.
+         (setq pos (point))
+         (if (and c-opt-block-decls-with-vars-key
+                  (progn
+                    (c-backward-syntactic-ws)
+                    (eq (char-before) ?}))
+                  (eq (car (c-beginning-of-decl-1))
+                      'previous)
+                  (save-excursion
+                    (c-end-of-decl-1)
+                    (> (point) pos)))
+             nil
+           (goto-char pos))
+
+         (setq pos (point))
+         ;; Try to be line oriented; position point at the closest
+         ;; preceding boi that isn't inside a comment, but if we hit
+         ;; the previous declaration then we use the current point
+         ;; instead.
+         (while (and (/= (point) (c-point 'boi))
+                     (c-backward-single-comment)))
+         (if (/= (point) (c-point 'boi))
+             (goto-char pos))
+
+         (setq arg (1- arg)))))
     (c-keep-region-active)
     (= arg 0)))
 
 (defun c-end-of-defun (&optional arg)
-  "Move forward to next end of defun.  With argument, do it that many times.
-Negative argument -N means move back to Nth preceding end of defun.
-Returns t unless search stops due to beginning or end of buffer.
+  "Move forward to the end of a top level declaration.
+With argument, do it that many times.  Negative argument -N means move
+back to Nth preceding end.  Returns t unless search stops due to
+beginning or end of buffer.
 
 An end of a defun occurs right after the close-parenthesis that matches
 the open-parenthesis that starts a defun; see `beginning-of-defun'."
+
   (interactive "p")
-  (if (not arg)
-      (setq arg 1))
+  (or arg (setq arg 1))
+
   (if (< arg 0)
-      (c-beginning-of-defun (- arg))
-    (while (> arg 0)
-      (let ((pos (point))
-           eol)
-       (while (and (c-safe (down-list 1) t)
-                   (not (eq (char-before) ?{)))
-         ;; skip down into the next defun-block
-         (forward-char -1)
-         (c-forward-sexp))
-       (c-beginning-of-defun 1)
-       (setq eol (c-point 'eol))
-       (c-forward-sexp)
-       (if (< eol (point))
-           ;; Don't move to next line for one line defuns.
-           (forward-line 1))
-       (when (<= (point) pos)
-         (goto-char (point-max))
-         (setq arg 0))
-       (setq arg (1- arg))))
+      (when (c-beginning-of-defun (- arg))
+       (c-save-buffer-state nil (c-backward-syntactic-ws))
+       t)
+
+    (c-save-buffer-state (paren-state lim pos)
+      (catch 'exit
+       (while (> arg 0)
+         ;; Note: Partial code duplication in `c-beginning-of-defun'
+         ;; and `c-declaration-limits'.
+
+         (setq paren-state (c-parse-state))
+         (unless (c-safe
+                   (goto-char (c-least-enclosing-brace paren-state))
+                   ;; If we moved to the outermost enclosing paren
+                   ;; then we can use c-safe-position to set the
+                   ;; limit.  Can't do that otherwise since the
+                   ;; earlier paren pair on paren-state might very
+                   ;; well be part of the declaration we should go
+                   ;; to.
+                   (setq lim (c-safe-position (point) paren-state))
+                   t)
+           ;; At top level.  Make sure we aren't inside a literal.
+           (setq pos (car-safe (c-literal-limits
+                                (c-safe-position (point) paren-state))))
+           (if pos (goto-char pos)))
+
+         ;; Have to move to the start first so that `c-end-of-decl-1'
+         ;; has the correct start position.
+         (setq pos (point))
+         (when (memq (car (c-beginning-of-decl-1 lim))
+                     '(previous macro))
+           ;; We moved back over the previous defun or a macro.  Move
+           ;; to the next token; it's the start of the next
+           ;; declaration.  We can also be directly after the block
+           ;; in a `c-opt-block-decls-with-vars-key' declaration, but
+           ;; then we won't move significantly far here.
+           (goto-char pos)
+           (c-forward-token-2 0))
+
+         (while (let ((start (point)))
+                  (c-end-of-decl-1)
+                  (if (= (point) start)
+                      ;; Didn't move.  Might be due to eob or unbalanced
+                      ;; parens.  Try to continue if it's the latter.
+                      (if (c-safe (goto-char (c-up-list-forward (point))))
+                          t
+                        ;; Didn't work, so it's eob then.
+                        (goto-char (point-max))
+                        (throw 'exit nil))
+
+                    (save-excursion
+                      ;; Check if the declaration contains a brace
+                      ;; block.  If not, we try another one.
+                      (setq pos (point))
+                      (goto-char start)
+                      (not (c-syntactic-re-search-forward "{" pos t t))))))
+
+         (setq pos (point))
+         ;; Try to be line oriented; position point after the next
+         ;; newline that isn't inside a comment, but if we hit the
+         ;; next declaration then we use the current point instead.
+         (while (and (not (bolp))
+                     (not (looking-at "\\s *$"))
+                     (c-forward-single-comment)))
+         (cond ((bolp))
+               ((looking-at "\\s *$")
+                (forward-line 1))
+               (t
+                (goto-char pos)))
+
+         (setq arg (1- arg)))))
     (c-keep-region-active)
     (= arg 0)))
 
+(defun c-declaration-limits (near)
+  ;; Return a cons of the beginning and end positions of the current
+  ;; top level declaration or macro.  If point is not inside any then
+  ;; nil is returned, unless NEAR is non-nil in which case the closest
+  ;; following one is chosen instead (if there is any).  The end
+  ;; position is at the next line, providing there is one before the
+  ;; declaration.
+  (save-excursion
+
+    ;; Note: Some code duplication in `c-beginning-of-defun' and
+    ;; `c-end-of-defun'.
+    (catch 'exit
+      (let ((start (point))
+           (paren-state (c-parse-state))
+           lim pos end-pos)
+       (unless (c-safe
+                 (goto-char (c-least-enclosing-brace paren-state))
+                 ;; If we moved to the outermost enclosing paren then we
+                 ;; can use c-safe-position to set the limit.  Can't do
+                 ;; that otherwise since the earlier paren pair on
+                 ;; paren-state might very well be part of the
+                 ;; declaration we should go to.
+                 (setq lim (c-safe-position (point) paren-state))
+                 t)
+         ;; At top level.  Make sure we aren't inside a literal.
+         (setq pos (c-literal-limits
+                    (c-safe-position (point) paren-state)))
+         (if pos (goto-char (car pos))))
+
+       (when (c-beginning-of-macro)
+         (throw 'exit
+                (cons (point)
+                      (save-excursion
+                        (c-end-of-macro)
+                        (forward-line 1)
+                        (point)))))
+
+       (setq pos (point))
+       (when (or (eq (car (c-beginning-of-decl-1 lim)) 'previous)
+                 (= pos (point)))
+         ;; We moved back over the previous defun.  Skip to the next
+         ;; one.  Not using c-forward-syntactic-ws here since we
+         ;; should not skip a macro.  We can also be directly after
+         ;; the block in a `c-opt-block-decls-with-vars-key'
+         ;; declaration, but then we won't move significantly far
+         ;; here.
+         (goto-char pos)
+         (c-forward-comments)
+
+         (when (and near (c-beginning-of-macro))
+           (throw 'exit
+                  (cons (point)
+                        (save-excursion
+                          (c-end-of-macro)
+                          (forward-line 1)
+                          (point))))))
+
+       (if (eobp) (throw 'exit nil))
+
+       ;; Check if `c-beginning-of-decl-1' put us after the block in a
+       ;; declaration that doesn't end there.  We're searching back and
+       ;; forth over the block here, which can be expensive.
+       (setq pos (point))
+       (if (and c-opt-block-decls-with-vars-key
+                (progn
+                  (c-backward-syntactic-ws)
+                  (eq (char-before) ?}))
+                (eq (car (c-beginning-of-decl-1))
+                    'previous)
+                (save-excursion
+                  (c-end-of-decl-1)
+                  (and (> (point) pos)
+                       (setq end-pos (point)))))
+           nil
+         (goto-char pos))
+
+       (if (and (not near) (> (point) start))
+           nil
+
+         ;; Try to be line oriented; position the limits at the
+         ;; closest preceding boi, and after the next newline, that
+         ;; isn't inside a comment, but if we hit a neighboring
+         ;; declaration then we instead use the exact declaration
+         ;; limit in that direction.
+         (cons (progn
+                 (setq pos (point))
+                 (while (and (/= (point) (c-point 'boi))
+                             (c-backward-single-comment)))
+                 (if (/= (point) (c-point 'boi))
+                     pos
+                   (point)))
+               (progn
+                 (if end-pos
+                     (goto-char end-pos)
+                   (c-end-of-decl-1))
+                 (setq pos (point))
+                 (while (and (not (bolp))
+                             (not (looking-at "\\s *$"))
+                             (c-forward-single-comment)))
+                 (cond ((bolp)
+                        (point))
+                       ((looking-at "\\s *$")
+                        (forward-line 1)
+                        (point))
+                       (t
+                        pos)))))
+       ))))
+
+(defun c-mark-function ()
+  "Put mark at end of the current top-level declaration or macro, point at beginning.
+If point is not inside any then the closest following one is chosen.
+
+As opposed to \\[c-beginning-of-defun] and \\[c-end-of-defun], this
+function does not require the declaration to contain a brace block."
+  (interactive)
+
+  (let (decl-limits)
+    (c-save-buffer-state nil
+      ;; We try to be line oriented, unless there are several
+      ;; declarations on the same line.
+      (if (looking-at c-syntactic-eol)
+         (c-backward-token-2 1 nil (c-point 'bol)))
+      (setq decl-limits (c-declaration-limits t)))
+
+    (if (not decl-limits)
+       (error "Cannot find any declaration")
+      (goto-char (car decl-limits))
+      (push-mark (cdr decl-limits) nil t))))
+
 \f
 (defun c-beginning-of-statement (&optional count lim sentence-flag)
   "Go to the beginning of the innermost C statement.
@@ -853,12 +1403,18 @@ comment or multiline string, move by sentences instead of statements.
 When called from a program, this function takes 3 optional args: the
 repetition count, a buffer position limit which is the farthest back
 to search for the syntactic context, and a flag saying whether to do
-sentence motion in or near comments and multiline strings."
+sentence motion in or near comments and multiline strings.
+
+Note that `c-beginning-of-statement-1' is usually better to use from
+programs.  It has much more well defined semantics than this one,
+which is intended for interactive use and might therefore change to be
+more \"DWIM:ey\"."
   (interactive (list (prefix-numeric-value current-prefix-arg)
                     nil t))
-  (let* ((count (or count 1))
-        here
-        (range (c-collect-line-comments (c-literal-limits lim))))
+  (c-save-buffer-state
+      ((count (or count 1))
+       here
+       (range (c-collect-line-comments (c-literal-limits lim))))
     (while (and (/= count 0)
                (or (not lim) (> (point) lim)))
       (setq here (point))
@@ -866,24 +1422,24 @@ sentence motion in or near comments and multiline strings."
          (save-excursion
            ;; Find the comment next to point if we're not in one.
            (if (> count 0)
-               (if (c-forward-comment -1)
+               (if (c-backward-single-comment)
                    (setq range (cons (point)
-                                     (progn (c-forward-comment 1) (point))))
-                 (skip-chars-backward " \t\n\r\f")
+                                     (progn (c-forward-single-comment)
+                                            (point))))
+                 (c-skip-ws-backward)
                  (setq range (point))
                  (setq range
                        (if (eq (char-before) ?\")
                            (c-safe (c-backward-sexp 1)
                                    (cons (point) range)))))
-             ;; skip-syntax-* doesn't count \n as whitespace..
-             (skip-chars-forward " \t\n\r\f")
+             (c-skip-ws-forward)
              (if (eq (char-after) ?\")
                  (setq range (cons (point)
                                    (progn
                                      (c-forward-sexp 1)
                                      (point))))
                (setq range (point))
-               (setq range (if (c-forward-comment 1)
+               (setq range (if (c-forward-single-comment)
                                (cons range (point))
                              nil))))
            (setq range (c-collect-line-comments range))))
@@ -982,7 +1538,7 @@ sentence motion in or near comments and multiline strings."
                                      (bolp))
                              (goto-char (cdr range)))))
                      (when (and (eq (point) (point-min))
-                                (looking-at "[ \t]*$"))
+                                (looking-at "[ \t]*\\\\?$"))
                        ;; Stop before instead of after the comment
                        ;; starter if nothing follows it.
                        (widen)
@@ -1002,10 +1558,6 @@ sentence motion in or near comments and multiline strings."
                    (setq range nil))))
            (goto-char (if (> count 0) (car range) (cdr range)))
            (setq range nil))
-       ;; Below we do approximately the same as
-       ;; c-beginning-of-statement-1 and c-end-of-statement-1, and
-       ;; perhaps they should be changed, but that'd likely break a
-       ;; lot in cc-engine.
        (goto-char here)
        (if (> count 0)
            (condition-case nil
@@ -1015,7 +1567,6 @@ sentence motion in or near comments and multiline strings."
                ;; into parens.  Also stop before `#' when it's at boi
                ;; on a line.
                (let ((literal-pos (not sentence-flag))
-                     (large-enough (- (point-max)))
                      last last-below-line)
                  (catch 'done
                    (while t
@@ -1033,14 +1584,18 @@ sentence motion in or near comments and multiline strings."
                                   (not (eq last-below-line here)))
                              (goto-char last-below-line))
                          (throw 'done t)))
+                     ;; Don't know why I added the following, but it
+                     ;; doesn't work when point is preceded by a line
+                     ;; style comment. /mast
+                     ;;(c-skip-ws-backward)
                      (if literal-pos
-                         (c-forward-comment large-enough)
-                       (when (c-forward-comment -1)
+                         (c-backward-comments)
+                       (when (c-backward-single-comment)
                          ;; Record position of first comment.
                          (save-excursion
-                           (c-forward-comment 1)
+                           (c-forward-single-comment)
                            (setq literal-pos (point)))
-                         (c-forward-comment large-enough)))
+                         (c-backward-comments)))
                      (unless last-below-line
                        (if (save-excursion
                              (re-search-forward "\\(^\\|[^\\]\\)$" last t))
@@ -1092,19 +1647,18 @@ sentence motion in or near comments and multiline strings."
              ;; and move into parens.  Also stop at eol of lines
              ;; with `#' at the boi.
              (let ((literal-pos (not sentence-flag))
-                   (large-enough (point-max))
                    last)
                (catch 'done
                  (while t
                    (setq last (point))
                    (if literal-pos
-                       (c-forward-comment large-enough)
+                       (c-forward-comments)
                      (if (progn
-                           (skip-chars-forward " \t\n\r\f")
+                           (c-skip-ws-forward)
                            ;; Record position of first comment.
                            (setq literal-pos (point))
-                           (c-forward-comment 1))
-                         (c-forward-comment large-enough)
+                           (c-forward-single-comment))
+                         (c-forward-comments)
                        (setq literal-pos nil)))
                    (cond ((and (eq (char-after) ?{)
                                (not (and c-special-brace-lists
@@ -1126,13 +1680,13 @@ sentence motion in or near comments and multiline strings."
                                (/= here last))
                           (goto-char last)
                           (throw 'done t))
-                         ((and (eq (char-after) ?#)
-                               (= (point) (c-point 'boi)))
-                          (if (= here last)
-                              (or (re-search-forward "\\(^\\|[^\\]\\)$" nil t)
-                                  (goto-char (point-max)))
-                            (goto-char last))
-                          (throw 'done t))
+;                        ((and (eq (char-after) ?#)
+;                              (= (point) (c-point 'boi)))
+;                         (if (= here last)
+;                             (or (re-search-forward "\\(^\\|[^\\]\\)$" nil t)
+;                                 (goto-char (point-max)))
+;                           (goto-char last))
+;                         (throw 'done t))
                          ((looking-at ";\\|};?")
                           (goto-char (match-end 0))
                           (throw 'done t))
@@ -1201,38 +1755,76 @@ sentence motion in or near comments and multiline strings."
 (put 'c-electric-delete    'pending-delete   'supersede) ; pending-del
 (put 'c-electric-backspace 'delete-selection 'supersede) ; delsel
 (put 'c-electric-backspace 'pending-delete   'supersede) ; pending-del
+(put 'c-electric-delete-forward 'delete-selection 'supersede) ; delsel
+(put 'c-electric-delete-forward 'pending-delete   'supersede) ; pending-del
 
 \f
-;; This is used by indent-for-comment to decide how much to indent a
-;; comment in C code based on its context.
+(defun c-calc-comment-indent (entry)
+  (if (symbolp entry)
+      (setq entry (or (assq entry c-indent-comment-alist)
+                     (assq 'other c-indent-comment-alist)
+                     '(default . (column . nil)))))
+  (let ((action (car (cdr entry)))
+       (value (cdr (cdr entry)))
+       (col (current-column)))
+    (cond ((eq action 'space)
+          (+ col value))
+         ((eq action 'column)
+          (unless value (setq value comment-column))
+          (if (bolp)
+              ;; Do not pad with one space if we're at bol.
+              value
+            (max (1+ col) value)))
+         ((eq action 'align)
+          (or (save-excursion
+                (beginning-of-line)
+                (unless (bobp)
+                  (backward-char)
+                  (let ((lim (c-literal-limits (c-point 'bol) t)))
+                    (when (consp lim)
+                      (goto-char (car lim))
+                      (when (looking-at "/[/*]")
+                        ;; Found comment to align with.
+                        (if (bolp)
+                            ;; Do not pad with one space if we're at bol.
+                            0
+                          (max (1+ col) (current-column))))))))
+              ;; Recurse to handle value as a new spec.
+              (c-calc-comment-indent (cdr entry)))))))
+
 (defun c-comment-indent ()
-  (if (looking-at (concat "^\\(" c-comment-start-regexp "\\)"))
-      0                                ;Existing comment at bol stays there.
-    (let ((opoint (point))
-         placeholder)
-      (save-excursion
-       (beginning-of-line)
-       (cond
-        ;; CASE 1: A comment following a solitary close-brace should
-        ;; have only one space.
-        ((looking-at (concat "[ \t]*}[ \t]*\\($\\|"
-                             c-comment-start-regexp
-                             "\\)"))
-         (search-forward "}")
-         (1+ (current-column)))
-        ;; CASE 2: 2 spaces after #endif
-        ((or (looking-at "[ \t]*#[ \t]*endif[ \t]*")
-             (looking-at "[ \t]*#[ \t]*else[ \t]*"))
-         7)
-        ;; CASE 3: when c-indent-comments-syntactically-p is t,
-        ;; calculate the offset according to c-offsets-alist.
-        ;; E.g. identical to hitting TAB.
-        ((and c-indent-comments-syntactically-p
-              (save-excursion
-                (skip-chars-forward " \t")
-                (or (looking-at c-comment-start-regexp)
-                    (eolp))))
-         (let ((syntax (c-guess-basic-syntax)))
+  "Used by `indent-for-comment' to create and indent comments.
+See `c-indent-comment-alist' for a description."
+  (save-excursion
+    (end-of-line)
+    (c-save-buffer-state
+         ((eot (let ((lim (c-literal-limits (c-point 'bol) t)))
+                 (or (when (consp lim)
+                       (goto-char (car lim))
+                       (when (looking-at "/[/*]")
+                         (skip-chars-backward " \t")
+                         (point)))
+                     (progn
+                       (skip-chars-backward " \t")
+                       (point)))))
+          (line-type
+           (cond ((looking-at "^/[/*]")
+                  'anchored-comment)
+                 ((progn (beginning-of-line)
+                         (eq (point) eot))
+                  'empty-line)
+                 ((progn (back-to-indentation)
+                         (and (eq (char-after) ?})
+                              (eq (point) (1- eot))))
+                  'end-block)
+                 ((and (looking-at "#[ \t]*\\(endif\\|else\\)")
+                       (eq (match-end 0) eot))
+                  'cpp-end-block)
+                 (t
+                  'other))))
+      (if (and (memq line-type '(anchored-comment empty-line))
+              c-indent-comments-syntactically-p)
+         (let ((c-syntactic-context (c-guess-basic-syntax)))
            ;; BOGOSITY ALERT: if we're looking at the eol, its
            ;; because indent-for-comment hasn't put the comment-start
            ;; in the buffer yet.  this will screw up the syntactic
@@ -1240,51 +1832,22 @@ sentence motion in or near comments and multiline strings."
            ;; kludge is that if we're at the bol, then we really want
            ;; to ignore any anchoring as specified by
            ;; c-comment-only-line-offset since it doesn't apply here.
-           (if (save-excursion
-                 (back-to-indentation)
-                 (eolp))
+           (if (eolp)
                (c-add-syntax 'comment-intro))
            (let ((c-comment-only-line-offset
                   (if (consp c-comment-only-line-offset)
                       c-comment-only-line-offset
                     (cons c-comment-only-line-offset
                           c-comment-only-line-offset))))
-             (c-get-syntactic-indentation syntax))))
-        ;; CASE 4: If previous line is a comment-only line, use its
-        ;; indentation if it's greater than comment-column.  Leave at
-        ;; least one space between the comment and the last nonblank
-        ;; character in any case.
-        ((save-excursion
-           (beginning-of-line)
-           (and (not (bobp))
-                (forward-line -1))
-           (skip-chars-forward " \t")
-           (prog1
-               (looking-at c-comment-start-regexp)
-             (setq placeholder (current-column))))
-         (goto-char opoint)
-         (skip-chars-backward " \t")
-         (max (if (bolp) 0 (1+ (current-column)))
-              placeholder
-              comment-column))
-        ;; CASE 5: If comment-column is 0, and nothing but space
-        ;; before the comment, align it at 0 rather than 1.
-        ((progn
-           (goto-char opoint)
-           (skip-chars-backward " \t")
-           (and (= comment-column 0) (bolp)))
-         0)
-        ;; CASE 6: indent at comment column except leave at least one
-        ;; space.
-        (t (max (1+ (current-column))
-                comment-column))
-        )))))
+             (c-get-syntactic-indentation c-syntactic-context)))
+       (goto-char eot)
+       (c-calc-comment-indent line-type)))))
 
 \f
 ;; used by outline-minor-mode
 (defun c-outline-level ()
-  ;; This so that `current-column' DTRT in otherwise-hidden text.
-  (let (buffer-invisibility-spec)
+  (let (buffer-invisibility-spec);; This so that `current-column' DTRT
+                                ;; in otherwise-hidden text.
     (save-excursion
       (skip-chars-forward "\t ")
       (current-column))))
@@ -1441,16 +2004,16 @@ literals (comments and strings) and inside preprocessor directives,
 but the line is always reindented.
 
 If `c-syntactic-indentation' is t, indentation is done according to
-the syntactic context.  If it's nil, the line is just indented one
+the syntactic context.  A numeric argument, regardless of its value,
+means indent rigidly all the lines of the expression starting after
+point so that this line becomes properly indented.  The relative
+indentation among the lines of the expression is preserved.
+
+If `c-syntactic-indentation' is nil, the line is just indented one
 step according to `c-basic-offset'.  In this mode, a numeric argument
 indents a number of such steps, positive or negative, and an empty
 prefix argument is equivalent to -1.
 
-If `c-syntactic-indentation' is t, then a numeric argument, regardless
-of its value, means indent rigidly all the lines of the expression
-starting after point so that this line becomes properly indented.  The
-relative indentation among the lines of the expression is preserved.
-
   [*] The amount and kind of whitespace inserted is controlled by the
   variable `c-insert-tab-function', which is called to do the actual
   insertion of whitespace.  Normally the function in this variable
@@ -1458,15 +2021,22 @@ relative indentation among the lines of the expression is preserved.
   depending on the variable `indent-tabs-mode'."
 
   (interactive "p")
-  (let ((bod (c-point 'bod))
-       (indent-function
+  (let ((indent-function
         (if c-syntactic-indentation
             (symbol-function 'indent-according-to-mode)
           (lambda ()
-            (let ((steps (cond ((not current-prefix-arg) 1)
+            (let ((c-macro-start c-macro-start)
+                  (steps (cond ((not current-prefix-arg) 1)
                                ((equal current-prefix-arg '(4)) -1)
                                (t arg))))
-              (c-shift-line-indentation (* steps c-basic-offset)))
+              (c-shift-line-indentation (* steps c-basic-offset))
+              (when (and c-auto-align-backslashes
+                         (save-excursion
+                           (end-of-line)
+                           (eq (char-before) ?\\))
+                         (c-query-and-set-macro-start))
+                ;; Realign the line continuation backslash if inside a macro.
+                (c-backslash-region (point) (point) nil t)))
             ))))
     (if (and c-syntactic-indentation current-prefix-arg)
        ;; If c-syntactic-indentation and got arg, always indent this
@@ -1508,7 +2078,7 @@ relative indentation among the lines of the expression is preserved.
        ;; CASE 3: if in a literal, insert a tab, but always indent the
        ;; line
        (t
-       (if (c-in-literal bod)
+       (if (c-in-literal)
            (funcall c-insert-tab-function))
        (funcall indent-function)
        )))))
@@ -1522,68 +2092,77 @@ balanced expression is found."
        end)
     (set-marker-insertion-type here t)
     (unwind-protect
-       (let ((start (progn
-                      ;; try to be smarter about finding the range of
-                      ;; lines to indent. skip all following
-                      ;; whitespace, then try to find any
-                      ;; opening paren on the current line
-                      (skip-chars-forward " \t\n")
-                      (save-restriction
-                        (narrow-to-region (point-min) (c-point 'eol))
-                        (c-safe (1- (scan-lists (point) 1 -1)))))))
-         ;; find balanced expression end
-         (setq end (and (c-safe (progn (c-forward-sexp 1) t))
-                        (point)))
+       (let ((start (save-restriction
+                      ;; Find the closest following open paren that
+                      ;; ends on another line.
+                      (narrow-to-region (point-min) (c-point 'eol))
+                      (let (beg (end (point)))
+                        (while (and (setq beg (c-down-list-forward end))
+                                    (setq end (c-up-list-forward beg))))
+                        (and beg
+                             (eq (char-syntax (char-before beg)) ?\()
+                             (1- beg))))))
          ;; sanity check
          (if (not start)
             (unless shutup-p
               (error "Cannot find start of balanced expression to indent"))
+           (goto-char start)
+           (setq end (c-safe (scan-sexps (point) 1)))
            (if (not end)
                (unless shutup-p
                  (error "Cannot find end of balanced expression to indent"))
-             (c-indent-region start end))))
+             (forward-line)
+             (if (< (point) end)
+                 (c-indent-region (point) end)))))
       (goto-char here)
       (set-marker here nil))))
 
 (defun c-indent-defun ()
-  "Indent the current top-level function def, struct or class declaration
-syntactically."
+  "Indent the current top-level declaration or macro syntactically.
+In the macro case this also has the effect of realigning any line
+continuation backslashes, unless `c-auto-align-backslashes' is nil."
   (interactive "*")
-  (let ((here (point-marker))
-       (c-echo-syntactic-information-p nil)
-       (brace (c-least-enclosing-brace (c-parse-state))))
-    (goto-char (or brace (c-point 'bod)))
-    ;; if we're sitting at b-o-b, it might be because there was no
-    ;; least enclosing brace and we were sitting on the defun's open
-    ;; brace.
-    (if (and (bobp) (not (eq (char-after) ?\{)))
-       (goto-char here))
-    ;; if defun-prompt-regexp is non-nil, b-o-d might not leave us at
-    ;; the open brace. I consider this an Emacs bug.
-    (and (boundp 'defun-prompt-regexp)
-        defun-prompt-regexp
-        (looking-at defun-prompt-regexp)
-        (goto-char (match-end 0)))
-    ;; catch all errors in c-indent-exp so we can 1. give more
-    ;; meaningful error message, and 2. restore point
+  (let ((here (point-marker)) decl-limits)
     (unwind-protect
-       (c-indent-exp)
+       (progn
+         (c-save-buffer-state nil
+           ;; We try to be line oriented, unless there are several
+           ;; declarations on the same line.
+           (if (looking-at c-syntactic-eol)
+               (c-backward-token-2 1 nil (c-point 'bol))
+             (c-forward-token-2 0 nil (c-point 'eol)))
+           (setq decl-limits (c-declaration-limits nil)))
+         (if decl-limits
+             (c-indent-region (car decl-limits)
+                              (cdr decl-limits))))
       (goto-char here)
       (set-marker here nil))))
 
 (defun c-indent-region (start end &optional quiet)
-  "Indent every line whose first char is between START and END inclusive.
-Be silent about syntactic errors if the optional argument QUIET is non-nil."
+  "Indent syntactically every line whose first char is between START
+and END inclusive.  If the optional argument QUIET is non-nil then no
+syntactic errors are reported, even if `c-report-syntactic-errors' is
+non-nil."
   (save-excursion
+    (goto-char end)
+    (skip-chars-backward " \t\n\r\f\v")
+    (setq end (point))
     (goto-char start)
     ;; Advance to first nonblank line.
-    (skip-chars-forward " \t\n")
+    (beginning-of-line)
+    (skip-chars-forward " \t\n\r\f\v")
+    (setq start (point))
     (beginning-of-line)
     (setq c-parsing-error
          (or (let ((endmark (copy-marker end))
                    (c-parsing-error nil)
                    ;; shut up any echo msgs on indiv lines
-                   (c-echo-syntactic-information-p nil))
+                   (c-echo-syntactic-information-p nil)
+                   (in-macro (and c-auto-align-backslashes
+                                  (save-excursion (c-beginning-of-macro))
+                                  start))
+                   (c-fix-backslashes nil)
+                   syntax)
                (unwind-protect
                    (progn
                      (c-progress-init start end 'c-indent-region)
@@ -1592,90 +2171,59 @@ Be silent about syntactic errors if the optional argument QUIET is non-nil."
                                  (< (point) endmark))
                        ;; update progress
                        (c-progress-update)
-                       ;; skip blank lines
+                       ;; skip empty lines
                        (skip-chars-forward " \t\n")
                        (beginning-of-line)
-                       ;; indent the current line
-                       (c-indent-line nil t)
-                       (forward-line)))
+                       ;; Get syntax and indent.
+                       (c-save-buffer-state nil
+                         (setq syntax (c-guess-basic-syntax)))
+                       (if (and c-auto-align-backslashes
+                                (assq 'cpp-macro syntax))
+                           ;; Record macro start.
+                           (setq in-macro (point)))
+                       (if in-macro
+                           (if (looking-at "\\s *\\\\$")
+                               (forward-line)
+                             (c-indent-line syntax t t)
+                             (if (progn (end-of-line)
+                                        (not (eq (char-before) ?\\)))
+                                 (progn
+                                   ;; Fixup macro backslashes.
+                                   (forward-line)
+                                   (c-backslash-region in-macro (point) nil)
+                                   (setq in-macro nil))
+                               (forward-line)))
+                         (c-indent-line syntax t t)
+                         (forward-line)))
+                     (if in-macro
+                         (c-backslash-region in-macro (c-point 'bopl) nil t)))
                  (set-marker endmark nil)
                  (c-progress-fini 'c-indent-region))
                (c-echo-parsing-error quiet))
              c-parsing-error))))
 
-(defun c-mark-function ()
-  "Put mark at end of current top-level defun, point at beginning."
-  (interactive)
-  (let ((here (point))
-       (eod (c-point 'eod))
-       (state (c-parse-state)))
-    ;; Are we sitting at the top level, someplace between either the
-    ;; beginning of buffer, or the nearest preceding defun?  If so,
-    ;; try first to figure out whether we're sitting on the
-    ;; introduction to a top-level defun, in which case we want to
-    ;; mark the entire defun we're sitting on.
-    ;;
-    ;; If we're sitting on anything else at the top-level, we want to
-    ;; just mark the statement that we're on
-    (if (or (and (consp (car state))
-                (= (length state) 1))
-           (null state))
-       ;; Are we in the whitespace after the nearest preceding defun?
-       (if (and state
-                (looking-at "[ \t]*$")
-                (= (save-excursion
-                     (c-backward-syntactic-ws)
-                     (skip-chars-backward ";")
-                     (point))
-                   (cdr (car state))))
-           (progn
-             (setq eod (point))
-             (goto-char (car (car state)))
-             (c-beginning-of-statement-1))
-         (if (= ?{ (save-excursion
-                     (c-end-of-statement-1)
-                     (char-before)))
-             ;; We must be in a defuns's introduction
-             (progn
-               (c-end-of-statement-1)
-               (skip-chars-backward "{")
-               (c-beginning-of-statement-1)
-               (c-forward-syntactic-ws))
-           ;; Just mark the statement
-           (c-end-of-statement-1)
-           (forward-line 1)
-           (setq eod (point))
-           (c-beginning-of-statement-1)))
-      ;; We are inside some enclosing brace structure, so we first
-      ;; need to find our way to the least enclosing brace.  Then, in
-      ;; both cases, we to mark the region from the beginning of the
-      ;; current statement, until the end of the next following defun
-      (while (and state)
-       (or (consp (car state))
-           (goto-char (car state)))
-       (setq state (cdr state)))
-      (c-beginning-of-statement-1))
-    (push-mark here)
-    (push-mark eod nil t)))
-
 (defun c-fn-region-is-active-p ()
   ;; Function version of the macro for use in places that aren't
   ;; compiled, e.g. in the menus.
+  ;;
+  ;; This function does not do any hidden buffer changes.
   (c-region-is-active-p))
 
 (defun c-indent-line-or-region ()
-  "When the region is active, indent it.  Otherwise indent the current line."
+  "When the region is active, indent it syntactically.  Otherwise
+indent the current line syntactically."
   ;; Emacs has a variable called mark-active, XEmacs uses region-active-p
   (interactive)
   (if (c-region-is-active-p)
       (c-indent-region (region-beginning) (region-end))
-    (indent-according-to-mode)))
+    (c-indent-line)))
 
 \f
 ;; for progress reporting
 (defvar c-progress-info nil)
 
 (defun c-progress-init (start end context)
+  ;; This function does not do any hidden buffer changes.
   (cond
    ;; Be silent
    ((not c-progress-interval))
@@ -1697,7 +2245,7 @@ Be silent about syntactic errors if the optional argument QUIET is non-nil."
    ))
 
 (defun c-progress-update ()
-  ;; update progress
+  ;; This function does not do any hidden buffer changes.
   (if (not (and c-progress-info c-progress-interval))
       nil
     (let ((now (nth 1 (current-time)))
@@ -1714,7 +2262,7 @@ Be silent about syntactic errors if the optional argument QUIET is non-nil."
       )))
 
 (defun c-progress-fini (context)
-  ;; finished
+  ;; This function does not do any hidden buffer changes.
   (if (not c-progress-interval)
       nil
     (if (or (eq context (aref c-progress-info 3))
@@ -1728,71 +2276,238 @@ Be silent about syntactic errors if the optional argument QUIET is non-nil."
 \f
 ;;; This page handles insertion and removal of backslashes for C macros.
 
-(defun c-backslash-region (from to delete-flag)
+(defun c-backslash-region (from to delete-flag &optional line-mode)
   "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.
+With an argument, deletes the backslashes.  The backslash alignment is
+done according to the settings in `c-backslash-column',
+`c-backslash-max-column' and `c-auto-align-backslashes'.
 
 This function does not modify blank lines at the start of the region.
-If the region ends at the start of a line, it always deletes the
-backslash (if any) at the end of the previous line.
+If the region ends at the start of a line and the macro doesn't
+continue below it, the backslash (if any) at the end of the previous
+line is deleted.
 
 You can put the region around an entire macro definition and use this
 command to conveniently insert and align the necessary backslashes."
   (interactive "*r\nP")
-  (save-excursion
-    (goto-char from)
-    (let ((column c-backslash-column)
-          (endmark (make-marker)))
-      (move-marker endmark to)
-      ;; Compute the smallest column number past the ends of all the lines.
-      (if (not delete-flag)
-          (while (< (point) to)
-            (end-of-line)
-            (if (eq (char-before) ?\\)
-                (progn (forward-char -1)
-                       (skip-chars-backward " \t")))
-            (setq column (max column (1+ (current-column))))
-            (forward-line 1)))
-      ;; Adjust upward to a tab column, if that doesn't push past the margin.
-      (if (> (% column tab-width) 0)
-          (let ((adjusted (* (/ (+ column tab-width -1) tab-width) tab-width)))
-            (if (< adjusted (window-width))
-                (setq column adjusted))))
-      ;; Don't modify blank lines at start of region.
-      (goto-char from)
-      (while (and (< (point) endmark) (eolp))
-        (forward-line 1))
-      ;; Add or remove backslashes on all the lines.
-      (while (< (point) endmark)
-       (if (and (not delete-flag)
-                ;; Un-backslashify the last line
-                ;; if the region ends right at the start of the next line.
-                (save-excursion
-                  (forward-line 1)
-                  (< (point) endmark)))
-            (c-append-backslash column)
-          (c-delete-backslash))
-        (forward-line 1))
-      (move-marker endmark nil))))
-
-(defun c-append-backslash (column)
-  (end-of-line)
-  (if (eq (char-before) ?\\)
-      (progn (forward-char -1)
-             (delete-horizontal-space)
-             (indent-to column))
-    (indent-to column)
-    (insert "\\")))
-
-(defun c-delete-backslash ()
-  (end-of-line)
-  (or (bolp)
-      (progn
-       (forward-char -1)
-       (if (looking-at "\\\\")
-           (delete-region (1+ (point))
-                          (progn (skip-chars-backward " \t") (point)))))))
+  (let ((endmark (make-marker))
+       ;; Keep the backslash trimming functions from changing the
+       ;; whitespace around point, since in this case it's only the
+       ;; position of point that tells the indentation of the line.
+       (point-pos (if (save-excursion
+                        (skip-chars-backward " \t")
+                        (and (bolp) (looking-at "[ \t]*\\\\?$")))
+                      (point-marker)
+                    (point-min)))
+       column longest-line-col bs-col-after-end)
+    (save-excursion
+      (goto-char to)
+      (if (and (not line-mode) (bobp))
+         ;; Nothing to do if to is at bob, since we should back up
+         ;; and there's no line to back up to.
+         nil
+       (when (and (not line-mode) (bolp))
+         ;; Do not back up the to line if line-mode is set, to make
+         ;; e.g. c-newline-and-indent consistent regardless whether
+         ;; the (newline) call leaves point at bol or not.
+         (backward-char)
+         (setq to (point)))
+       (if delete-flag
+           (progn
+             (set-marker endmark (point))
+             (goto-char from)
+             (c-delete-backslashes-forward endmark point-pos))
+         ;; Set bs-col-after-end to the column of any backslash
+         ;; following the region, or nil if there is none.
+         (setq bs-col-after-end
+               (and (progn (end-of-line)
+                           (eq (char-before) ?\\))
+                    (= (forward-line 1) 0)
+                    (progn (end-of-line)
+                           (eq (char-before) ?\\))
+                    (1- (current-column))))
+         (when line-mode
+           ;; Back up the to line if line-mode is set, since the line
+           ;; after the newly inserted line break should not be
+           ;; touched in c-newline-and-indent.
+           (setq to (max from (or (c-safe (c-point 'eopl)) from)))
+           (unless bs-col-after-end
+             ;; Set bs-col-after-end to non-nil in any case, since we
+             ;; do not want to delete the backslash at the last line.
+             (setq bs-col-after-end t)))
+         (if (and line-mode
+                  (not c-auto-align-backslashes))
+             (goto-char from)
+           ;; Compute the smallest column number past the ends of all
+           ;; the lines.
+           (setq longest-line-col 0)
+           (goto-char to)
+           (if bs-col-after-end
+               ;; Include one more line in the max column
+               ;; calculation, since the to line will be backslashed
+               ;; too.
+               (forward-line 1))
+           (end-of-line)
+           (while (and (>= (point) from)
+                       (progn
+                         (if (eq (char-before) ?\\)
+                             (forward-char -1))
+                         (skip-chars-backward " \t")
+                         (setq longest-line-col (max longest-line-col
+                                                     (1+ (current-column))))
+                         (beginning-of-line)
+                         (not (bobp))))
+             (backward-char))
+           ;; Try to align with surrounding backslashes.
+           (goto-char from)
+           (beginning-of-line)
+           (if (and (not (bobp))
+                    (progn (backward-char)
+                           (eq (char-before) ?\\)))
+               (progn
+                 (setq column (1- (current-column)))
+                 (if (numberp bs-col-after-end)
+                     ;; Both a preceding and a following backslash.
+                     ;; Choose the greatest of them.
+                     (setq column (max column bs-col-after-end)))
+                 (goto-char from))
+             ;; No preceding backslash.  Try to align with one
+             ;; following the region.  Disregard the backslash at the
+             ;; to line since it's likely to be bogus (e.g. when
+             ;; called from c-newline-and-indent).
+             (if (numberp bs-col-after-end)
+                 (setq column bs-col-after-end))
+             ;; Don't modify blank lines at start of region.
+             (goto-char from)
+             (while (and (< (point) to) (bolp) (eolp))
+               (forward-line 1)))
+           (if (and column (< column longest-line-col))
+               ;; Don't try to align with surrounding backslashes if
+               ;; any line is too long.
+               (setq column nil))
+           (unless column
+             ;; Impose minimum limit and tab width alignment only if
+             ;; we can't align with surrounding backslashes.
+             (if (> (% longest-line-col tab-width) 0)
+                 (setq longest-line-col
+                       (* (/ (+ longest-line-col tab-width -1)
+                             tab-width)
+                          tab-width)))
+             (setq column (max c-backslash-column
+                               longest-line-col)))
+           ;; Always impose maximum limit.
+           (setq column (min column c-backslash-max-column)))
+         (if bs-col-after-end
+             ;; Add backslashes on all lines if the macro continues
+             ;; after the to line.
+             (progn
+               (set-marker endmark to)
+               (c-append-backslashes-forward endmark column point-pos))
+           ;; Add backslashes on all lines except the last, and
+           ;; remove any on the last line.
+           (if (save-excursion
+                 (goto-char to)
+                 (beginning-of-line)
+                 (if (not (bobp))
+                     (set-marker endmark (1- (point)))))
+               (progn
+                 (c-append-backslashes-forward endmark column point-pos)
+                 ;; The function above leaves point on the line
+                 ;; following endmark.
+                 (set-marker endmark (point)))
+             (set-marker endmark to))
+           (c-delete-backslashes-forward endmark point-pos)))))
+    (set-marker endmark nil)
+    (if (markerp point-pos)
+       (set-marker point-pos nil))))
+
+(defun c-append-backslashes-forward (to-mark column point-pos)
+  ;; This function does not do any hidden buffer changes.
+  (let ((state (parse-partial-sexp (c-point 'bol) (point))))
+    (if column
+       (while
+           (and
+            (<= (point) to-mark)
+
+            (let ((start (point)) (inserted nil) end col)
+              (end-of-line)
+              (unless (eq (char-before) ?\\)
+                (insert ?\\)
+                (setq inserted t))
+              (setq state (parse-partial-sexp
+                           start (point) nil nil state))
+              (backward-char)
+              (setq col (current-column))
+
+              ;; Avoid unnecessary changes of the buffer.
+              (cond ((and (not inserted) (nth 3 state))
+                     ;; Don't realign backslashes in string literals
+                     ;; since that would change them.
+                     )
+
+                    ((< col column)
+                     (delete-region
+                      (point)
+                      (progn
+                        (skip-chars-backward
+                         " \t" (if (>= (point) point-pos) point-pos))
+                        (point)))
+                     (indent-to column))
+
+                    ((and (= col column)
+                          (memq (char-before) '(?\  ?\t))))
+
+                    ((progn
+                       (setq end (point))
+                       (or (/= (skip-chars-backward
+                                " \t" (if (>= (point) point-pos) point-pos))
+                               -1)
+                           (/= (char-after) ?\ )))
+                     (delete-region (point) end)
+                     (indent-to column 1)))
+
+              (= (forward-line 1) 0))))
+
+      ;; Make sure there are backslashes with at least one space in
+      ;; front of them.
+      (while
+         (and
+          (<= (point) to-mark)
+
+          (let ((start (point)))
+            (end-of-line)
+            (setq state (parse-partial-sexp
+                         start (point) nil nil state))
+
+            (if (eq (char-before) ?\\)
+                (unless (nth 3 state)
+                  (backward-char)
+                  (unless (and (memq (char-before) '(?\  ?\t))
+                               (/= (point) point-pos))
+                    (insert ?\ )))
+
+              (if (and (memq (char-before) '(?\  ?\t))
+                       (/= (point) point-pos))
+                  (insert ?\\)
+                (insert ?\  ?\\)))
+
+            (= (forward-line 1) 0)))))))
+
+(defun c-delete-backslashes-forward (to-mark point-pos)
+  ;; This function does not do any hidden buffer changes.
+  (while
+      (and (<= (point) to-mark)
+          (progn
+            (end-of-line)
+            (if (eq (char-before) ?\\)
+                (delete-region
+                 (point)
+                 (progn (backward-char)
+                        (skip-chars-backward " \t" (if (>= (point) point-pos)
+                                                       point-pos))
+                        (point))))
+            (= (forward-line 1) 0)))))
 
 
 \f
@@ -1824,6 +2539,7 @@ command to conveniently insert and align the necessary backslashes."
   ;; comment.  Return a cons of the prefix string and the column where
   ;; it ends.  If fill-prefix is set, it'll override.  Note that this
   ;; function also uses the value of point in some heuristics.
+
   (let* ((here (point))
         (prefix-regexp (concat "[ \t]*\\("
                                c-current-comment-prefix
@@ -1832,38 +2548,40 @@ command to conveniently insert and align the necessary backslashes."
                                   prefix-regexp
                                 comment-start-skip))
         prefix-line comment-prefix res comment-text-end)
+
     (cond
      (fill-prefix
       (setq res (cons fill-prefix
                      ;; Ugly way of getting the column after the fill
                      ;; prefix; it'd be nice with a current-column
                      ;; that works on strings..
-                     (let ((buffer-modified (buffer-modified-p))
-                           (buffer-undo-list t)
-                           (start (point)))
+                     (let ((start (point)))
                        (unwind-protect
                            (progn
-                             (insert ?\n fill-prefix)
+                             (insert-and-inherit "\n" fill-prefix)
                              (current-column))
-                         (delete-region start (point))
-                         (set-buffer-modified-p buffer-modified))))))
+                         (delete-region start (point)))))))
+
      ((eq lit-type 'c++)
       (save-excursion
        ;; Set fallback for comment-prefix if none is found.
        (setq comment-prefix "// "
              comment-text-end (cdr lit-limits))
+
        (beginning-of-line)
        (if (> (point) (car lit-limits))
            ;; The current line is not the comment starter, so the
            ;; comment has more than one line, and it can therefore be
            ;; used to find the comment fill prefix.
            (setq prefix-line (point))
+
          (goto-char (car lit-limits))
          (if (and (= (forward-line 1) 0)
                   (< (point) (cdr lit-limits)))
              ;; The line after the comment starter is inside the
              ;; comment, so we can use it.
              (setq prefix-line (point))
+
            ;; The comment is only one line.  Take the comment prefix
            ;; from it and keep the indentation.
            (goto-char (car lit-limits))
@@ -1871,38 +2589,47 @@ command to conveniently insert and align the necessary backslashes."
                (goto-char (match-end 0))
              (forward-char 2)
              (skip-chars-forward " \t"))
-           (setq res
-                 (if (eq (c-point 'boi) (car lit-limits))
-                     ;; There is only whitespace before the comment
-                     ;; starter; take the prefix straight from this
-                     ;; line.
-                     (cons (buffer-substring-no-properties
+
+           (let (str col)
+             (if (eq (c-point 'boi) (car lit-limits))
+                 ;; There is only whitespace before the comment
+                 ;; starter; take the prefix straight from this line.
+                 (setq str (buffer-substring-no-properties
                             (c-point 'bol) (point))
-                           (current-column))
-                   ;; There is code before the comment starter, so we
-                   ;; have to temporarily insert and indent a new
-                   ;; line to get the right space/tab mix in the
-                   ;; indentation.
-                   (let ((buffer-modified (buffer-modified-p))
-                         (buffer-undo-list t)
-                         (prefix-len (- (point) (car lit-limits)))
-                         tmp)
-                     (unwind-protect
-                         (progn
-                           (goto-char (car lit-limits))
-                           (indent-to (prog1 (current-column)
-                                        (insert ?\n)))
-                           (setq tmp (point))
-                           (forward-char prefix-len)
-                           (cons (buffer-substring-no-properties
+                       col (current-column))
+
+               ;; There is code before the comment starter, so we
+               ;; have to temporarily insert and indent a new line to
+               ;; get the right space/tab mix in the indentation.
+               (let ((prefix-len (- (point) (car lit-limits)))
+                     tmp)
+                 (unwind-protect
+                     (progn
+                       (goto-char (car lit-limits))
+                       (indent-to (prog1 (current-column)
+                                    (insert ?\n)))
+                       (setq tmp (point))
+                       (forward-char prefix-len)
+                       (setq str (buffer-substring-no-properties
                                   (c-point 'bol) (point))
-                                 (current-column)))
-                       (delete-region (car lit-limits) tmp)
-                       (set-buffer-modified-p buffer-modified))))
-                 )))))
+                             col (current-column)))
+                   (delete-region (car lit-limits) tmp))))
+
+             (setq res
+                   (if (or (string-match "\\s \\'" str) (not (eolp)))
+                       (cons str col)
+                     ;; The prefix ends the line with no whitespace
+                     ;; after it.  Default to a single space.
+                     (cons (concat str " ") (1+ col))))
+             )))))
+
      (t
+      (setq comment-text-end
+           (save-excursion
+             (goto-char (- (cdr lit-limits) 2))
+             (if (looking-at "\\*/") (point) (cdr lit-limits))))
+
       (save-excursion
-       (setq comment-text-end (- (cdr lit-limits) 2))
        (beginning-of-line)
        (if (and (> (point) (car lit-limits))
                 (not (and (looking-at "[ \t]*\\*/")
@@ -1912,74 +2639,124 @@ command to conveniently insert and align the necessary backslashes."
            ;; to be used for the comment fill prefix.
            (setq prefix-line (point))
          (goto-char (car lit-limits))
-         (if (or (/= (forward-line 1) 0)
-                 (>= (point) (cdr lit-limits))
-                 (and (looking-at "[ \t]*\\*/")
-                      (eq (cdr lit-limits) (match-end 0)))
-                 (and (looking-at prefix-regexp)
-                      (<= (1- (cdr lit-limits)) (match-end 0)))
-                 (and (< here (point))
-                      (or (not (match-beginning 0))
-                          (looking-at "[ \t]*$"))))
-             ;; The comment is either one line or the next line
-             ;; contains just the comment ender.  Also, if point is
-             ;; on the comment opener line and the following line is
-             ;; empty or doesn't match c-current-comment-prefix we
-             ;; assume that this is in fact a not yet closed one line
-             ;; comment, so we shouldn't look for the comment prefix
-             ;; on the next line.  In these cases we have no
-             ;; information about a suitable comment prefix, so we
-             ;; resort to c-block-comment-prefix.
-             (setq comment-prefix (or c-block-comment-prefix "")
-                   res (let ((buffer-modified (buffer-modified-p))
-                             (buffer-undo-list t)
-                             tmp-pre tmp-post)
-                         ;; The comment doesn't give any information
-                         ;; about the indentation column.  We'll have to
-                         ;; temporarily insert a new comment line and
-                         ;; indent it to find the correct column.
-                         (unwind-protect
-                             (progn
-                               (goto-char (car lit-limits))
-                               (if (looking-at comment-start-regexp)
-                                   (goto-char (match-end 0))
-                                 (forward-char 2)
-                                 (skip-chars-forward " \t"))
-                               (when (eq (char-syntax (char-before)) ?\ )
-                                 ;; If there's ws on the current
-                                 ;; line, we'll use it instead of
-                                 ;; what's ending comment-prefix.
-                                 (setq comment-prefix
-                                       (concat (substring comment-prefix
-                                                          0 (string-match
-                                                             "\\s *\\'"
-                                                             comment-prefix))
-                                               (buffer-substring-no-properties
-                                                (save-excursion
-                                                  (skip-chars-backward " \t")
-                                                  (point))
-                                                (point)))))
-                               (setq tmp-pre (point-marker))
-                               ;; We insert an extra non-whitespace
-                               ;; character before the line break and
-                               ;; after comment-prefix in case it's
-                               ;; "" or ends with whitespace.
-                               (insert "x\n" comment-prefix ?x)
-                               (setq tmp-post (point-marker))
-                               (indent-according-to-mode)
-                               (goto-char (1- tmp-post))
-                               (cons (buffer-substring-no-properties
-                                        (c-point 'bol) (point))
-                                     (current-column)))
-                           (when tmp-post
-                             (delete-region tmp-pre tmp-post)
-                             (set-marker tmp-pre nil)
-                             (set-marker tmp-post nil))
-                           (set-buffer-modified-p buffer-modified))))
-           ;; Otherwise the line after the comment starter is good
-           ;; enough to find the prefix in.
-           (setq prefix-line (point)))))))
-    (or res
+
+         (cond ((or (/= (forward-line 1) 0)
+                    (>= (point) (cdr lit-limits))
+                    (and (looking-at "[ \t]*\\*/")
+                         (eq (cdr lit-limits) (match-end 0)))
+                    (and (looking-at prefix-regexp)
+                         (<= (1- (cdr lit-limits)) (match-end 0))))
+                ;; The comment is either one line or the next line contains
+                ;; just the comment ender.  In this case we have no
+                ;; information about a suitable comment prefix, so we resort
+                ;; to c-block-comment-prefix.
+                (setq comment-prefix (or c-block-comment-prefix "")))
+
+               ((< here (point))
+                ;; The point was on the comment opener line, so we might want
+                ;; to treat this as a not yet closed comment.
+
+                (if (and (match-beginning 1)
+                         (/= (match-beginning 1) (match-end 1)))
+                    ;; Above `prefix-regexp' matched a nonempty prefix on the
+                    ;; second line, so let's use it.  Normally it should do
+                    ;; to set `prefix-line' and let the code below pick up
+                    ;; the whole prefix, but if there's no text after the
+                    ;; match then it will probably fall back to no prefix at
+                    ;; all if the comment isn't closed yet, so in that case
+                    ;; it's better to force use of the prefix matched now.
+                    (if (= (match-end 0) (c-point 'eol))
+                        (setq comment-prefix (match-string 1))
+                      (setq prefix-line (point)))
+
+                  ;; There's no nonempty prefix on the line after the
+                  ;; comment opener.  If the line is empty, or if the
+                  ;; text on has less or equal indentation than the
+                  ;; comment starter we assume it's an unclosed
+                  ;; comment starter, i.e. that
+                  ;; `c-block-comment-prefix' should be used.
+                  ;; Otherwise we assume it's a closed comment where
+                  ;; the prefix really is the empty string.
+                  ;; E.g. this is an unclosed comment:
+                  ;;
+                  ;;     /*
+                  ;;     foo
+                  ;;
+                  ;; But this is not:
+                  ;;
+                  ;;     /*
+                  ;;       foo
+                  ;;     */
+                  ;;
+                  ;; (Looking for the presence of the comment closer
+                  ;; rarely works since it's probably the closer of
+                  ;; some comment further down when the comment
+                  ;; really is unclosed.)
+                  (if (<= (save-excursion (back-to-indentation)
+                                          (current-column))
+                          (save-excursion (goto-char (car lit-limits))
+                                          (current-column)))
+                      (setq comment-prefix (or c-block-comment-prefix ""))
+                    (setq prefix-line (point)))))
+
+               (t
+                ;; Otherwise the line after the comment starter is good
+                ;; enough to find the prefix in.
+                (setq prefix-line (point))))
+
+         (when comment-prefix
+           ;; Haven't got the comment prefix on any real line that we
+           ;; can take it from, so we have to temporarily insert
+           ;; `comment-prefix' on a line and indent it to find the
+           ;; correct column and the correct mix of tabs and spaces.
+           (setq res
+                 (let (tmp-pre tmp-post)
+                   (unwind-protect
+                       (progn
+
+                         (goto-char (car lit-limits))
+                         (if (looking-at comment-start-regexp)
+                             (goto-char (min (match-end 0)
+                                             comment-text-end))
+                           (forward-char 2)
+                           (skip-chars-forward " \t"))
+
+                         (when (eq (char-syntax (char-before)) ?\ )
+                           ;; If there's ws on the current line, we'll use it
+                           ;; instead of what's ending comment-prefix.
+                           (setq comment-prefix
+                                 (concat (substring comment-prefix
+                                                    0 (string-match
+                                                       "\\s *\\'"
+                                                       comment-prefix))
+                                         (buffer-substring-no-properties
+                                          (save-excursion
+                                            (skip-chars-backward " \t")
+                                            (point))
+                                          (point)))))
+
+                         (setq tmp-pre (point-marker))
+
+                         ;; We insert an extra non-whitespace character
+                         ;; before the line break and after comment-prefix in
+                         ;; case it's "" or ends with whitespace.
+                         (insert-and-inherit "x\n" comment-prefix "x")
+                         (setq tmp-post (point-marker))
+
+                         (indent-according-to-mode)
+
+                         (goto-char (1- tmp-post))
+                         (cons (buffer-substring-no-properties
+                                (c-point 'bol) (point))
+                               (current-column)))
+
+                     (when tmp-post
+                       (delete-region tmp-pre tmp-post)
+                       (set-marker tmp-pre nil)
+                       (set-marker tmp-post nil))))))))))
+
+    (or res                            ; Found a good prefix above.
+
        (save-excursion
          ;; prefix-line is the bol of a line on which we should try
          ;; to find the prefix.
@@ -2002,11 +2779,13 @@ command to conveniently insert and align the necessary backslashes."
                                         (match-beginning 0) (match-end 0))
                              fb-endpos (match-end 0)))
                      t))))
+
            (or (catch 'found
                  ;; Search for a line which has text after the prefix
                  ;; so that we get the proper amount of whitespace
                  ;; after it.  We start with the current line, then
                  ;; search backwards, then forwards.
+
                  (goto-char prefix-line)
                  (when (and (funcall test-line)
                             (or (/= (match-end 1) (match-end 0))
@@ -2019,6 +2798,7 @@ command to conveniently insert and align the necessary backslashes."
                    (throw 'found (cons fb-string
                                        (progn (goto-char fb-endpos)
                                               (current-column)))))
+
                  (if (eq lit-type 'c++)
                      ;; For line comments we can search up to and
                      ;; including the first line.
@@ -2030,19 +2810,26 @@ command to conveniently insert and align the necessary backslashes."
                    (while (and (zerop (forward-line -1))
                                (> (point) (car lit-limits)))
                      (funcall test-line)))
+
                  (goto-char prefix-line)
                  (while (and (zerop (forward-line 1))
                              (< (point) (cdr lit-limits)))
                    (funcall test-line))
+
                  (goto-char prefix-line)
                  nil)
+
                (when fb-string
                  ;; A good line wasn't found, but at least we have a
                  ;; fallback that matches the comment prefix regexp.
-                 (cond ((string-match "\\s \\'" fb-string)
-                        ;; There are ws after the prefix, so let's use it.
-                        (cons fb-string
-                              (progn (goto-char fb-endpos) (current-column))))
+                 (cond ((or (string-match "\\s \\'" fb-string)
+                            (progn
+                              (goto-char fb-endpos)
+                              (not (eolp))))
+                        ;; There are ws or text after the prefix, so
+                        ;; let's use it.
+                        (cons fb-string (current-column)))
+
                        ((progn
                           ;; Check if there's any whitespace padding
                           ;; on the comment start line that we can
@@ -2052,7 +2839,9 @@ command to conveniently insert and align the necessary backslashes."
                               (goto-char (match-end 0))
                             (forward-char 2)
                             (skip-chars-forward " \t"))
-                          (eq (char-syntax (char-before)) ?\ ))
+                          (or (not (eolp))
+                              (eq (char-syntax (char-before)) ?\ )))
+
                         (setq fb-string (buffer-substring-no-properties
                                          (save-excursion
                                            (skip-chars-backward " \t")
@@ -2060,26 +2849,26 @@ command to conveniently insert and align the necessary backslashes."
                                          (point)))
                         (goto-char fb-endpos)
                         (skip-chars-backward " \t")
-                        (let ((buffer-modified (buffer-modified-p))
-                              (buffer-undo-list t)
-                              (tmp (point)))
+
+                        (let ((tmp (point)))
                           ;; Got to mess in the buffer once again to
                           ;; ensure the column gets correct.  :P
                           (unwind-protect
                               (progn
-                                (insert fb-string)
+                                (insert-and-inherit fb-string)
                                 (cons (buffer-substring-no-properties
                                        (c-point 'bol)
                                        (point))
                                       (current-column)))
-                            (delete-region tmp (point))
-                            (set-buffer-modified-p buffer-modified))))
+                            (delete-region tmp (point)))))
+
                        (t
                         ;; Last resort: Just add a single space after
                         ;; the prefix.
                         (cons (concat fb-string " ")
                               (progn (goto-char fb-endpos)
                                      (1+ (current-column)))))))
+
                ;; The line doesn't match the comment prefix regexp.
                (if comment-prefix
                    ;; We have a fallback for line comments that we must use.
@@ -2088,6 +2877,7 @@ command to conveniently insert and align the necessary backslashes."
                                  comment-prefix)
                          (progn (back-to-indentation)
                                 (+ (current-column) (length comment-prefix))))
+
                  ;; Assume we are dealing with a "free text" block
                  ;; comment where the lines doesn't have any comment
                  ;; prefix at all and we should just fill it as
@@ -2095,29 +2885,23 @@ command to conveniently insert and align the necessary backslashes."
                  '("" . 0))))))
     ))
 
-(defun c-fill-paragraph (&optional arg)
-  "Like \\[fill-paragraph] but handles C and C++ style comments.
-If any of the current line is a comment or within a comment, fill the
-comment or the paragraph of it that point is in, preserving the
-comment indentation or line-starting decorations (see the
-`c-comment-prefix-regexp' and `c-block-comment-prefix' variables for
-details).
-
-If point is inside multiline string literal, fill it.  This currently
-does not respect escaped newlines, except for the special case when it
-is the very first thing in the string.  The intended use for this rule
-is in situations like the following:
-
-char description[] = \"\\
-A very long description of something that you want to fill to make
-nicely formatted output.\"\;
-
-If point is in any other situation, i.e. in normal code, do nothing.
-
-Optional prefix ARG means justify paragraph as well."
-  (interactive "*P")
-  (let (lit-limits lit-type fill
-       ;; beg and end limits the region to be filled.  end is a marker.
+(defun c-mask-paragraph (fill-paragraph apply-outside-literal fun &rest args)
+  ;; Calls FUN with ARGS ar arguments while the current paragraph is
+  ;; masked to allow adaptive filling to work correctly.  That
+  ;; includes narrowing the buffer and, if point is inside a comment,
+  ;; masking the comment starter and ender appropriately.
+  ;;
+  ;; FILL-PARAGRAPH is non-nil if called for whole paragraph filling.
+  ;; The position of point is then less significant when doing masking
+  ;; and narrowing.
+  ;;
+  ;; If APPLY-OUTSIDE-LITERAL is nil then the function will be called
+  ;; only if the point turns out to be inside a comment or a string.
+  ;;
+  ;; This function does not do any hidden buffer changes.
+
+  (let (fill
+       ;; beg and end limits the region to narrow.  end is a marker.
        beg end
        ;; tmp-pre and tmp-post mark strings that are temporarily
        ;; inserted at the start and end of the region.  tmp-pre is a
@@ -2129,17 +2913,25 @@ Optional prefix ARG means justify paragraph as well."
        ;; hanging.  In that case it's set to the number of spaces
        ;; that should be between the text and the ender.
        hang-ender-stuck
-       (here (point)))
+       (here (point))
+       (c-lit-limits c-lit-limits)
+       (c-lit-type c-lit-type))
+
     ;; Restore point on undo.  It's necessary since we do a lot of
     ;; hidden inserts and deletes below that should be as transparent
     ;; as possible.
     (if (and buffer-undo-list (not (eq buffer-undo-list t)))
        (setq buffer-undo-list (cons (point) buffer-undo-list)))
+
     (save-restriction
       ;; Widen to catch comment limits correctly.
       (widen)
-      (setq lit-limits (c-collect-line-comments (c-literal-limits nil t))
-           lit-type (c-literal-type lit-limits)))
+      (unless c-lit-limits
+       (setq c-lit-limits (c-literal-limits nil fill-paragraph)))
+      (setq c-lit-limits (c-collect-line-comments c-lit-limits))
+      (unless c-lit-type
+       (setq c-lit-type (c-literal-type c-lit-limits))))
+
     (save-excursion
       (unless (c-safe (backward-char)
                      (forward-paragraph)
@@ -2154,117 +2946,179 @@ Optional prefix ARG means justify paragraph as well."
        (goto-char here)
        (backward-paragraph))
       (setq beg (point)))
+
     (unwind-protect
        (progn
          (cond
-          ((eq lit-type 'c++)          ; Line comment.
+
+          ((eq c-lit-type 'c++)        ; Line comment.
            (save-excursion
-             ;; Fill to the comment or paragraph end, whichever
+             ;; Limit to the comment or paragraph end, whichever
              ;; comes first.
-             (set-marker end (min end (cdr lit-limits)))
-             (when (<= beg (car lit-limits))
-               ;; The region to be filled includes the comment
-               ;; starter, so we must check it.
-               (goto-char (car lit-limits))
+             (set-marker end (min end (cdr c-lit-limits)))
+
+             (when (<= beg (car c-lit-limits))
+               ;; The region includes the comment starter, so we must
+               ;; check it.
+               (goto-char (car c-lit-limits))
                (back-to-indentation)
-               (if (eq (point) (car lit-limits))
-                   ;; Include the first line in the fill.
+               (if (eq (point) (car c-lit-limits))
+                   ;; Include the first line in the region.
                    (setq beg (c-point 'bol))
                  ;; The first line contains code before the
                  ;; comment.  We must fake a line that doesn't.
-                 (setq tmp-pre t)))
-             ))
-          ((eq lit-type 'c)            ; Block comment.
-           (when (>= end (cdr lit-limits))
-             ;; The region to be filled includes the comment ender.
+                 (setq tmp-pre t))))
+
+           (setq apply-outside-literal t))
+
+          ((eq c-lit-type 'c)          ; Block comment.
+           (when (>= end (cdr c-lit-limits))
+             ;; The region includes the comment ender which we might
+             ;; want to keep together with the last word.
              (unless (save-excursion
-                       (goto-char (cdr lit-limits))
+                       (goto-char (cdr c-lit-limits))
                        (beginning-of-line)
                        (and (looking-at (concat "[ \t]*\\("
                                                 c-current-comment-prefix
                                                 "\\)\\*/"))
-                            (eq (cdr lit-limits) (match-end 0))
-                            ;; Leave the comment ender on its own line.
+                            (eq (cdr c-lit-limits) (match-end 0))
+                            ;; The comment ender is on a line of its
+                            ;; own.  Keep it that way.
                             (set-marker end (point))))
-               ;; The comment ender should hang.  Replace all cruft
-               ;; between it and the last word with one or two 'x'
-               ;; and include it in the fill.  We'll change them back
-               ;; spaces afterwards.
-               (let* ((ender-start (save-excursion
-                                     (goto-char (cdr lit-limits))
-                                     (skip-syntax-backward "^w ")
-                                     (point)))
-                      (point-rel (- ender-start here))
-                      spaces)
-                 (save-excursion
-                   (goto-char (cdr lit-limits))
-                   (setq tmp-post (point-marker))
-                   (insert ?\n)
-                   (set-marker end (point))
-                   (forward-line -1)
-                   (if (and (looking-at (concat "[ \t]*\\(\\("
-                                                c-current-comment-prefix
-                                                "\\)[ \t]*\\)"))
-                            (eq ender-start (match-end 0)))
-                       ;; The comment ender is prefixed by nothing
-                       ;; but a comment line prefix.  Remove it
-                       ;; along with surrounding ws.
-                       (setq spaces (- (match-end 1) (match-end 2)))
-                     (goto-char ender-start))
-                   (skip-chars-backward " \t\r\n")
-                   (if (/= (point) ender-start)
-                       (progn
-                         (if (<= here (point))
-                             ;; Don't adjust point below if it's
-                             ;; before the string we replace.
-                             (setq point-rel -1))
-                         ;; Keep one or two spaces between the text and
-                         ;; the ender, depending on how many there are now.
-                         (unless spaces (setq spaces (- ender-start (point))))
-                         (setq spaces (max (min spaces 2) 1))
-                         ;; Insert the filler first to keep marks right.
-                         (insert (make-string spaces ?x))
-                         (delete-region (point) (+ ender-start spaces))
-                         (setq hang-ender-stuck spaces)
-                         (setq point-rel
-                               (and (>= point-rel 0)
-                                    (- (point) (min point-rel spaces)))))
-                     (setq point-rel nil)))
-                 (if point-rel
-                     ;; Point was in the middle of the string we
-                     ;; replaced above, so put it back in the same
-                     ;; relative position, counting from the end.
-                     (goto-char point-rel))
-                 )))
-           (when (<= beg (car lit-limits))
-             ;; The region to be filled includes the comment starter.
+
+               (if fill-paragraph
+                   ;; The comment ender should hang.  Replace all
+                   ;; cruft between it and the last word with one or
+                   ;; two 'x' and include it in the region.  We'll
+                   ;; change them back to spaces afterwards.  This
+                   ;; isn't done when auto filling, since that'd
+                   ;; effectively make it impossible to insert extra
+                   ;; spaces before the comment ender.
+                   (let* ((ender-start (save-excursion
+                                         (goto-char (cdr c-lit-limits))
+                                         (skip-syntax-backward "^w ")
+                                         (point)))
+                          (point-rel (- ender-start here))
+                          spaces)
+
+                     (save-excursion
+                       (goto-char (cdr c-lit-limits))
+                       (setq tmp-post (point-marker))
+                       (insert ?\n)
+                       (set-marker end (point))
+                       (forward-line -1)
+                       (if (and (looking-at (concat "[ \t]*\\(\\("
+                                                    c-current-comment-prefix
+                                                    "\\)[ \t]*\\)"))
+                                (eq ender-start (match-end 0)))
+                           ;; The comment ender is prefixed by nothing
+                           ;; but a comment line prefix.  Remove it
+                           ;; along with surrounding ws.
+                           (setq spaces (- (match-end 1) (match-end 2)))
+                         (goto-char ender-start))
+                       (skip-chars-backward " \t\r\n")
+
+                       (if (/= (point) ender-start)
+                           (progn
+                             (if (<= here (point))
+                                 ;; Don't adjust point below if it's
+                                 ;; before the string we replace.
+                                 (setq point-rel -1))
+                             ;; Keep one or two spaces between the
+                             ;; text and the ender, depending on how
+                             ;; many there are now.
+                             (unless spaces
+                               (setq spaces (- ender-start (point))))
+                             (setq spaces
+                                   (max
+                                    (min spaces
+                                         (if sentence-end-double-space 2 1))
+                                    1))
+                             ;; Insert the filler first to keep marks right.
+                             (insert-char ?x spaces t)
+                             (delete-region (point) (+ ender-start spaces))
+                             (setq hang-ender-stuck spaces)
+                             (setq point-rel
+                                   (and (>= point-rel 0)
+                                        (- (point) (min point-rel spaces)))))
+                         (setq point-rel nil)))
+
+                     (if point-rel
+                         ;; Point was in the middle of the string we
+                         ;; replaced above, so put it back in the same
+                         ;; relative position, counting from the end.
+                         (goto-char point-rel)))
+
+                 ;; We're doing auto filling.  Just move the marker
+                 ;; to the comment end to ignore any code after the
+                 ;; comment.
+                 (move-marker end (cdr c-lit-limits)))))
+
+           (when (<= beg (car c-lit-limits))
+             ;; The region includes the comment starter.
              (save-excursion
-               (goto-char (car lit-limits))
+               (goto-char (car c-lit-limits))
                (if (looking-at (concat "\\(" comment-start-skip "\\)$"))
-                   ;; Begin filling with the next line.
+                   ;; Begin with the next line.
                    (setq beg (c-point 'bonl))
                  ;; Fake the fill prefix in the first line.
-                 (setq tmp-pre t)))))
-          ((eq lit-type 'string)       ; String.
+                 (setq tmp-pre t))))
+
+           (setq apply-outside-literal t))
+
+          ((eq c-lit-type 'string)     ; String.
            (save-excursion
-             (when (>= end (cdr lit-limits))
-               (goto-char (1- (cdr lit-limits)))
+             (when (>= end (cdr c-lit-limits))
+               (goto-char (1- (cdr c-lit-limits)))
                (setq tmp-post (point-marker))
                (insert ?\n)
                (set-marker end (point)))
-             (when (<= beg (car lit-limits))
-               (goto-char (1+ (car lit-limits)))
+             (when (<= beg (car c-lit-limits))
+               (goto-char (1+ (car c-lit-limits)))
                (setq beg (if (looking-at "\\\\$")
                              ;; Leave the start line if it's
                              ;; nothing but an escaped newline.
                              (1+ (match-end 0))
-                           (point))))))
-          (t (setq beg nil)))
+                           (point)))))
+           (setq apply-outside-literal t))
+
+          ((eq c-lit-type 'pound)      ; Macro
+           ;; Narrow to the macro limits if they are nearer than the
+           ;; paragraph limits.  Don't know if this is necessary but
+           ;; do it for completeness sake (doing auto filling at all
+           ;; inside macros is bogus to begin with since the line
+           ;; continuation backslashes aren't handled).
+           (save-excursion
+             (c-beginning-of-macro)
+             (beginning-of-line)
+             (if (> (point) beg)
+                 (setq beg (point)))
+             (c-end-of-macro)
+             (forward-line)
+             (if (< (point) end)
+                 (set-marker end (point)))))
+
+          (t                           ; Other code.
+           ;; Try to avoid comments and macros in the paragraph to
+           ;; avoid that the adaptive fill mode gets the prefix from
+           ;; them.
+           (c-save-buffer-state nil
+             (save-excursion
+               (goto-char beg)
+               (c-forward-syntactic-ws end)
+               (beginning-of-line)
+               (setq beg (point))
+               (goto-char end)
+               (c-backward-syntactic-ws beg)
+               (forward-line)
+               (set-marker end (point))))))
+
          (when tmp-pre
            ;; Temporarily insert the fill prefix after the comment
            ;; starter so that the first line looks like any other
            ;; comment line in the narrowed region.
-           (setq fill (c-guess-fill-prefix lit-limits lit-type))
+           (setq fill (c-save-buffer-state nil
+                        (c-guess-fill-prefix c-lit-limits c-lit-type)))
            (unless (string-match (concat "\\`[ \t]*\\("
                                          c-current-comment-prefix
                                          "\\)[ \t]*\\'")
@@ -2283,60 +3137,71 @@ Warning: Regexp from `c-comment-prefix-regexp' doesn't match the comment prefix
            ;; same column by temporarily prefixing the first word
            ;; with a number of 'x'.
            (save-excursion
-             (goto-char (car lit-limits))
-             (if (looking-at (if (eq lit-type 'c++)
-                                 c-comment-prefix-regexp
+             (goto-char (car c-lit-limits))
+             (if (looking-at (if (eq c-lit-type 'c++)
+                                 c-current-comment-prefix
                                comment-start-skip))
                  (goto-char (match-end 0))
                (forward-char 2)
                (skip-chars-forward " \t"))
-             (while (< (current-column) (cdr fill)) (forward-char 1))
+             (while (and (< (current-column) (cdr fill))
+                         (not (eolp)))
+               (forward-char 1))
              (let ((col (current-column)))
                (setq beg (1+ (point))
                      tmp-pre (list (point)))
                (unwind-protect
                    (progn
-                     (insert ?\n (car fill))
-                     (insert (make-string (- col (current-column)) ?x)))
+                     (insert-and-inherit "\n" (car fill))
+                     (insert-char ?x (- col (current-column)) t))
                  (setcdr tmp-pre (point))))))
-         (when beg
-           (let ((fill-paragraph-function
-                  ;; Avoid infinite recursion.
-                  (if (not (eq fill-paragraph-function 'c-fill-paragraph))
-                      fill-paragraph-function))
-                 (fill-prefix
+
+         (when apply-outside-literal
+           ;; `apply-outside-literal' is always set to t here if
+           ;; we're inside a literal.
+
+           (let ((fill-prefix
                   (or fill-prefix
                       ;; Kludge: If the function that adapts the fill prefix
-                      ;; doesn't produce the required comment starter for line
-                      ;; comments, then force it by setting fill-prefix.
-                      (when (and (eq lit-type 'c++)
+                      ;; doesn't produce the required comment starter for
+                      ;; line comments, then force it by setting fill-prefix.
+                      (when (and (eq c-lit-type 'c++)
                                  ;; Kludge the kludge: filladapt-mode doesn't
-                                 ;; have this problem, but it doesn't override
-                                 ;; fill-context-prefix currently (version
-                                 ;; 2.12).
+                                 ;; have this problem, but it currently
+                                 ;; doesn't override fill-context-prefix
+                                 ;; (version 2.12).
                                  (not (and (boundp 'filladapt-mode)
                                            filladapt-mode))
                                  (not (string-match
                                        "\\`[ \t]*//"
                                        (or (fill-context-prefix beg end)
                                            ""))))
-                        (car (or fill (c-guess-fill-prefix
-                                       lit-limits lit-type))))))
-                 (point-rel (cond ((< here beg) (- here beg))
-                                  ((> here end) (- here end)))))
+                        (c-save-buffer-state nil
+                          (car (or fill (c-guess-fill-prefix
+                                         c-lit-limits c-lit-type)))))))
+
+                 ;; Save the relative position of point if it's outside the
+                 ;; region we're going to narrow.  Want to restore it in that
+                 ;; case, but otherwise it should be moved according to the
+                 ;; called function.
+                 (point-rel (cond ((< (point) beg) (- (point) beg))
+                                  ((> (point) end) (- (point) end)))))
+
              ;; Preparations finally done!  Now we can call the
-             ;; real fill function.
-             (save-restriction
-               (narrow-to-region beg end)
-               (fill-paragraph arg))
-             (if point-rel
-                 ;; Restore point if it was outside the region.
-                 (if (< point-rel 0)
-                     (goto-char (+ beg point-rel))
-                   (goto-char (+ end point-rel))))
-             )))
+             ;; actual function.
+             (prog1
+                 (save-restriction
+                   (narrow-to-region beg end)
+                   (apply fun args))
+               (if point-rel
+                   ;; Restore point if it was outside the region.
+                   (if (< point-rel 0)
+                       (goto-char (+ beg point-rel))
+                     (goto-char (+ end point-rel))))))))
+
       (when (consp tmp-pre)
        (delete-region (car tmp-pre) (cdr tmp-pre)))
+
       (when tmp-post
        (save-excursion
          (goto-char tmp-post)
@@ -2348,11 +3213,39 @@ Warning: Regexp from `c-comment-prefix-regexp' doesn't match the comment prefix
          (goto-char tmp-post)
          (skip-syntax-backward "^w ")
          (forward-char (- hang-ender-stuck))
-         (insert (make-string hang-ender-stuck ?\ ))
+         (insert-char ?\  hang-ender-stuck t)
          (delete-char hang-ender-stuck)
          (goto-char here))
        (set-marker tmp-post nil))
-      (set-marker end nil)))
+
+      (set-marker end nil))))
+
+(defun c-fill-paragraph (&optional arg)
+  "Like \\[fill-paragraph] but handles C and C++ style comments.
+If any of the current line is a comment or within a comment, fill the
+comment or the paragraph of it that point is in, preserving the
+comment indentation or line-starting decorations (see the
+`c-comment-prefix-regexp' and `c-block-comment-prefix' variables for
+details).
+
+If point is inside multiline string literal, fill it.  This currently
+does not respect escaped newlines, except for the special case when it
+is the very first thing in the string.  The intended use for this rule
+is in situations like the following:
+
+char description[] = \"\\
+A very long description of something that you want to fill to make
+nicely formatted output.\"\;
+
+If point is in any other situation, i.e. in normal code, do nothing.
+
+Optional prefix ARG means justify paragraph as well."
+  (interactive "*P")
+  (let ((fill-paragraph-function
+        ;; Avoid infinite recursion.
+        (if (not (eq fill-paragraph-function 'c-fill-paragraph))
+            fill-paragraph-function)))
+    (c-mask-paragraph t nil 'fill-paragraph arg))
   ;; Always return t.  This has the effect that if filling isn't done
   ;; above, it isn't done at all, and it's therefore effectively
   ;; disabled in normal code.
@@ -2361,6 +3254,8 @@ Warning: Regexp from `c-comment-prefix-regexp' doesn't match the comment prefix
 (defun c-do-auto-fill ()
   ;; Do automatic filling if not inside a context where it should be
   ;; ignored.
+  ;;
+  ;; This function does not do any hidden buffer changes.
   (let ((c-auto-fill-prefix
         ;; The decision whether the line should be broken is actually
         ;; done in c-indent-new-comment-line, which do-auto-fill
@@ -2369,40 +3264,44 @@ Warning: Regexp from `c-comment-prefix-regexp' doesn't match the comment prefix
         ;; also used to detect whether fill-prefix is user set or
         ;; generated automatically by do-auto-fill.
         fill-prefix))
-    (do-auto-fill)))
+    (c-mask-paragraph nil t 'do-auto-fill)))
 
-(defun c-indent-new-comment-line (&optional soft)
-  "Break line at point and indent, continuing comment if within one.
+(defun c-indent-new-comment-line (&optional soft allow-auto-fill)
+  "Break line at point and indent, continuing comment or macro if within one.
 If inside a comment and `comment-multi-line' is non-nil, the
 indentation and line prefix are preserved (see the
 `c-comment-prefix-regexp' and `c-block-comment-prefix' variables for
 details).  If inside a single line comment and `comment-multi-line' is
 nil, a new comment of the same type is started on the next line and
-indented as appropriate for comments.
+indented as appropriate for comments.  If inside a macro, a line
+continuation backslash is inserted and aligned as appropriate, and the
+new line is indented according to `c-syntactic-indentation'.
 
 If a fill prefix is specified, it overrides all the above."
+  ;; allow-auto-fill is used from c-context-line-break to allow auto
+  ;; filling to break the line more than once.  Since this function is
+  ;; used from auto-fill itself, that's normally disabled to avoid
+  ;; unnecessary recursion.
   (interactive)
   (let ((fill-prefix fill-prefix)
        (do-line-break
         (lambda ()
-          (delete-region (progn (skip-chars-backward " \t") (point))
-                         (progn (skip-chars-forward " \t") (point)))
-          (if soft (insert-and-inherit ?\n) (newline 1))))
+          (delete-horizontal-space)
+          (if soft
+              (insert-and-inherit ?\n)
+            (newline (if allow-auto-fill nil 1)))))
        ;; Already know the literal type and limits when called from
        ;; c-context-line-break.
        (c-lit-limits c-lit-limits)
-       (c-lit-type c-lit-type))
+       (c-lit-type c-lit-type)
+       (c-macro-start c-macro-start))
     (when (not (eq c-auto-fill-prefix t))
       ;; Called from do-auto-fill.
       (unless c-lit-limits
        (setq c-lit-limits (c-literal-limits nil nil t)))
       (unless c-lit-type
        (setq c-lit-type (c-literal-type c-lit-limits)))
-      (if (memq (cond ((eq c-lit-type 'pound)
-                      ;; Come to think about it, "pound" is a bit
-                      ;; of a misnomer, so call it "cpp" instead
-                      ;; in user interaction.
-                      'cpp)
+      (if (memq (cond ((c-query-and-set-macro-start) 'cpp)
                      ((null c-lit-type) 'code)
                      (t c-lit-type))
                c-ignore-auto-fill)
@@ -2430,49 +3329,60 @@ If a fill prefix is specified, it overrides all the above."
           (insert-and-inherit fill-prefix))
          ((progn
             (unless c-lit-limits
-              (setq c-lit-limits (c-literal-limits nil nil t)))
+              (setq c-lit-limits (c-literal-limits)))
             (unless c-lit-type
               (setq c-lit-type (c-literal-type c-lit-limits)))
             (memq c-lit-type '(c c++)))
+          ;; Some sort of comment.
           (if (or comment-multi-line
                   (save-excursion
                     (goto-char (car c-lit-limits))
                     (end-of-line)
                     (< (point) (cdr c-lit-limits))))
               ;; Inside a comment that should be continued.
-              (let ((fill (c-guess-fill-prefix
-                           (setq c-lit-limits
-                                 (c-collect-line-comments c-lit-limits))
-                           c-lit-type))
-                    (pos (point)))
-                (if (save-excursion
-                      (back-to-indentation)
-                      (> (point) (car c-lit-limits))
-                      (looking-at c-current-comment-prefix))
+              (let ((fill (c-save-buffer-state nil
+                            (c-guess-fill-prefix
+                             (setq c-lit-limits
+                                   (c-collect-line-comments c-lit-limits))
+                             c-lit-type)))
+                    (pos (point))
+                    (comment-text-end
+                     (or (and (eq c-lit-type 'c)
+                              (save-excursion
+                                (goto-char (- (cdr c-lit-limits) 2))
+                                (if (looking-at "\\*/") (point))))
+                         (cdr c-lit-limits))))
+                ;; Skip forward past the fill prefix in case
+                ;; we're standing in it.
+                ;;
+                ;; FIXME: This doesn't work well in cases like
+                ;;
+                ;; /* Bla bla bla bla bla
+                ;;         bla bla
+                ;;
+                ;; If point is on the 'B' then the line will be
+                ;; broken after "Bla b".
+                (while (and (< (current-column) (cdr fill))
+                            (not (eolp)))
+                  (forward-char 1))
+                (if (and (> (point) comment-text-end)
+                         (> (c-point 'bol) (car c-lit-limits)))
                     (progn
-                      ;; Skip forward past the fill prefix in case
-                      ;; we're standing in it.
-                      (while (and (< (current-column) (cdr fill))
-                                  (not (eolp)))
-                        (forward-char 1))
-                      (if (> (point) (if (and (eq c-lit-type 'c)
-                                              (save-excursion
-                                                (forward-char -2)
-                                                (looking-at "\\*/")))
-                                         (- (cdr c-lit-limits) 2)
-                                       (cdr c-lit-limits)))
-                          (progn
-                            ;; The skip takes us out of the comment;
-                            ;; insert the fill prefix at bol instead
-                            ;; and keep the position.
-                            (setq pos (copy-marker pos t))
-                            (beginning-of-line)
-                            (insert-and-inherit (car fill))
-                            (if soft (insert-and-inherit ?\n) (newline 1))
-                            (goto-char pos)
-                            (set-marker pos nil))
-                        (funcall do-line-break)
-                        (insert-and-inherit (car fill))))
+                      ;; The skip takes us out of the (block)
+                      ;; comment; insert the fill prefix at bol
+                      ;; instead and keep the position.
+                      (setq pos (copy-marker pos t))
+                      (beginning-of-line)
+                      (insert-and-inherit (car fill))
+                      (if soft (insert-and-inherit ?\n) (newline 1))
+                      (goto-char pos)
+                      (set-marker pos nil))
+                  ;; Don't break in the middle of a comment starter
+                  ;; or ender.
+                  (cond ((> (point) comment-text-end)
+                         (goto-char comment-text-end))
+                        ((< (point) (+ (car c-lit-limits) 2))
+                         (goto-char (+ (car c-lit-limits) 2))))
                   (funcall do-line-break)
                   (insert-and-inherit (car fill))))
             ;; Inside a comment that should be broken.
@@ -2498,13 +3408,24 @@ If a fill prefix is specified, it overrides all the above."
               (indent-to col)
               (insert-and-inherit comment-start)
               (indent-for-comment))))
+         ((c-query-and-set-macro-start)
+          ;; In a macro.
+          (unless (looking-at "[ \t]*\\\\$")
+            ;; Do not clobber the alignment of the line continuation
+            ;; slash; c-backslash-region might look at it.
+            (delete-horizontal-space))
+          ;; Got an asymmetry here: In normal code this command
+          ;; doesn't indent the next line syntactically, and otoh a
+          ;; normal syntactically indenting newline doesn't continue
+          ;; the macro.
+          (c-newline-and-indent (if allow-auto-fill nil 1)))
          (t
           ;; Somewhere else in the code.
           (let ((col (save-excursion
-                       (while (progn (back-to-indentation)
-                                     (and (looking-at "^\\s *$")
-                                          (= (forward-line -1) 0))))
-                       (current-column))))
+                       (beginning-of-line)
+                       (while (and (looking-at "[ \t]*\\\\?$")
+                                   (= (forward-line -1) 0)))
+                       (current-indentation))))
             (funcall do-line-break)
             (indent-to col))))))
 
@@ -2526,37 +3447,72 @@ If a fill prefix is specified, it overrides all the above."
 (defun c-context-line-break ()
   "Do a line break suitable to the context.
 
-When point is outside a comment, insert a newline and indent according
-to the syntactic context.
+When point is outside a comment or macro, insert a newline and indent
+according to the syntactic context, unless `c-syntactic-indentation'
+is nil, in which case the new line is indented as the previous
+non-empty line instead.
+
+When point is inside the content of a preprocessor directive, a line
+continuation backslash is inserted before the line break and aligned
+appropriately.  The end of the cpp directive doesn't count as inside
+it.
 
 When point is inside a comment, continue it with the appropriate
 comment prefix (see the `c-comment-prefix-regexp' and
 `c-block-comment-prefix' variables for details).  The end of a
-C++-style line comment doesn't count as inside the comment, though."
+C++-style line comment doesn't count as inside it."
   (interactive "*")
   (let* ((c-lit-limits (c-literal-limits nil nil t))
-        (c-lit-type (c-literal-type c-lit-limits)))
+        (c-lit-type (c-literal-type c-lit-limits))
+        (c-macro-start c-macro-start))
     (if (or (eq c-lit-type 'c)
            (and (eq c-lit-type 'c++)
-                (< (point)
+                (< (save-excursion
+                     (skip-chars-forward " \t")
+                     (point))
                    (1- (cdr (setq c-lit-limits
-                                  (c-collect-line-comments c-lit-limits)))))))
+                                  (c-collect-line-comments c-lit-limits))))))
+           (and (or (not (looking-at "\\s *$"))
+                    (eq (char-before) ?\\))
+                (c-query-and-set-macro-start)
+                (<= (save-excursion
+                      (goto-char c-macro-start)
+                      (if (looking-at c-opt-cpp-start)
+                          (goto-char (match-end 0)))
+                      (point))
+                   (point))))
        (let ((comment-multi-line t)
              (fill-prefix nil))
-         (c-indent-new-comment-line))
-      (delete-region (point) (progn (skip-chars-backward " \t") (point)))
+         (c-indent-new-comment-line nil t))
+      (delete-horizontal-space)
       (newline)
       ;; c-indent-line may look at the current indentation, so let's
       ;; start out with the same indentation as the previous line.
       (let ((col (save-excursion
                   (forward-line -1)
-                  (while (progn (back-to-indentation)
-                                (and (looking-at "^\\s *$")
-                                     (= (forward-line -1) 0))))
-                  (current-column))))
+                  (while (and (looking-at "[ \t]*\\\\?$")
+                              (= (forward-line -1) 0)))
+                  (current-indentation))))
        (indent-to col))
       (indent-according-to-mode))))
 
+(defun c-context-open-line ()
+  "Insert a line break suitable to the context and leave point before it.
+This is the `c-context-line-break' equivalent to `open-line', which is
+normally bound to C-o.  See `c-context-line-break' for the details."
+  (interactive "*")
+  (let ((here (point)))
+    (unwind-protect
+       (progn
+         ;; Temporarily insert a non-whitespace char to keep any
+         ;; preceding whitespace intact.
+         (insert ?x)
+         (c-context-line-break))
+      (goto-char here)
+      (delete-char 1))))
+
 \f
 (cc-provide 'cc-cmds)
+
+;;; arch-tag: bf0611dc-d1f4-449e-9e45-4ec7c6936677
 ;;; cc-cmds.el ends here