*** empty log message ***
[bpt/emacs.git] / lisp / progmodes / c-mode.el
CommitLineData
c0274f38
ER
1;;; c-mode.el --- C code editing commands for Emacs
2
e5167999
ER
3;; Maintainer: FSF
4;; Last-Modified: 11 Jul 1992
5;; Keywords: c
6
a17915dc
ER
7;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
e5167999 13;; the Free Software Foundation; either version 2, or (at your option)
a17915dc
ER
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to
23;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24
e5167999 25;;; Code:
a17915dc
ER
26
27(defvar c-mode-abbrev-table nil
28 "Abbrev table in use in C mode.")
29(define-abbrev-table 'c-mode-abbrev-table ())
30
31(defvar c-mode-map ()
32 "Keymap used in C mode.")
33(if c-mode-map
34 ()
35 (setq c-mode-map (make-sparse-keymap))
36 (define-key c-mode-map "{" 'electric-c-brace)
37 (define-key c-mode-map "}" 'electric-c-brace)
38 (define-key c-mode-map ";" 'electric-c-semi)
39 (define-key c-mode-map "#" 'electric-c-sharp-sign)
40 (define-key c-mode-map ":" 'electric-c-terminator)
41 (define-key c-mode-map "\e\C-h" 'mark-c-function)
42 (define-key c-mode-map "\e\C-q" 'indent-c-exp)
43 (define-key c-mode-map "\ea" 'c-beginning-of-statement)
44 (define-key c-mode-map "\ee" 'c-end-of-statement)
45 (define-key c-mode-map "\eq" 'c-fill-paragraph)
46 (define-key c-mode-map "\177" 'backward-delete-char-untabify)
47 (define-key c-mode-map "\t" 'c-indent-command))
48
49;; cmacexp is lame because it uses no preprocessor symbols.
50;; It isn't very extensible either -- hardcodes /lib/cpp.
51(autoload 'c-macro-expand "cmacexp"
52 "Display the result of expanding all C macros occurring in the region.
53The expansion is entirely correct because it uses the C preprocessor."
54 t)
55
56(defvar c-mode-syntax-table nil
57 "Syntax table in use in C-mode buffers.")
58
59(if c-mode-syntax-table
60 ()
61 (setq c-mode-syntax-table (make-syntax-table))
62 (modify-syntax-entry ?\\ "\\" c-mode-syntax-table)
63 (modify-syntax-entry ?/ ". 14" c-mode-syntax-table)
64 (modify-syntax-entry ?* ". 23" c-mode-syntax-table)
65 (modify-syntax-entry ?+ "." c-mode-syntax-table)
66 (modify-syntax-entry ?- "." c-mode-syntax-table)
67 (modify-syntax-entry ?= "." c-mode-syntax-table)
68 (modify-syntax-entry ?% "." c-mode-syntax-table)
69 (modify-syntax-entry ?< "." c-mode-syntax-table)
70 (modify-syntax-entry ?> "." c-mode-syntax-table)
71 (modify-syntax-entry ?& "." c-mode-syntax-table)
72 (modify-syntax-entry ?| "." c-mode-syntax-table)
73 (modify-syntax-entry ?\' "\"" c-mode-syntax-table))
74
75(defconst c-indent-level 2
76 "*Indentation of C statements with respect to containing block.")
77(defconst c-brace-imaginary-offset 0
78 "*Imagined indentation of a C open brace that actually follows a statement.")
79(defconst c-brace-offset 0
80 "*Extra indentation for braces, compared with other text in same context.")
81(defconst c-argdecl-indent 5
82 "*Indentation level of declarations of C function arguments.")
83(defconst c-label-offset -2
84 "*Offset of C label lines and case statements relative to usual indentation.")
85(defconst c-continued-statement-offset 2
86 "*Extra indent for lines not starting new statements.")
87(defconst c-continued-brace-offset 0
88 "*Extra indent for substatements that start with open-braces.
89This is in addition to c-continued-statement-offset.")
90(defconst c-style-alist
91 '(("GNU"
92 (c-indent-level . 2)
93 (c-argdecl-indent . 5)
94 (c-brace-offset . 0)
95 (c-label-offset . -2)
96 (c-continued-statement-offset . 2))
97 ("K&R"
98 (c-indent-level . 5)
99 (c-argdecl-indent . 0)
100 (c-brace-offset . -5)
101 (c-label-offset . -5)
102 (c-continued-statement-offset . 5))
103 ("BSD"
104 (c-indent-level . 4)
105 (c-argdecl-indent . 4)
106 (c-brace-offset . -4)
107 (c-label-offset . -4)
108 (c-continued-statement-offset . 4))
2b529dd2
JB
109 (C++
110 (c-indent-level . 4)
111 (c-continued-statement-offset . 4)
112 (c-brace-offset . -4)
113 (c-argdecl-indent . 0)
114 (c-label-offset . -4)
115 (c-auto-newline . t))
a17915dc
ER
116 ("Whitesmith"
117 (c-indent-level . 4)
118 (c-argdecl-indent . 4)
119 (c-brace-offset . 0)
120 (c-label-offset . -4)
121 (c-continued-statement-offset . 4))))
122
123(defconst c-auto-newline nil
124 "*Non-nil means automatically newline before and after braces,
125and after colons and semicolons, inserted in C code.
126If you do not want a leading newline before braces then use:
127 (define-key c-mode-map "{" 'electric-c-semi)")
128
129(defconst c-tab-always-indent t
130 "*Non-nil means TAB in C mode should always reindent the current line,
131regardless of where in the line point is when the TAB command is used.")
132\f
a17915dc
ER
133(defun c-mode ()
134 "Major mode for editing C code.
135Expression and list commands understand all C brackets.
136Tab indents for C code.
137Comments are delimited with /* ... */.
138Paragraphs are separated by blank lines only.
139Delete converts tabs to spaces as it moves back.
140\\{c-mode-map}
141Variables controlling indentation style:
142 c-tab-always-indent
143 Non-nil means TAB in C mode should always reindent the current line,
144 regardless of where in the line point is when the TAB command is used.
145 c-auto-newline
146 Non-nil means automatically newline before and after braces,
147 and after colons and semicolons, inserted in C code.
148 c-indent-level
149 Indentation of C statements within surrounding block.
150 The surrounding block's indentation is the indentation
151 of the line on which the open-brace appears.
152 c-continued-statement-offset
153 Extra indentation given to a substatement, such as the
154 then-clause of an if or body of a while.
155 c-continued-brace-offset
156 Extra indentation given to a brace that starts a substatement.
157 This is in addition to c-continued-statement-offset.
158 c-brace-offset
159 Extra indentation for line if it starts with an open brace.
160 c-brace-imaginary-offset
161 An open brace following other text is treated as if it were
162 this far to the right of the start of its line.
163 c-argdecl-indent
164 Indentation level of declarations of C function arguments.
165 c-label-offset
166 Extra indentation for line that is a label, or case or default.
167
168Settings for K&R and BSD indentation styles are
169 c-indent-level 5 8
170 c-continued-statement-offset 5 8
171 c-brace-offset -5 -8
172 c-argdecl-indent 0 8
173 c-label-offset -5 -8
174
175Turning on C mode calls the value of the variable c-mode-hook with no args,
176if that value is non-nil."
177 (interactive)
178 (kill-all-local-variables)
179 (use-local-map c-mode-map)
180 (setq major-mode 'c-mode)
181 (setq mode-name "C")
182 (setq local-abbrev-table c-mode-abbrev-table)
183 (set-syntax-table c-mode-syntax-table)
184 (make-local-variable 'paragraph-start)
185 (setq paragraph-start (concat "^$\\|" page-delimiter))
186 (make-local-variable 'paragraph-separate)
187 (setq paragraph-separate paragraph-start)
188 (make-local-variable 'paragraph-ignore-fill-prefix)
189 (setq paragraph-ignore-fill-prefix t)
190 (make-local-variable 'indent-line-function)
191 (setq indent-line-function 'c-indent-line)
192 (make-local-variable 'indent-region-function)
193 (setq indent-region-function 'c-indent-region)
194 (make-local-variable 'require-final-newline)
195 (setq require-final-newline t)
196 (make-local-variable 'comment-start)
197 (setq comment-start "/* ")
198 (make-local-variable 'comment-end)
199 (setq comment-end " */")
200 (make-local-variable 'comment-column)
201 (setq comment-column 32)
202 (make-local-variable 'comment-start-skip)
203 (setq comment-start-skip "/\\*+ *")
204 (make-local-variable 'comment-indent-hook)
205 (setq comment-indent-hook 'c-comment-indent)
206 (make-local-variable 'parse-sexp-ignore-comments)
207 (setq parse-sexp-ignore-comments t)
208 (run-hooks 'c-mode-hook))
209\f
210;; This is used by indent-for-comment
211;; to decide how much to indent a comment in C code
212;; based on its context.
213(defun c-comment-indent ()
214 (if (looking-at "^/\\*")
215 0 ;Existing comment at bol stays there.
216 (let ((opoint (point)))
217 (save-excursion
218 (beginning-of-line)
219 (cond ((looking-at "[ \t]*}[ \t]*\\($\\|/\\*\\)")
220 ;; A comment following a solitary close-brace
221 ;; should have only one space.
222 (search-forward "}")
223 (1+ (current-column)))
224 ((or (looking-at "^#[ \t]*endif[ \t]*")
225 (looking-at "^#[ \t]*else[ \t]*"))
226 7) ;2 spaces after #endif
227 ((progn
228 (goto-char opoint)
229 (skip-chars-backward " \t")
230 (and (= comment-column 0) (bolp)))
231 ;; If comment-column is 0, and nothing but space
232 ;; before the comment, align it at 0 rather than 1.
233 0)
234 (t
235 (max (1+ (current-column)) ;Else indent at comment column
236 comment-column))))))) ; except leave at least one space.
237
238(defun c-fill-paragraph (&optional arg)
239 "Like \\[fill-paragraph] but handle C comments.
240If point is inside a comment, the current paragraph of the comment
241is filled, preserving the comment indentation or line-starting decorations."
242 (interactive "P")
243 (let ((first-line
244 (save-excursion
245 (beginning-of-line)
246 (skip-chars-forward " \t")
247 (looking-at comment-start-skip))))
248 (if (or first-line
249 (eq (calculate-c-indent) t))
250 ;; Inside a comment: fill one comment paragraph.
251 (let ((fill-prefix
252 ;; The prefix for each line of this paragraph
253 ;; is the appropriate part of the start of this line,
254 ;; up to the column at which text should be indented.
255 (save-excursion
256 (beginning-of-line)
257 (if (looking-at "[ \t]*/\\*.*\\*/")
258 (progn (re-search-forward comment-start-skip)
259 (make-string (current-column) ?\ ))
260 (if first-line (forward-line 1))
261 (buffer-substring (point)
262 (progn
263 (move-to-column
264 (calculate-c-indent-within-comment t)
265 t)
266 (point))))))
267 (paragraph-start
268 ;; Lines containing just a comment start or just an end
269 ;; should not be filled into paragraphs they are next to.
270 (concat paragraph-start
271 "\\|^[ \t]*/\\*[ \t]*$\\|^[ \t]*\\*/[ \t]*$\\|^[^ \t/*]"))
272 (paragraph-separate
273 (concat paragraph-separate
274 "\\|^[ \t]*/\\*[ \t]*$\\|^[ \t]*\\*/[ \t]*$\\|^[^ \t/*]")))
275 (save-restriction
276 ;; Don't fill the comment together with the code following it.
277 (narrow-to-region (point-min)
278 (save-excursion
279 (search-forward "*/" nil 'move)
280 (forward-line 1)
281 (point)))
282 (fill-paragraph arg)
283 (save-excursion
284 (search-forward "*/")
285 (beginning-of-line)
286 (if (looking-at "[ \t]*\\*/")
287 (delete-indentation)))))
288 ;; Outside of comments: do ordinary filling.
289 (fill-paragraph arg))))
290
291(defun electric-c-brace (arg)
292 "Insert character and correct line's indentation."
293 (interactive "P")
294 (let (insertpos)
295 (if (and (not arg)
296 (eolp)
297 (or (save-excursion
298 (skip-chars-backward " \t")
299 (bolp))
300 (if c-auto-newline (progn (c-indent-line) (newline) t) nil)))
301 (progn
302 (insert last-command-char)
303 (c-indent-line)
304 (if c-auto-newline
305 (progn
306 (newline)
307 ;; (newline) may have done auto-fill
308 (setq insertpos (- (point) 2))
309 (c-indent-line)))
310 (save-excursion
311 (if insertpos (goto-char (1+ insertpos)))
312 (delete-char -1))))
313 (if insertpos
314 (save-excursion
315 (goto-char insertpos)
316 (self-insert-command (prefix-numeric-value arg)))
317 (self-insert-command (prefix-numeric-value arg)))))
318
319(defun electric-c-sharp-sign (arg)
320 "Insert character and correct line's indentation."
321 (interactive "P")
322 (if (save-excursion
323 (skip-chars-backward " \t")
324 (bolp))
325 (let ((c-auto-newline nil))
326 (electric-c-terminator arg))
327 (self-insert-command (prefix-numeric-value arg))))
328
329(defun electric-c-semi (arg)
330 "Insert character and correct line's indentation."
331 (interactive "P")
332 (if c-auto-newline
333 (electric-c-terminator arg)
334 (self-insert-command (prefix-numeric-value arg))))
335
336(defun electric-c-terminator (arg)
337 "Insert character and correct line's indentation."
338 (interactive "P")
339 (let (insertpos (end (point)))
340 (if (and (not arg) (eolp)
341 (not (save-excursion
342 (beginning-of-line)
343 (skip-chars-forward " \t")
344 (or (= (following-char) ?#)
345 ;; Colon is special only after a label, or case ....
346 ;; So quickly rule out most other uses of colon
347 ;; and do no indentation for them.
348 (and (eq last-command-char ?:)
349 (not (looking-at "case[ \t'/(]\\|default\\>"))
350 (save-excursion
351 (skip-chars-forward "a-zA-Z0-9_$")
352 (skip-chars-forward " \t")
353 (< (point) end)))
354 (progn
355 (beginning-of-defun)
356 (let ((pps (parse-partial-sexp (point) end)))
357 (or (nth 3 pps) (nth 4 pps) (nth 5 pps))))))))
358 (progn
359 (insert last-command-char)
360 (c-indent-line)
361 (and c-auto-newline
362 (not (c-inside-parens-p))
363 (progn
364 (newline)
365 ;; (newline) may have done auto-fill
366 (setq insertpos (- (point) 2))
367 (c-indent-line)))
368 (save-excursion
369 (if insertpos (goto-char (1+ insertpos)))
370 (delete-char -1))))
371 (if insertpos
372 (save-excursion
373 (goto-char insertpos)
374 (self-insert-command (prefix-numeric-value arg)))
375 (self-insert-command (prefix-numeric-value arg)))))
376
377(defun c-inside-parens-p ()
378 (condition-case ()
379 (save-excursion
380 (save-restriction
381 (narrow-to-region (point)
382 (progn (beginning-of-defun) (point)))
383 (goto-char (point-max))
384 (= (char-after (or (scan-lists (point) -1 1) (point-min))) ?\()))
385 (error nil)))
386\f
387(defun c-indent-command (&optional whole-exp)
388 "Indent current line as C code, or in some cases insert a tab character.
389If `c-tab-always-indent' is non-nil (the default), always indent current line.
390Otherwise, indent the current line only if point is at the left margin or
391in the line's indentation; otherwise insert a tab.
392
393A numeric argument, regardless of its value, means indent rigidly all the
394lines of the expression starting after point so that this line becomes
395properly indented. The relative indentation among the lines of the
396expression are preserved."
397 (interactive "P")
398 (if whole-exp
399 ;; If arg, always indent this line as C
400 ;; and shift remaining lines of expression the same amount.
401 (let ((shift-amt (c-indent-line))
402 beg end)
403 (save-excursion
404 (if c-tab-always-indent
405 (beginning-of-line))
406 ;; Find beginning of following line.
407 (save-excursion
408 (forward-line 1) (setq beg (point)))
409 ;; Find first beginning-of-sexp for sexp extending past this line.
410 (while (< (point) beg)
411 (forward-sexp 1)
412 (setq end (point))
413 (skip-chars-forward " \t\n")))
414 (if (> end beg)
415 (indent-code-rigidly beg end shift-amt "#")))
416 (if (and (not c-tab-always-indent)
417 (save-excursion
418 (skip-chars-backward " \t")
419 (not (bolp))))
420 (insert-tab)
421 (c-indent-line))))
422
423(defun c-indent-line ()
424 "Indent current line as C code.
425Return the amount the indentation changed by."
426 (let ((indent (calculate-c-indent nil))
427 beg shift-amt
428 (case-fold-search nil)
429 (pos (- (point-max) (point))))
430 (beginning-of-line)
431 (setq beg (point))
432 (cond ((eq indent nil)
433 (setq indent (current-indentation)))
434 ((eq indent t)
435 (setq indent (calculate-c-indent-within-comment)))
436 ((looking-at "[ \t]*#")
437 (setq indent 0))
438 (t
439 (skip-chars-forward " \t")
440 (if (listp indent) (setq indent (car indent)))
441 (cond ((or (looking-at "case[ \t'/(]\\|default\\>")
442 (and (looking-at "[A-Za-z]")
443 (save-excursion
444 (forward-sexp 1)
445 (looking-at ":"))))
446 (setq indent (max 1 (+ indent c-label-offset))))
447 ((and (looking-at "else\\b")
448 (not (looking-at "else\\s_")))
449 (setq indent (save-excursion
450 (c-backward-to-start-of-if)
451 (current-indentation))))
452 ((looking-at "}[ \t]*else")
453 (setq indent (save-excursion
454 (forward-char)
455 (backward-sexp)
456 (current-indentation))))
457 ((and (looking-at "while\\b")
458 (save-excursion
459 (c-backward-to-start-of-do)))
460 ;; This is a `while' that ends a do-while.
461 (setq indent (save-excursion
462 (c-backward-to-start-of-do)
463 (current-indentation))))
464 ((= (following-char) ?})
465 (setq indent (- indent c-indent-level)))
466 ((= (following-char) ?{)
467 (setq indent (+ indent c-brace-offset))))))
468 (skip-chars-forward " \t")
469 (setq shift-amt (- indent (current-column)))
470 (if (zerop shift-amt)
471 (if (> (- (point-max) pos) (point))
472 (goto-char (- (point-max) pos)))
473 (delete-region beg (point))
474 (indent-to indent)
475 ;; If initial point was within line's indentation,
476 ;; position after the indentation. Else stay at same point in text.
477 (if (> (- (point-max) pos) (point))
478 (goto-char (- (point-max) pos))))
479 shift-amt))
480
481(defun calculate-c-indent (&optional parse-start)
482 "Return appropriate indentation for current line as C code.
483In usual case returns an integer: the column to indent to.
484Returns nil if line starts inside a string, t if in a comment."
485 (save-excursion
486 (beginning-of-line)
487 (let ((indent-point (point))
488 (case-fold-search nil)
489 state
490 containing-sexp)
491 (if parse-start
492 (goto-char parse-start)
493 (beginning-of-defun))
494 (while (< (point) indent-point)
495 (setq parse-start (point))
496 (setq state (parse-partial-sexp (point) indent-point 0))
497 (setq containing-sexp (car (cdr state))))
498 (cond ((or (nth 3 state) (nth 4 state))
499 ;; return nil or t if should not change this line
500 (nth 4 state))
501 ((null containing-sexp)
502 ;; Line is at top level. May be data or function definition,
503 ;; or may be function argument declaration.
504 ;; Indent like the previous top level line
505 ;; unless that ends in a closeparen without semicolon,
506 ;; in which case this line is the first argument decl.
507 (goto-char indent-point)
508 (skip-chars-forward " \t")
509 (if (= (following-char) ?{)
510 0 ; Unless it starts a function body
511 (c-backward-to-noncomment (or parse-start (point-min)))
512 ;; Look at previous line that's at column 0
513 ;; to determine whether we are in top-level decls
514 ;; or function's arg decls. Set basic-indent accordingly.
515 (let ((basic-indent
516 (save-excursion
517 (re-search-backward "^[^ \^L\t\n#]" nil 'move)
c763f396
RS
518 (let (comment lim)
519 (if (and (looking-at "\\sw\\|\\s_")
520 (looking-at "[^\"\n=]*(")
521 (progn
522 (goto-char (1- (match-end 0)))
523 (setq lim (point))
524 (forward-sexp 1)
525 (skip-chars-forward " \t\f")
526 (and (< (point) indent-point)
527 (not (memq (following-char)
528 '(?\, ?\;)))))
529 ;; Make sure the "function decl" we found
530 ;; is not inside a comment.
531 (progn
532 (beginning-of-line)
533 (while (and (not comment)
534 (search-forward "/*" lim t))
535 (setq comment
536 (not (search-forward "*/" lim t))))
537 (not comment)))
538 c-argdecl-indent 0)))))
a17915dc
ER
539 basic-indent)))
540
541;; ;; Now add a little if this is a continuation line.
542;; (+ basic-indent (if (or (bobp)
543;; (memq (preceding-char) '(?\) ?\; ?\}))
544;; ;; Line with zero indentation
545;; ;; is probably the return-type
546;; ;; of a function definition,
547;; ;; so following line is function name.
548;; (= (current-indentation) 0))
549;; 0 c-continued-statement-offset))
550
551 ((/= (char-after containing-sexp) ?{)
552 ;; line is expression, not statement:
553 ;; indent to just after the surrounding open.
554 (goto-char (1+ containing-sexp))
555 (current-column))
556 (t
557 ;; Statement level. Is it a continuation or a new statement?
558 ;; Find previous non-comment character.
559 (goto-char indent-point)
560 (c-backward-to-noncomment containing-sexp)
561 ;; Back up over label lines, since they don't
562 ;; affect whether our line is a continuation.
563 (while (or (eq (preceding-char) ?\,)
564 (and (eq (preceding-char) ?:)
565 (or (eq (char-after (- (point) 2)) ?\')
566 (memq (char-syntax (char-after (- (point) 2)))
567 '(?w ?_)))))
568 (if (eq (preceding-char) ?\,)
569 (progn (forward-char -1)
570 (c-backward-to-start-of-continued-exp containing-sexp)))
571 (beginning-of-line)
572 (c-backward-to-noncomment containing-sexp))
573 ;; Check for a preprocessor statement or its continuation lines.
574 ;; Move back to end of previous non-preprocessor line.
575 (let ((found (point)) stop)
576 (while (not stop)
577 (cond ((save-excursion (end-of-line 0)
578 (= (preceding-char) ?\\))
579 (end-of-line 0))
580 ;; This line is not preceded by a backslash.
581 ;; So either it starts a preprocessor command
582 ;; or any following continuation lines
583 ;; should not be skipped.
584 ((progn (beginning-of-line) (= (following-char) ?#))
585 (end-of-line 0)
586 (setq found (point)))
587 (t (setq stop t))))
588 (goto-char found))
589 ;; Now we get the answer.
590 (if (and (not (memq (preceding-char) '(nil ?\, ?\; ?\} ?\{)))
591 ;; But don't treat a line with a close-brace
592 ;; as a continuation. It is probably the
593 ;; end of an enum type declaration.
594 (save-excursion
595 (goto-char indent-point)
596 (skip-chars-forward " \t")
597 (not (= (following-char) ?}))))
598 ;; This line is continuation of preceding line's statement;
599 ;; indent c-continued-statement-offset more than the
600 ;; previous line of the statement.
601 (progn
602 (c-backward-to-start-of-continued-exp containing-sexp)
603 (+ c-continued-statement-offset (current-column)
604 (if (save-excursion (goto-char indent-point)
605 (skip-chars-forward " \t")
606 (eq (following-char) ?{))
607 c-continued-brace-offset 0)))
608 ;; This line starts a new statement.
609 ;; Position following last unclosed open.
610 (goto-char containing-sexp)
611 ;; Is line first statement after an open-brace?
612 (or
613 ;; If no, find that first statement and indent like it.
614 (save-excursion
615 (forward-char 1)
616 (let ((colon-line-end 0))
617 (while (progn (skip-chars-forward " \t\n")
618 (looking-at "#\\|/\\*\\|case[ \t\n'/(].*:\\|[a-zA-Z0-9_$]*:"))
619 ;; Skip over comments and labels following openbrace.
620 (cond ((= (following-char) ?\#)
621 (forward-line 1))
622 ((= (following-char) ?\/)
623 (forward-char 2)
624 (search-forward "*/" nil 'move))
625 ;; case or label:
626 (t
627 (save-excursion (end-of-line)
628 (setq colon-line-end (point)))
629 (search-forward ":"))))
630 ;; The first following code counts
631 ;; if it is before the line we want to indent.
632 (and (< (point) indent-point)
633 (if (> colon-line-end (point))
634 (- (current-indentation) c-label-offset)
635 (current-column)))))
636 ;; If no previous statement,
637 ;; indent it relative to line brace is on.
638 ;; For open brace in column zero, don't let statement
639 ;; start there too. If c-indent-level is zero,
640 ;; use c-brace-offset + c-continued-statement-offset instead.
641 ;; For open-braces not the first thing in a line,
642 ;; add in c-brace-imaginary-offset.
643 (+ (if (and (bolp) (zerop c-indent-level))
644 (+ c-brace-offset c-continued-statement-offset)
645 c-indent-level)
646 ;; Move back over whitespace before the openbrace.
647 ;; If openbrace is not first nonwhite thing on the line,
648 ;; add the c-brace-imaginary-offset.
649 (progn (skip-chars-backward " \t")
650 (if (bolp) 0 c-brace-imaginary-offset))
651 ;; If the openbrace is preceded by a parenthesized exp,
652 ;; move to the beginning of that;
653 ;; possibly a different line
654 (progn
655 (if (eq (preceding-char) ?\))
656 (forward-sexp -1))
657 ;; Get initial indentation of the line we are on.
658 (current-indentation))))))))))
659
660(defun calculate-c-indent-within-comment (&optional after-star)
661 "Return the indentation amount for line inside a block comment.
662Optional arg AFTER-STAR means, if lines in the comment have a leading star,
663return the indentation of the text that would follow this star."
664 (let (end star-start)
665 (save-excursion
666 (beginning-of-line)
667 (skip-chars-forward " \t")
668 (setq star-start (= (following-char) ?\*))
669 (skip-chars-backward " \t\n")
670 (setq end (point))
671 (beginning-of-line)
672 (skip-chars-forward " \t")
673 (if after-star
674 (and (looking-at "\\*")
675 (re-search-forward "\\*[ \t]*")))
676 (and (re-search-forward "/\\*[ \t]*" end t)
677 star-start
678 (not after-star)
679 (goto-char (1+ (match-beginning 0))))
680 (if (and (looking-at "[ \t]*$") (= (preceding-char) ?\*))
681 (1+ (current-column))
682 (current-column)))))
683
684
685(defun c-backward-to-noncomment (lim)
686 (let (opoint stop)
687 (while (not stop)
688 (skip-chars-backward " \t\n\f" lim)
689 (setq opoint (point))
690 (if (and (>= (point) (+ 2 lim))
691 (save-excursion
692 (forward-char -2)
693 (looking-at "\\*/")))
694 (search-backward "/*" lim 'move)
695 (setq stop (or (<= (point) lim)
696 (save-excursion
697 (beginning-of-line)
698 (skip-chars-forward " \t")
699 (not (looking-at "#")))))
700 (or stop (beginning-of-line))))))
701
702(defun c-backward-to-start-of-continued-exp (lim)
703 (if (memq (preceding-char) '(?\) ?\"))
704 (forward-sexp -1))
705 (beginning-of-line)
706 (if (<= (point) lim)
707 (goto-char (1+ lim)))
708 (skip-chars-forward " \t"))
709
710(defun c-backward-to-start-of-if (&optional limit)
711 "Move to the start of the last \"unbalanced\" `if'."
712 (or limit (setq limit (save-excursion (beginning-of-defun) (point))))
713 (let ((if-level 1)
714 (case-fold-search nil))
715 (while (and (not (bobp)) (not (zerop if-level)))
716 (backward-sexp 1)
717 (cond ((looking-at "else\\b")
718 (setq if-level (1+ if-level)))
719 ((looking-at "if\\b")
720 (setq if-level (1- if-level)))
721 ((< (point) limit)
722 (setq if-level 0)
723 (goto-char limit))))))
724
725(defun c-backward-to-start-of-do (&optional limit)
726 "If point follows a `do' statement, move to beginning of it and return t.
727Otherwise return nil and don't move point."
728 (or limit (setq limit (save-excursion (beginning-of-defun) (point))))
729 (let ((first t)
730 (startpos (point))
731 (done nil))
732 (while (not done)
733 (let ((next-start (point)))
734 (condition-case nil
735 ;; Move back one token or one brace or paren group.
736 (backward-sexp 1)
737 ;; If we find an open-brace, we lose.
738 (error (setq done 'fail)))
739 (if done
740 nil
741 ;; If we reached a `do', we win.
742 (if (looking-at "do\\b")
743 (setq done 'succeed)
744 ;; Otherwise, if we skipped a semicolon, we lose.
745 ;; (Exception: we can skip one semicolon before getting
746 ;; to a the last token of the statement, unless that token
747 ;; is a close brace.)
748 (if (save-excursion
749 (forward-sexp 1)
750 (or (and (not first) (= (preceding-char) ?}))
751 (search-forward ";" next-start t
752 (if (and first
753 (/= (preceding-char) ?}))
754 2 1))))
755 (setq done 'fail)
756 (setq first nil)
757 ;; If we go too far back in the buffer, we lose.
758 (if (< (point) limit)
759 (setq done 'fail)))))))
760 (if (eq done 'succeed)
761 t
762 (goto-char startpos)
763 nil)))
764\f
765(defun c-beginning-of-statement (count)
766 "Go to the beginning of the innermost C statement.
767With prefix arg, go back N - 1 statements. If already at the beginning of a
768statement then go to the beginning of the preceeding one."
769 (interactive "p")
770 (while (> count 0)
771 (c-beginning-of-statement-1)
772 (setq count (1- count)))
773 (while (< count 0)
774 (c-end-of-statement-1)
775 (setq count (1+ count))))
776
777(defun c-end-of-statement (count)
778 "Go to the end of the innermost C statement.
779With prefix arg, go forward N - 1 statements. Moves forward to end of the
780next statement if already at end."
781 (interactive "p")
782 (c-beginning-of-statement (- count)))
783
784(defun c-beginning-of-statement-1 ()
785 (let ((last-begin (point))
786 (first t))
787 (condition-case ()
788 (progn
789 (while (and (not (bobp))
790 (progn
791 (backward-sexp 1)
792 (or first
793 (not (re-search-forward "[;{}]" last-begin t)))))
794 (setq last-begin (point) first nil))
795 (goto-char last-begin))
796 (error (if first (backward-up-list 1) (goto-char last-begin))))))
797
798(defun c-end-of-statement-1 ()
799 (condition-case ()
800 (progn
801 (while (and (not (eobp))
802 (let ((beg (point)))
803 (forward-sexp 1)
804 (let ((end (point)))
805 (save-excursion
806 (goto-char beg)
807 (not (re-search-forward "[;{}]" end t)))))))
808 (re-search-backward "[;}]")
809 (forward-char 1))
810 (error
811 (let ((beg (point)))
812 (backward-up-list -1)
813 (let ((end (point)))
814 (goto-char beg)
815 (search-forward ";" end 'move))))))
816\f
817(defun mark-c-function ()
818 "Put mark at end of C function, point at beginning."
819 (interactive)
820 (push-mark (point))
821 (end-of-defun)
822 (push-mark (point))
823 (beginning-of-defun)
824 (backward-paragraph))
825\f
826(defun indent-c-exp (&optional endpos)
827 "Indent each line of the C grouping following point.
828If optional arg ENDPOS is given, indent each line, stopping when
829ENDPOS is encountered."
830 (interactive)
831 (let* ((indent-stack (list nil))
832 (opoint (point)) ;; May be altered below.
833 (contain-stack
834 (list (if endpos
835 (let (funbeg)
836 ;; Find previous fcn-start.
837 (save-excursion (forward-char 1)
838 (beginning-of-defun)
839 (setq funbeg (point)))
840 ;; Try to find containing open,
841 ;; but don't scan past that fcn-start.
842 (save-restriction
843 (narrow-to-region funbeg (point))
844 (condition-case nil
845 (save-excursion
846 (backward-up-list 1) (point))
847 ;; We gave up: must be between fcns.
848 ;; Set opoint to beg of prev fcn
849 ;; since otherwise calculate-c-indent
850 ;; will get wrong answers.
851 (error (setq opoint funbeg)
852 (point)))))
853 (point))))
854 (case-fold-search nil)
855 restart outer-loop-done inner-loop-done state ostate
856 this-indent last-sexp
857 at-else at-brace at-while
858 last-depth
859 (next-depth 0))
860 ;; If the braces don't match, get an error right away.
861 (save-excursion
862 (forward-sexp 1))
863 ;; Realign the comment on the first line, even though we don't reindent it.
864 (save-excursion
865 (let ((beg (point)))
866 (and (re-search-forward
867 comment-start-skip
868 (save-excursion (end-of-line) (point)) t)
869 ;; Make sure the comment starter we found
870 ;; is not actually in a string or quoted.
871 (let ((new-state
872 (parse-partial-sexp beg (point)
873 nil nil state)))
874 (and (not (nth 3 new-state)) (not (nth 5 new-state))))
875 (progn (indent-for-comment) (beginning-of-line)))))
876 (save-excursion
877 (setq outer-loop-done nil)
878 (while (and (not (eobp))
879 (if endpos (< (point) endpos)
880 (not outer-loop-done)))
881 (setq last-depth next-depth)
882 ;; Compute how depth changes over this line
883 ;; plus enough other lines to get to one that
884 ;; does not end inside a comment or string.
885 ;; Meanwhile, do appropriate indentation on comment lines.
886 (setq inner-loop-done nil)
887 (while (and (not inner-loop-done)
888 (not (and (eobp) (setq outer-loop-done t))))
889 (setq ostate state)
890 (setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
891 nil nil state))
892 (setq next-depth (car state))
893 (if (and (car (cdr (cdr state)))
894 (>= (car (cdr (cdr state))) 0))
895 (setq last-sexp (car (cdr (cdr state)))))
896 (if (or (nth 4 ostate))
897 (c-indent-line))
898 (if (or (nth 3 state))
899 (forward-line 1)
900 (setq inner-loop-done t)))
901 (and endpos
902 (while (< next-depth 0)
903 (setq indent-stack (append indent-stack (list nil)))
904 (setq contain-stack (append contain-stack (list nil)))
905 (setq next-depth (1+ next-depth))
906 (setq last-depth (1+ last-depth))
907 (setcar (nthcdr 6 state) (1+ (nth 6 state)))))
908 (setq outer-loop-done (and (not endpos) (<= next-depth 0)))
909 (if outer-loop-done
910 nil
911 ;; If this line had ..))) (((.. in it, pop out of the levels
912 ;; that ended anywhere in this line, even if the final depth
913 ;; doesn't indicate that they ended.
914 (while (> last-depth (nth 6 state))
915 (setq indent-stack (cdr indent-stack)
916 contain-stack (cdr contain-stack)
917 last-depth (1- last-depth)))
918 (if (/= last-depth next-depth)
919 (setq last-sexp nil))
920 ;; Add levels for any parens that were started in this line.
921 (while (< last-depth next-depth)
922 (setq indent-stack (cons nil indent-stack)
923 contain-stack (cons nil contain-stack)
924 last-depth (1+ last-depth)))
925 (if (null (car contain-stack))
926 (setcar contain-stack (or (car (cdr state))
927 (save-excursion (forward-sexp -1)
928 (point)))))
929 (forward-line 1)
930 (skip-chars-forward " \t")
931 (if (eolp)
932 nil
933 (if (and (car indent-stack)
934 (>= (car indent-stack) 0))
935 ;; Line is on an existing nesting level.
936 ;; Lines inside parens are handled specially.
937 (if (/= (char-after (car contain-stack)) ?{)
938 (setq this-indent (car indent-stack))
939 ;; Line is at statement level.
940 ;; Is it a new statement? Is it an else?
941 ;; Find last non-comment character before this line
942 (save-excursion
943 (setq at-else (looking-at "else\\W"))
944 (setq at-brace (= (following-char) ?{))
945 (setq at-while (looking-at "while\\b"))
946 (c-backward-to-noncomment opoint)
947 (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?{)))
948 ;; Preceding line did not end in comma or semi;
949 ;; indent this line c-continued-statement-offset
950 ;; more than previous.
951 (progn
952 (c-backward-to-start-of-continued-exp (car contain-stack))
953 (setq this-indent
954 (+ c-continued-statement-offset (current-column)
955 (if at-brace c-continued-brace-offset 0))))
956 ;; Preceding line ended in comma or semi;
957 ;; use the standard indent for this level.
958 (cond (at-else (progn (c-backward-to-start-of-if opoint)
959 (setq this-indent
960 (current-indentation))))
961 ((and at-while (c-backward-to-start-of-do opoint))
962 (setq this-indent (current-indentation)))
963 (t (setq this-indent (car indent-stack)))))))
964 ;; Just started a new nesting level.
965 ;; Compute the standard indent for this level.
966 (let ((val (calculate-c-indent
967 (if (car indent-stack)
968 (- (car indent-stack))
969 opoint))))
970 (setcar indent-stack
971 (setq this-indent val))))
972 ;; Adjust line indentation according to its contents
973 (if (or (looking-at "case[ \t'/(]\\|default\\>")
974 (and (looking-at "[A-Za-z]")
975 (save-excursion
976 (forward-sexp 1)
977 (looking-at ":"))))
978 (setq this-indent (max 1 (+ this-indent c-label-offset))))
979 (if (= (following-char) ?})
980 (setq this-indent (- this-indent c-indent-level)))
981 (if (= (following-char) ?{)
982 (setq this-indent (+ this-indent c-brace-offset)))
983 ;; Don't leave indentation in empty lines.
984 (if (eolp) (setq this-indent 0))
985 ;; Put chosen indentation into effect.
986 (or (= (current-column) this-indent)
987 (= (following-char) ?\#)
988 (progn
989 (delete-region (point) (progn (beginning-of-line) (point)))
990 (indent-to this-indent)))
991 ;; Indent any comment following the text.
992 (or (looking-at comment-start-skip)
993 (let ((beg (point)))
994 (and (re-search-forward
995 comment-start-skip
996 (save-excursion (end-of-line) (point)) t)
997 ;; Make sure the comment starter we found
998 ;; is not actually in a string or quoted.
999 (let ((new-state
1000 (parse-partial-sexp beg (point)
1001 nil nil state)))
1002 (and (not (nth 3 new-state)) (not (nth 5 new-state))))
1003 (progn (indent-for-comment) (beginning-of-line)))))))))))
1004
1005;; Look at all comment-start strings in the current line after point.
1006;; Return t if one of them starts a real comment.
1007;; This is not used yet, because indent-for-comment
1008;; isn't smart enough to handle the cases this can find.
1009(defun indent-c-find-real-comment ()
1010 (let (win)
1011 (while (and (not win)
1012 (re-search-forward comment-start-skip
1013 (save-excursion (end-of-line) (point))
1014 t))
1015 ;; Make sure the comment start is not quoted.
1016 (let ((state-1
1017 (parse-partial-sexp
1018 (save-excursion (beginning-of-line) (point))
1019 (point) nil nil state)))
1020 (setq win (and (null (nth 3 state-1)) (null (nth 5 state-1))))))
1021 win))
1022
1023;; Indent every line whose first char is between START and END inclusive.
1024(defun c-indent-region (start end)
1025 (save-excursion
1026 (goto-char start)
1027 (let ((endmark (copy-marker end)))
1028 (and (bolp) (not (eolp))
1029 (c-indent-line))
1030 (indent-c-exp endmark)
1031 (set-marker endmark nil))))
1032\f
1832dbd1 1033(defun set-c-style (style &optional global)
a17915dc 1034 "Set C-mode variables to use one of several different indentation styles.
1832dbd1
RS
1035The arguments are a string representing the desired style
1036and a flag which, if non-nil, means to set the style globally.
1037\(Interactively, the flag comes from the prefix argument.)
1038Available styles are GNU, K&R, BSD and Whitesmith.
a17915dc 1039 (interactive (list (completing-read "Use which C indentation style? "
1832dbd1
RS
1040 c-style-alist nil t)
1041 current-prefix-arg))
a17915dc 1042 (let ((vars (cdr (assoc style c-style-alist))))
1832dbd1
RS
1043 (or vars
1044 (error "Invalid C indentation style `%s'" style))
a17915dc 1045 (while vars
1832dbd1
RS
1046 (or global
1047 (make-local-variable (car (car vars))))
a17915dc
ER
1048 (set (car (car vars)) (cdr (car vars)))
1049 (setq vars (cdr vars)))))
1832dbd1
RS
1050\f
1051;;; This page handles insertion and removal of backslashes for C macros.
1052
1053(defvar c-backslash-column 48
1054 "*Minimum column for end-of-line backslashes of macro definitions.")
1055
1056(defun c-backslash-region (from to delete-flag)
1057 "Insert, align, or delete end-of-line backslashes on the lines in the region.
1058With no argument, inserts backslashes and aligns existing backslashes.
1059With an argument, deletes the backslashes.
1060
1061This function does not modify the last line of the region if the region ends
1062right at the start of the following line; it does not modify blank lines
1063at the start of the region. So you can put the region around an entire macro
1064definition and conveniently use this command."
1065 (interactive "r\nP")
1066 (save-excursion
1067 (goto-char from)
1068 (let ((column c-backslash-column)
1069 (endmark (make-marker)))
1070 (move-marker endmark to)
1071 ;; Compute the smallest column number past the ends of all the lines.
1072 (if (not delete-flag)
1073 (while (< (point) to)
1074 (end-of-line)
1075 (if (= (preceding-char) ?\\)
1076 (progn (forward-char -1)
1077 (skip-chars-backward " \t")))
1078 (setq column (max column (1+ (current-column))))
1079 (forward-line 1)))
1080 ;; Adjust upward to a tab column, if that doesn't push past the margin.
1081 (if (> (% column tab-width) 0)
1082 (let ((adjusted (* (/ (+ column tab-width -1) tab-width) tab-width)))
1083 (if (< adjusted (window-width))
1084 (setq column adjusted))))
1085 ;; Don't modify blank lines at start of region.
1086 (goto-char from)
1087 (while (and (< (point) endmark) (eolp))
1088 (forward-line 1))
1089 ;; Add or remove backslashes on all the lines.
1090 (while (and (< (point) endmark)
1091 ;; Don't backslashify the last line
1092 ;; if the region ends right at the start of the next line.
1093 (save-excursion
1094 (forward-line 1)
1095 (< (point) endmark)))
1096 (if (not delete-flag)
1097 (c-append-backslash column)
1098 (c-delete-backslash))
1099 (forward-line 1))
1100 (move-marker endmark nil))))
1101
1102(defun c-append-backslash (column)
1103 (end-of-line)
1104 ;; Note that "\\\\" is needed to get one backslash.
1105 (if (= (preceding-char) ?\\)
1106 (progn (forward-char -1)
1107 (delete-horizontal-space)
1108 (indent-to column))
1109 (indent-to column)
1110 (insert "\\")))
1111
1112(defun c-delete-backslash ()
1113 (end-of-line)
1114 (forward-char -1)
1115 (if (looking-at "\\\\")
1116 (delete-region (1+ (point))
1117 (progn (skip-chars-backward " \t") (point)))))
c0274f38
ER
1118
1119;;; c-mode.el ends here