;;; c-mode.el --- C code editing commands for Emacs
-;; Copyright (C) 1985, 1986, 1987, 1992, 1994 Free Software Foundation, Inc.
+
+;; Copyright (C) 1985, 86, 87, 92, 94, 95 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: c
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; A smart editing mode for C code. It knows a lot about C syntax and tries
-;; to position the curser according to C layout conventions. You can
+;; to position the cursor according to C layout conventions. You can
;; change the details of the layout style with option variables. Load it
;; and do M-x describe-mode for details.
;;; Code:
+(defgroup old-c nil
+ "Old C code editing commands for Emacs."
+ :prefix "c-"
+ :group 'languages)
+
(defvar c-mode-abbrev-table nil
"Abbrev table in use in C mode.")
(define-key c-mode-map [menu-bar] (make-sparse-keymap))
+;; "C-mode" is not strictly the right punctuation--it should be "C
+;; mode"--but that would look like two menu items. "C-mode" is the
+;; best alternative I can think of.
(define-key c-mode-map [menu-bar c]
- (cons "C Mode" (make-sparse-keymap "C Mode")))
+ (cons "C-mode" (make-sparse-keymap "C-mode")))
(define-key c-mode-map [menu-bar c comment-region]
'("Comment Out Region" . comment-region))
(define-key c-mode-map [menu-bar c forward-stmt]
'("Forward Statement" . c-end-of-statement))
+(put 'comment-region 'menu-enable 'mark-active)
+(put 'c-macro-expand 'menu-enable 'mark-active)
+(put 'c-backslash-region 'menu-enable 'mark-active)
+
(autoload 'c-macro-expand "cmacexp"
"Display the result of expanding all C macros occurring in the region.
The expansion is entirely correct because it uses the C preprocessor."
(modify-syntax-entry ?| "." c-mode-syntax-table)
(modify-syntax-entry ?\' "\"" c-mode-syntax-table))
-(defconst c-indent-level 2
- "*Indentation of C statements with respect to containing block.")
-(defconst c-brace-imaginary-offset 0
- "*Imagined indentation of a C open brace that actually follows a statement.")
-(defconst c-brace-offset 0
- "*Extra indentation for braces, compared with other text in same context.")
-(defconst c-argdecl-indent 5
- "*Indentation level of declarations of C function arguments.")
-(defconst c-label-offset -2
- "*Offset of C label lines and case statements relative to usual indentation.")
-(defconst c-continued-statement-offset 2
- "*Extra indent for lines not starting new statements.")
-(defconst c-continued-brace-offset 0
+(defcustom c-indent-level 2
+ "*Indentation of C statements with respect to containing block."
+ :type 'integer
+ :group 'old-c)
+(defcustom c-brace-imaginary-offset 0
+ "*Imagined indentation of a C open brace that actually follows a statement."
+ :type 'integer
+ :group 'old-c)
+(defcustom c-brace-offset 0
+ "*Extra indentation for braces, compared with other text in same context."
+ :type 'integer
+ :group 'old-c)
+(defcustom c-argdecl-indent 5
+ "*Indentation level of declarations of C function arguments."
+ :type 'integer
+ :group 'old-c)
+(defcustom c-label-offset -2
+ "*Offset of C label lines and case statements relative to usual indentation."
+ :type 'integer
+ :group 'old-c)
+(defcustom c-continued-statement-offset 2
+ "*Extra indent for lines not starting new statements."
+ :type 'integer
+ :group 'old-c)
+(defcustom c-continued-brace-offset 0
"*Extra indent for substatements that start with open-braces.
-This is in addition to `c-continued-statement-offset'.")
+This is in addition to `c-continued-statement-offset'."
+ :type 'integer
+ :group 'old-c)
(defconst c-style-alist
'(("GNU"
(c-indent-level . 2)
(c-argdecl-indent . 5)
(c-brace-offset . 0)
+ (c-continued-brace-offset . 0)
(c-label-offset . -2)
(c-continued-statement-offset . 2))
("K&R"
(c-indent-level . 5)
(c-argdecl-indent . 0)
- (c-brace-offset . -5)
+ (c-brace-offset . 0)
+ (c-continued-brace-offset . -5)
(c-label-offset . -5)
(c-continued-statement-offset . 5))
("BSD"
(c-indent-level . 4)
(c-argdecl-indent . 4)
+ (c-brace-offset . 0)
(c-continued-brace-offset . -4)
(c-label-offset . -4)
(c-continued-statement-offset . 4))
("C++"
- (c-indent-level . 4)
- (c-continued-statement-offset . 4)
- (c-brace-offset . -4)
- (c-argdecl-indent . 0)
+ (c-indent-level . 4)
+ (c-argdecl-indent . 0)
+ (c-brace-offset . 0)
+ (c-continued-brace-offset . -4)
(c-label-offset . -4)
- (c-auto-newline . t))
+ (c-continued-statement-offset . 4)
+ (c-auto-newline . t))
("Whitesmith"
(c-indent-level . 4)
(c-argdecl-indent . 4)
(c-brace-offset . 0)
+ (c-continued-brace-offset . 0)
(c-label-offset . -4)
(c-continued-statement-offset . 4))))
-(defconst c-auto-newline nil
+(defcustom c-auto-newline nil
"*Non-nil means automatically newline before and after braces,
and after colons and semicolons, inserted in C code.
If you do not want a leading newline before braces then use:
- (define-key c-mode-map \"{\" 'electric-c-semi)")
+ (define-key c-mode-map \"{\" 'electric-c-semi)"
+ :type 'boolean
+ :group 'old-c)
-(defconst c-tab-always-indent t
+(defcustom c-tab-always-indent t
"*Non-nil means TAB in C mode should always reindent the current line,
-regardless of where in the line point is when the TAB command is used.")
+regardless of where in the line point is when the TAB command is used."
+ :type 'boolean
+ :group 'old-c)
;;; Regular expression used internally to recognize labels in switch
;;; statements.
(defconst c-switch-label-regexp "case[ \t'/(]\\|default[ \t]*:")
+;; This is actually the expression for C++ mode, but it's used for C too.
+(defvar c-imenu-generic-expression
+ (`
+ ((nil
+ (,
+ (concat
+ "^" ; beginning of line is required
+ "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+ "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; type specs; there can be no
+ "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; more than 3 tokens, right?
+
+ "\\(" ; last type spec including */&
+ "[a-zA-Z0-9_:]+"
+ "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)" ; either pointer/ref sign or whitespace
+ "\\)?" ; if there is a last type spec
+ "\\(" ; name; take that into the imenu entry
+ "[a-zA-Z0-9_:~]+" ; member function, ctor or dtor...
+ ; (may not contain * because then
+ ; "a::operator char*" would become "char*"!)
+ "\\|"
+ "\\([a-zA-Z0-9_:~]*::\\)?operator"
+ "[^a-zA-Z1-9_][^(]*" ; ...or operator
+ " \\)"
+ "[ \t]*([^)]*)[ \t\n]*[^ ;]" ; require something other than a ; after
+ ; the (...) to avoid prototypes. Can't
+ ; catch cases with () inside the parentheses
+ ; surrounding the parameters
+ ; (like "int foo(int a=bar()) {...}"
+
+ )) 6)
+ ("Class"
+ (, (concat
+ "^" ; beginning of line is required
+ "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+ "class[ \t]+"
+ "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
+ "[ \t]*[:{]"
+ )) 2)
+;; Example of generic expression for finding prototypes, structs, unions, enums.
+;; Uncomment if you want to find these too. It will be a bit slower gathering
+;; the indexes.
+; ("Prototypes"
+; (,
+; (concat
+; "^" ; beginning of line is required
+; "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+; "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; type specs; there can be no
+; "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; more than 3 tokens, right?
+
+; "\\(" ; last type spec including */&
+; "[a-zA-Z0-9_:]+"
+; "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)" ; either pointer/ref sign or whitespace
+; "\\)?" ; if there is a last type spec
+; "\\(" ; name; take that into the imenu entry
+; "[a-zA-Z0-9_:~]+" ; member function, ctor or dtor...
+; ; (may not contain * because then
+; ; "a::operator char*" would become "char*"!)
+; "\\|"
+; "\\([a-zA-Z0-9_:~]*::\\)?operator"
+; "[^a-zA-Z1-9_][^(]*" ; ...or operator
+; " \\)"
+; "[ \t]*([^)]*)[ \t\n]*;" ; require ';' after
+; ; the (...) Can't
+; ; catch cases with () inside the parentheses
+; ; surrounding the parameters
+; ; (like "int foo(int a=bar());"
+; )) 6)
+; ("Struct"
+; (, (concat
+; "^" ; beginning of line is required
+; "\\(static[ \t]+\\)?" ; there may be static or const.
+; "\\(const[ \t]+\\)?"
+; "struct[ \t]+"
+; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
+; "[ \t]*[{]"
+; )) 3)
+; ("Enum"
+; (, (concat
+; "^" ; beginning of line is required
+; "\\(static[ \t]+\\)?" ; there may be static or const.
+; "\\(const[ \t]+\\)?"
+; "enum[ \t]+"
+; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
+; "[ \t]*[{]"
+; )) 3)
+; ("Union"
+; (, (concat
+; "^" ; beginning of line is required
+; "\\(static[ \t]+\\)?" ; there may be static or const.
+; "\\(const[ \t]+\\)?"
+; "union[ \t]+"
+; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
+; "[ \t]*[{]"
+; )) 3)
+ ))
+ "Imenu generic expression for C mode. See `imenu-generic-expression'.")
\f
(defun c-mode ()
"Major mode for editing C code.
(setq comment-multi-line t)
(make-local-variable 'parse-sexp-ignore-comments)
(setq parse-sexp-ignore-comments t)
+ (make-local-variable 'imenu-generic-expression)
+ (setq imenu-generic-expression c-imenu-generic-expression)
+ (setq imenu-case-fold-search nil)
(run-hooks 'c-mode-hook))
(defun c-outline-level ()
(paragraph-start
;; Lines containing just a comment start or just an end
;; should not be filled into paragraphs they are next to.
- (concat
+ (concat
paragraph-start
"\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$"))
(paragraph-separate
(paragraph-start
;; Lines containing just a comment start or just an end
;; should not be filled into paragraphs they are next to.
- (concat
+ (concat
paragraph-start
"\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$"))
(paragraph-separate
(if comment-start-place
(goto-char comment-start-place)
(search-backward "/*"))
- ;; Protect text before the comment start
- ;; by excluding it. Add spaces to bring back
+ ;; Protect text before the comment start
+ ;; by excluding it. Add spaces to bring back
;; proper indentation of that point.
(let ((column (current-column)))
(prog1 (point)
(search-forward "*/" nil 'move)
(forward-line 1)
(point)))
- (goto-char (point-max))
- (forward-line -1)
- ;; And comment terminator was on a separate line before,
- ;; keep it that way.
- ;; This also avoids another problem:
- ;; if the fill-prefix ends in a *, it could eat up
- ;; the * of the comment terminator.
- (if (looking-at "[ \t]*\\*/")
- (narrow-to-region (point-min) (point)))
+ (save-excursion
+ (goto-char (point-max))
+ (forward-line -1)
+ ;; And comment terminator was on a separate line before,
+ ;; keep it that way.
+ ;; This also avoids another problem:
+ ;; if the fill-prefix ends in a *, it could eat up
+ ;; the * of the comment terminator.
+ (if (looking-at "[ \t]*\\*/")
+ (narrow-to-region (point-min) (point))))
(fill-paragraph arg)
(save-excursion
;; Delete the chars we inserted to avoid clobbering
;; The first following code counts
;; if it is before the line we want to indent.
(and (< (point) indent-point)
- (-
+ (-
(if (> colon-line-end (point))
(- (current-indentation) c-label-offset)
(current-column))
(if (= (following-char) ?\{) c-brace-offset 0)))))
;; If no previous statement,
;; indent it relative to line brace is on.
- ;; For open brace in column zero, don't let statement
- ;; start there too. If c-indent-level is zero,
- ;; use c-brace-offset + c-continued-statement-offset instead.
- ;; For open-braces not the first thing in a line,
- ;; add in c-brace-imaginary-offset.
- (+ (if (and (bolp) (zerop c-indent-level))
- (+ c-brace-offset c-continued-statement-offset)
- c-indent-level)
- ;; Move back over whitespace before the openbrace.
- ;; If openbrace is not first nonwhite thing on the line,
- ;; add the c-brace-imaginary-offset.
- (progn (skip-chars-backward " \t")
- (if (bolp) 0 c-brace-imaginary-offset))
- ;; If the openbrace is preceded by a parenthesized exp,
- ;; move to the beginning of that;
- ;; possibly a different line
- (progn
- (if (eq (preceding-char) ?\))
- (forward-sexp -1))
- ;; Get initial indentation of the line we are on.
- (current-indentation))))))))))
+ (calculate-c-indent-after-brace))))))))
+
+(defun calculate-c-indent-after-brace ()
+ "Return the proper C indent for the first line after an open-brace.
+This function is called with point before the brace."
+ ;; For open brace in column zero, don't let statement
+ ;; start there too. If c-indent-level is zero,
+ ;; use c-brace-offset + c-continued-statement-offset instead.
+ ;; For open-braces not the first thing in a line,
+ ;; add in c-brace-imaginary-offset.
+ (+ (if (and (bolp) (zerop c-indent-level))
+ (+ c-brace-offset c-continued-statement-offset)
+ c-indent-level)
+ ;; Move back over whitespace before the openbrace.
+ ;; If openbrace is not first nonwhite thing on the line,
+ ;; add the c-brace-imaginary-offset.
+ (progn (skip-chars-backward " \t")
+ (if (bolp) 0 c-brace-imaginary-offset))
+ ;; If the openbrace is preceded by a parenthesized exp,
+ ;; move to the beginning of that;
+ ;; possibly a different line
+ (progn
+ (if (eq (preceding-char) ?\))
+ (forward-sexp -1))
+ ;; Get initial indentation of the line we are on.
+ (current-indentation))))
(defun calculate-c-indent-within-comment (&optional after-star)
"Return the indentation amount for line inside a block comment.
(not (re-search-forward "[;{}]" end t)))))))
(re-search-backward "[;}]")
(forward-char 1))
- (error
+ (error
(let ((beg (point)))
(backward-up-list -1)
(let ((end (point)))
(if (= (char-after (car contain-stack)) ?{)
(save-excursion
(goto-char (car contain-stack))
- (setq val (+ c-indent-level (current-column))))
+ (setq val (calculate-c-indent-after-brace)))
(setq val (calculate-c-indent
(if (car indent-stack)
(- (car indent-stack))
\f
;;; This page handles insertion and removal of backslashes for C macros.
-(defvar c-backslash-column 48
- "*Minimum column for end-of-line backslashes of macro definitions.")
+(defcustom c-backslash-column 48
+ "*Minimum column for end-of-line backslashes of macro definitions."
+ :type 'integer
+ :group 'old-c)
(defun c-backslash-region (from to delete-flag)
"Insert, align, or delete end-of-line backslashes on the lines in the region.
With no argument, inserts backslashes and aligns existing backslashes.
With an argument, deletes the backslashes.
-This function does not modify the last line of the region if the region ends
+This function does not modify the last line of the region if the region ends
right at the start of the following line; it does not modify blank lines
at the start of the region. So you can put the region around an entire macro
definition and conveniently use this command."
(setq count (+ count increment))))
(push-mark)
(goto-char new)))
+\f
+(provide 'c-mode)
;;; c-mode.el ends here