+ (insert-and-inherit "::"))
+
+\f
+;; Movement (etc.) by defuns.
+(defun c-in-function-trailer-p (&optional lim)
+ ;; Return non-nil if point is between the closing brace and the semicolon of
+ ;; a brace construct which needs a semicolon, e.g. within the "variables"
+ ;; portion of a declaration like "struct foo {...} bar ;".
+ ;;
+ ;; Return the position of the main declaration. Otherwise, return nil.
+ ;; Point is assumed to be at the top level and outside of any macro or
+ ;; literal.
+ ;;
+ ;; If LIM is non-nil, it is the bound on a the backward search for the
+ ;; beginning of the declaration.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (and c-opt-block-decls-with-vars-key
+ (save-excursion
+ (c-syntactic-skip-backward "^;}" lim)
+ (let ((eo-block (point))
+ bod)
+ (and (eq (char-before) ?\})
+ (eq (car (c-beginning-of-decl-1 lim)) 'previous)
+ (setq bod (point))
+ ;; Look for struct or union or ... If we find one, it might
+ ;; be the return type of a function, or the like. Exclude
+ ;; this case.
+ (c-syntactic-re-search-forward
+ (concat "[;=\(\[{]\\|\\("
+ c-opt-block-decls-with-vars-key
+ "\\)")
+ eo-block t t t)
+ (match-beginning 1) ; Is there a "struct" etc., somewhere?
+ (not (eq (char-before) ?_))
+ (c-syntactic-re-search-forward "[;=\(\[{]" eo-block t t t)
+ (eq (char-before) ?\{)
+ bod)))))
+
+(defun c-where-wrt-brace-construct ()
+ ;; Determine where we are with respect to functions (or other brace
+ ;; constructs, included in the term "function" in the rest of this comment).
+ ;; Point is assumed to be outside any macro or literal.
+ ;; This is used by c-\(begining\|end\)-of-defun.
+ ;;
+ ;; Return one of these symbols:
+ ;; at-header : we're at the start of a function's header.
+ ;; in-header : we're inside a function's header, this extending right
+ ;; up to the brace. This bit includes any k&r declarations.
+ ;; in-block : we're inside a function's brace block.
+ ;; in-trailer : we're in the area between the "}" and ";" of something
+ ;; like "struct foo {...} bar, baz;".
+ ;; at-function-end : we're just after the closing brace (or semicolon) that
+ ;; terminates the function.
+ ;; outwith-function: we're not at or in any function. Being inside a
+ ;; non-brace construct also counts as 'outwith-function'.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-excursion
+ (let* (kluge-start
+ decl-result brace-decl-p
+ (start (point))
+ (paren-state (c-parse-state))
+ (least-enclosing (c-least-enclosing-brace paren-state)))
+
+ (cond
+ ((and least-enclosing
+ (eq (char-after least-enclosing) ?\{))
+ 'in-block)
+ ((c-in-function-trailer-p)
+ 'in-trailer)
+ ((and (not least-enclosing)
+ (consp paren-state)
+ (consp (car paren-state))
+ (eq start (cdar paren-state)))
+ 'at-function-end)
+ (t
+ ;; Find the start of the current declaration. NOTE: If we're in the
+ ;; variables after a "struct/eval" type block, we don't get to the
+ ;; real declaration here - we detect and correct for this later.
+
+ ;;If we're in the parameters' parens, move back out of them.
+ (if least-enclosing (goto-char least-enclosing))
+ ;; Kluge so that c-beginning-of-decl-1 won't go back if we're already
+ ;; at a declaration.
+ (if (or (and (eolp) (not (eobp))) ; EOL is matched by "\\s>"
+ (not (looking-at
+"\\([;#]\\|\\'\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s$\\|\\s<\\|\\s>\\|\\s!\\)")))
+ (forward-char))
+ (setq kluge-start (point))
+ (setq decl-result
+ (car (c-beginning-of-decl-1
+ ;; NOTE: If we're in a K&R region, this might be the start
+ ;; of a parameter declaration, not the actual function.
+ (and least-enclosing ; LIMIT for c-b-of-decl-1
+ (c-safe-position least-enclosing paren-state)))))
+
+ ;; Has the declaration we've gone back to got braces?
+ (setq brace-decl-p
+ (save-excursion
+ (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))))))
+
+ (cond
+ ((= (point) kluge-start) ; might be BOB or unbalanced parens.
+ 'outwith-function)
+ ((eq decl-result 'same)
+ (if brace-decl-p
+ (if (eq (point) start)
+ 'at-header
+ 'in-header)
+ 'outwith-function))
+ ((eq decl-result 'previous)
+ (if (and (not brace-decl-p)
+ (c-in-function-trailer-p))
+ 'at-function-end
+ 'outwith-function))
+ (t (error
+ "c-where-wrt-brace-construct: c-beginning-of-decl-1 returned %s"
+ decl-result))))))))
+
+(defun c-backward-to-nth-BOF-{ (n where)
+ ;; Skip to the opening brace of the Nth function before point. If
+ ;; point is inside a function, this counts as the first. Point must be
+ ;; outside any comment/string or macro.
+ ;;
+ ;; N must be strictly positive.
+ ;; WHERE describes the position of point, one of the symbols `at-header',
+ ;; `in-header', `in-block', `in-trailer', `at-function-end',
+ ;; `outwith-function' as returned by c-where-wrt-brace-construct.
+ ;;
+ ;; If we run out of functions, leave point at BOB. Return zero on success,
+ ;; otherwise the number of {s still to go.
+ ;;
+ ;; This function may do hidden buffer changes
+ (cond
+ ;; What we do to go back the first defun depends on where we start.
+ ((bobp))
+ ((eq where 'in-block)
+ (goto-char (c-least-enclosing-brace (c-parse-state)))
+ (setq n (1- n)))
+ ((eq where 'in-header)
+ (c-syntactic-re-search-forward "{")
+ (backward-char)
+ (setq n (1- n)))
+ ((memq where '(at-header outwith-function at-function-end in-trailer))
+ (c-syntactic-skip-backward "^}")
+ (when (eq (char-before) ?\})
+ (backward-sexp)
+ (setq n (1- n))))
+ (t (error "Unknown `where' %s in c-backward-to-nth-EOF-{" where)))
+
+ ;; Each time round the loop, go back to a "{" at the outermost level.
+ (while (and (> n 0) (not (bobp)))
+ (c-parse-state) ; This call speeds up the following one
+ ; by a factor of ~6. Hmmm. 2006/4/5.
+ (c-syntactic-skip-backward "^}")
+ (when (eq (char-before) ?\})
+ (backward-sexp)
+ (setq n (1- n))))
+ n)
+
+(defun c-beginning-of-defun (&optional arg)
+ "Move backward to the beginning of a defun.
+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")
+ (or arg (setq arg 1))
+
+ (c-save-buffer-state
+ (beginning-of-defun-function end-of-defun-function
+ (start (point))
+ where paren-state pos)
+
+ ;; Move back out of any macro/comment/string we happen to be in.
+ (c-beginning-of-macro)
+ (setq pos (c-literal-limits))
+ (if pos (goto-char (car pos)))
+
+ (setq where (c-where-wrt-brace-construct))
+
+ (if (< arg 0)
+ ;; Move forward to the closing brace of a function.
+ (progn
+ (if (memq where '(at-function-end outwith-function))
+ (setq arg (1+ arg)))
+ (if (< arg 0)
+ (setq arg (c-forward-to-nth-EOF-} (- arg) where)))
+ ;; Move forward to the next opening brace....
+ (when (and (= arg 0)
+ (c-syntactic-re-search-forward "{" nil 'eob))
+ (backward-char)
+ ;; ... and backward to the function header.
+ (c-beginning-of-decl-1)
+ t))
+
+ ;; Move backward to the opening brace of a function.
+ (when (and (> arg 0)
+ (eq (setq arg (c-backward-to-nth-BOF-{ arg where)) 0))
+
+ ;; Go backward to this function's header.
+ (c-beginning-of-decl-1)
+
+ (setq pos (point))
+ ;; We're now there, modulo comments and whitespace.
+ ;; 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)))
+
+ (c-keep-region-active)
+ (= arg 0))))
+
+(defun c-forward-to-nth-EOF-} (n where)
+ ;; Skip to the closing brace of the Nth function after point. If
+ ;; point is inside a function, this counts as the first. Point must be
+ ;; outside any comment/string or macro.
+ ;;
+ ;; N must be strictly positive.
+ ;; WHERE describes the position of point, one of the symbols `at-header',
+ ;; `in-header', `in-block', `in-trailer', `at-function-end',
+ ;; `outwith-function' as returned by c-where-wrt-brace-construct.
+ ;;
+ ;; If we run out of functions, leave point at EOB. Return zero on success,
+ ;; otherwise the number of }s still to go.
+ ;;
+ ;; This function may do hidden buffer changes.
+
+ (cond
+ ;; What we do to go forward over the first defun depends on where we
+ ;; start. We go to the closing brace of that defun, even when we go
+ ;; backwards to it (in a "struct foo {...} bar ;").
+ ((eobp))
+ ((eq where 'in-block)
+ (goto-char (c-least-enclosing-brace (c-parse-state)))
+ (forward-sexp)
+ (setq n (1- n)))
+ ((eq where 'in-trailer)
+ (c-syntactic-skip-backward "^}")
+ (setq n (1- n)))
+ ((memq where '(at-function-end outwith-function at-header in-header))
+ (when (c-syntactic-re-search-forward "{" nil 'eob)
+ (backward-char)
+ (forward-sexp)
+ (setq n (1- n))))
+ (t (error "c-forward-to-nth-EOF-}: `where' is %s" where)))
+
+ ;; Each time round the loop, go forward to a "}" at the outermost level.
+ (while (and (> n 0) (not (eobp)))
+ ;(c-parse-state) ; This call speeds up the following one by a factor
+ ; of ~6. Hmmm. 2006/4/5.
+ (when (c-syntactic-re-search-forward "{" nil 'eob)
+ (backward-char)
+ (forward-sexp))
+ (setq n (1- n)))
+ n)
+
+(defun c-end-of-defun (&optional arg)
+ "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")
+ (or arg (setq arg 1))
+
+ (c-save-buffer-state
+ (beginning-of-defun-function end-of-defun-function
+ (start (point))
+ where paren-state pos)
+
+ ;; Move back out of any macro/comment/string we happen to be in.
+ (c-beginning-of-macro)
+ (setq pos (c-literal-limits))
+ (if pos (goto-char (car pos)))
+
+ (setq where (c-where-wrt-brace-construct))
+
+ (if (< arg 0)
+ ;; Move backwards to the } of a function
+ (progn
+ (if (memq where '(at-header outwith-function))
+ (setq arg (1+ arg)))
+ (if (< arg 0)
+ (setq arg (c-backward-to-nth-BOF-{ (- arg) where)))
+ (if (= arg 0)
+ (c-syntactic-skip-backward "^}")))
+
+ ;; Move forward to the } of a function
+ (if (> arg 0)
+ (setq arg (c-forward-to-nth-EOF-} arg where))))
+
+ ;; Do we need to move forward from the brace to the semicolon?
+ (when (eq arg 0)
+ (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc.
+ (c-syntactic-re-search-forward ";"))
+
+ (setq pos (point))
+ ;; We're there now, modulo comments and whitespace.
+ ;; 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))))
+
+ (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.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (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
+;; Movement by statements.
+(defun c-in-comment-line-prefix-p ()
+ ;; Point is within a comment. Is it also within a comment-prefix?
+ ;; Space at BOL which precedes a comment-prefix counts as part of it.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (let ((here (point)))
+ (save-excursion
+ (beginning-of-line)
+ (skip-chars-forward " \t")
+ (and (looking-at c-current-comment-prefix)
+ (/= (match-beginning 0) (match-end 0))
+ (< here (match-end 0))))))
+
+(defun c-narrow-to-comment-innards (range)
+ ;; Narrow to the "inside" of the comment (block) defined by range, as
+ ;; follows:
+ ;;
+ ;; A c-style block comment has its opening "/*" and its closing "*/" (if
+ ;; present) removed. A c++-style line comment retains its opening "//" but
+ ;; has any final NL removed. If POINT is currently outwith these innards,
+ ;; move it to the appropriate boundary.
+ ;;
+ ;; This narrowing simplifies the sentence movement functions, since it
+ ;; eliminates awkward things at the boundaries of the comment (block).
+ ;;
+ ;; This function might do hidden buffer changes.
+ (let* ((lit-type (c-literal-type range))
+ (beg (if (eq lit-type 'c) (+ (car range) 2) (car range)))
+ (end (if (eq lit-type 'c)
+ (if (and (eq (char-before (cdr range)) ?/)
+ (eq (char-before (1- (cdr range))) ?*))
+ (- (cdr range) 2)
+ (point-max))
+ (if (eq (cdr range) (point-max))
+ (point-max)
+ (- (cdr range) 1)))))
+ (if (> (point) end)
+ (goto-char end)) ; This would be done automatically by ...
+ (if (< (point) beg)
+ (goto-char beg)) ; ... narrow-to-region but is not documented.
+ (narrow-to-region beg end)))
+
+(defun c-beginning-of-sentence-in-comment (range)
+ ;; Move backwards to the "beginning of a sentence" within the comment
+ ;; defined by RANGE, a cons of its starting and ending positions. If we
+ ;; find a BOS, return NIL. Otherwise, move point to just before the start
+ ;; of the comment and return T.
+ ;;
+ ;; The BOS is either text which follows a regexp match of sentence-end,
+ ;; or text which is a beginning of "paragraph".
+ ;; Comment-prefixes are treated like WS when calculating BOSes or BOPs.
+ ;;
+ ;; This code was adapted from GNU Emacs's forward-sentence in paragraphs.el.
+ ;; It is not a general function, but is intended only for calling from
+ ;; c-move-over-sentence. Not all preconditions have been explicitly stated.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let ((start-point (point)))
+ (save-restriction
+ (c-narrow-to-comment-innards range) ; This may move point back.
+ (let* ((here (point))
+ last
+ (here-filler ; matches WS and comment-prefices at point.
+ (concat "\\=\\(^[ \t]*\\(" c-current-comment-prefix "\\)"
+ "\\|[ \t\n\r\f]\\)*"))
+ (prefix-at-bol-here ; matches WS and prefix at BOL, just before point
+ (concat "^[ \t]*\\(" c-current-comment-prefix "\\)[ \t\n\r\f]*\\="))
+ ;; First, find the previous paragraph start, if any.
+ (par-beg ; point where non-WS/non-prefix text of paragraph starts.
+ (save-excursion
+ (forward-paragraph -1) ; uses cc-mode values of
+ ; paragraph-\(start\|separate\)
+ (if (> (re-search-forward here-filler nil t) here)
+ (goto-char here))
+ (when (>= (point) here)
+ (forward-paragraph -2)
+ (if (> (re-search-forward here-filler nil t) here)
+ (goto-char here)))
+ (point))))
+
+ ;; Now seek successively earlier sentence ends between PAR-BEG and
+ ;; HERE, until the "start of sentence" following it is earlier than
+ ;; HERE, or we hit PAR-BEG. Beware of comment prefices!
+ (while (and (re-search-backward (c-sentence-end) par-beg 'limit)
+ (setq last (point))
+ (goto-char (match-end 0)) ; tentative beginning of sentence
+ (or (>= (point) here)
+ (and (not (bolp)) ; Found a non-blank comment-prefix?
+ (save-excursion
+ (if (re-search-backward prefix-at-bol-here nil t)
+ (/= (match-beginning 1) (match-end 1)))))
+ (progn ; Skip the crud to find a real b-o-s.
+ (if (c-in-comment-line-prefix-p)
+ (beginning-of-line))
+ (re-search-forward here-filler) ; always succeeds.
+ (>= (point) here))))
+ (goto-char last))
+ (re-search-forward here-filler)))
+
+ (if (< (point) start-point)
+ nil
+ (goto-char (car range))
+ t))))
+
+(defun c-end-of-sentence-in-comment (range)
+ ;; Move forward to the "end of a sentence" within the comment defined by
+ ;; RANGE, a cons of its starting and ending positions (enclosing the opening
+ ;; comment delimiter and the terminating */ or newline). If we find an EOS,
+ ;; return NIL. Otherwise, move point to just after the end of the comment
+ ;; and return T.
+ ;;
+ ;; The EOS is just after the non-WS part of the next match of the regexp
+ ;; sentence-end. Typically, this is just after one of [.!?]. If there is
+ ;; no sentence-end match following point, any WS before the end of the
+ ;; comment will count as EOS, providing we're not already in it.
+ ;;
+ ;; This code was adapted from GNU Emacs's forward-sentence in paragraphs.el.
+ ;; It is not a general function, but is intended only for calling from
+ ;; c-move-over-sentence.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let ((start-point (point))
+ ;; (lit-type (c-literal-type range)) ; Commented out, 2005/11/23, ACM
+ )
+ (save-restriction
+ (c-narrow-to-comment-innards range) ; This might move point forwards.
+ (let* ((here (point))
+ (par-end ; EOL position of last text in current/next paragraph.
+ (save-excursion
+ ;; The cc-mode values of paragraph-\(start\|separate\), set
+ ;; in c-setup-paragraph-variables, are used in the
+ ;; following.
+ (forward-paragraph 1)
+ (if (eq (preceding-char) ?\n) (forward-char -1))
+ (when (<= (point) here) ; can happen, e.g., when HERE is at EOL.
+ (goto-char here)
+ (forward-paragraph 2)
+ (if (eq (preceding-char) ?\n) (forward-char -1)))
+ (point)))
+
+ last
+ (prefix-at-bol-here
+ (concat "^[ \t]*\\(" c-current-comment-prefix "\\)\\=")))
+ ;; Go forward one "comment-prefix which looks like sentence-end"
+ ;; each time round the following:
+ (while (and (re-search-forward (c-sentence-end) par-end 'limit)
+ (progn
+ (setq last (point))
+ (skip-chars-backward " \t\n")
+ (or (and (not (bolp))
+ (re-search-backward prefix-at-bol-here nil t)
+ (/= (match-beginning 1) (match-end 1)))
+ (<= (point) here))))
+ (goto-char last))
+
+ ;; Take special action if we're up against the end of a comment (of
+ ;; either sort): Leave point just after the last non-ws text.
+ (if (eq (point) (point-max))
+ (while (or (/= (skip-chars-backward " \t\n") 0)
+ (and (re-search-backward prefix-at-bol-here nil t)
+ (/= (match-beginning 1) (match-end 1))))))))
+
+ (if (> (point) start-point)
+ nil
+ (goto-char (cdr range))
+ t))))
+
+(defun c-beginning-of-sentence-in-string (range)
+ ;; Move backwards to the "beginning of a sentence" within the string defined
+ ;; by RANGE, a cons of its starting and ending positions (enclosing the
+ ;; string quotes). If we find a BOS, return NIL. Otherwise, move point to
+ ;; just before the start of the string and return T.
+ ;;
+ ;; The BOS is either the text which follows a regexp match of sentence-end
+ ;; or text which is a beginning of "paragraph". For the purposes of
+ ;; determining paragraph boundaries, escaped newlines are treated as
+ ;; ordinary newlines.
+ ;;
+ ;; This code was adapted from GNU Emacs's forward-sentence in paragraphs.el.
+ ;; It is not a general function, but is intended only for calling from
+ ;; c-move-over-sentence.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let* ((here (point)) last
+ (end (1- (cdr range)))
+ (here-filler ; matches WS and escaped newlines at point.
+ "\\=\\([ \t\n\r\f]\\|\\\\[\n\r]\\)*")
+ ;; Enhance paragraph-start and paragraph-separate also to recognise
+ ;; blank lines terminated by escaped EOLs. IT MAY WELL BE that
+ ;; these values should be customizable user options, or something.
+ (paragraph-start c-string-par-start)
+ (paragraph-separate c-string-par-separate)
+
+ (par-beg ; beginning of current (or previous) paragraph.
+ (save-excursion
+ (save-restriction
+ (narrow-to-region (1+ (car range)) end)
+ (forward-paragraph -1) ; uses above values of
+ ; paragraph-\(start\|separate\)
+ (if (> (re-search-forward here-filler nil t) here)
+ (goto-char here))
+ (when (>= (point) here)
+ (forward-paragraph -2)
+ (if (> (re-search-forward here-filler nil t) here)
+ (goto-char here)))
+ (point)))))
+ ;; Now see if we can find a sentence end after PAR-BEG.
+ (while (and (re-search-backward c-sentence-end-with-esc-eol par-beg 'limit)
+ (setq last (point))
+ (goto-char (match-end 0))
+ (or (> (point) end)
+ (progn
+ (re-search-forward
+ here-filler end t) ; always succeeds. Use end rather
+ ; than here, in case point starts
+ ; beyond the closing quote.
+ (>= (point) here))))
+ (goto-char last))
+ (re-search-forward here-filler here t)
+ (if (< (point) here)
+ nil
+ (goto-char (car range))
+ t))))
+
+(defun c-end-of-sentence-in-string (range)
+ ;; Move forward to the "end of a sentence" within the string defined by
+ ;; RANGE, a cons of its starting and ending positions. If we find an EOS,
+ ;; return NIL. Otherwise, move point to just after the end of the string
+ ;; and return T.
+ ;;
+ ;; The EOS is just after the non-WS part of the next match of the regexp
+ ;; sentence-end. Typically, this is just after one of [.!?]. If there is
+ ;; no sentence-end match following point, any WS before the end of the
+ ;; string will count as EOS, providing we're not already in it.
+ ;;
+ ;; This code was adapted from GNU Emacs's forward-sentence in paragraphs.el.
+ ;; It is not a general function, but is intended only for calling from
+ ;; c-move-over-sentence.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let* ((here (point))
+ last
+ ;; Enhance paragraph-start and paragraph-separate to recognise
+ ;; blank lines terminated by escaped EOLs.
+ (paragraph-start c-string-par-start)
+ (paragraph-separate c-string-par-separate)
+
+ (par-end ; EOL position of last text in current/next paragraph.
+ (save-excursion
+ (save-restriction
+ (narrow-to-region (car range) (1- (cdr range)))
+ ;; The above values of paragraph-\(start\|separate\) are used
+ ;; in the following.
+ (forward-paragraph 1)
+ (setq last (point))
+ ;; (re-search-backward filler-here nil t) would find an empty
+ ;; string. Therefore we simulate it by the following:
+ (while (or (/= (skip-chars-backward " \t\n\r\f") 0)
+ (re-search-backward "\\\\\\($\\)\\=" nil t)))
+ (unless (> (point) here)
+ (goto-char last)
+ (forward-paragraph 1)
+ (while (or (/= (skip-chars-backward " \t\n\r\f") 0)
+ (re-search-backward "\\\\\\($\\)\\=" nil t))))
+ (point)))))
+ ;; Try to go forward a sentence.
+ (when (re-search-forward c-sentence-end-with-esc-eol par-end 'limit)
+ (setq last (point))
+ (while (or (/= (skip-chars-backward " \t\n") 0)
+ (re-search-backward "\\\\\\($\\)\\=" nil t))))
+ ;; Did we move a sentence, or did we hit the end of the string?
+ (if (> (point) here)
+ nil
+ (goto-char (cdr range))
+ t))))
+
+(defun c-ascertain-preceding-literal ()
+ ;; Point is not in a literal (i.e. comment or string (include AWK regexp)).
+ ;; If a literal is the next thing (aside from whitespace) to be found before
+ ;; point, return a cons of its start.end positions (enclosing the
+ ;; delimiters). Otherwise return NIL.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-excursion
+ (c-collect-line-comments
+ (let ((here (point))
+ pos)
+ (if (c-backward-single-comment)
+ (cons (point) (progn (c-forward-single-comment) (point)))
+ (save-restriction
+ ;; to prevent `looking-at' seeing a " at point.
+ (narrow-to-region (point-min) here)
+ (when
+ (or
+ ;; An EOL can act as an "open string" terminator in AWK.
+ (looking-at c-ws*-string-limit-regexp)
+ (and (not (bobp))
+ (progn (backward-char)
+ (looking-at c-string-limit-regexp))))
+ (goto-char (match-end 0)) ; just after the string terminator.
+ (setq pos (point))
+ (c-safe (c-backward-sexp 1) ; move back over the string.
+ (cons (point) pos)))))))))
+
+(defun c-ascertain-following-literal ()
+ ;; Point is not in a literal (i.e. comment or string (include AWK regexp)).
+ ;; If a literal is the next thing (aside from whitespace) following point,
+ ;; return a cons of its start.end positions (enclosing the delimiters).
+ ;; Otherwise return NIL.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-excursion
+ (c-collect-line-comments
+ (let (pos)
+ (c-skip-ws-forward)
+ (if (looking-at c-string-limit-regexp) ; string-delimiter.
+ (cons (point) (or (c-safe (progn (c-forward-sexp 1) (point)))
+ (point-max)))
+ (setq pos (point))
+ (if (c-forward-single-comment)
+ (cons pos (point))))))))
+
+(defun c-after-statement-terminator-p () ; Should we pass in LIM here?
+ ;; Does point immediately follow a statement "terminator"? A virtual
+ ;; semicolon is regarded here as such. So is a an opening brace ;-)
+ ;;
+ ;; This function might do hidden buffer changes.
+ (or (save-excursion
+ (backward-char)
+ (and (looking-at "[;{}]")
+ (not (and c-special-brace-lists ; Pike special brace lists.
+ (eq (char-after) ?{)
+ (c-looking-at-special-brace-list)))))
+ (c-at-vsemi-p)
+ ;; The following (for macros) is not strict about exactly where we are
+ ;; wrt white space at the end of the macro. Doesn't seem to matter too
+ ;; much. ACM 2004/3/29.
+ (let (eom)
+ (save-excursion
+ (if (c-beginning-of-macro)
+ (setq eom (progn (c-end-of-macro)
+ (point)))))
+ (when eom
+ (save-excursion
+ (c-forward-comments)
+ (>= (point) eom))))))
+
+(defun c-back-over-illiterals (macro-start)
+ ;; Move backwards over code which isn't a literal (i.e. comment or string),
+ ;; stopping before reaching BOB or a literal or the boundary of a
+ ;; preprocessor statement or the "beginning of a statement". MACRO-START is
+ ;; the position of the '#' beginning the current preprocessor directive, or
+ ;; NIL if we're not in such.
+ ;;
+ ;; Return a cons (A.B), where
+ ;; A is NIL if we moved back to a BOS (and know it), T otherwise (we
+ ;; didn't move, or we hit a literal, or we're not sure about BOS).
+ ;; B is MACRO-BOUNDARY if we are about to cross the boundary out of or
+ ;; into a macro, otherwise LITERAL if we've hit a literal, otherwise NIL
+ ;;
+ ;; The total collection of returned values is as follows:
+ ;; (nil . nil): Found a BOS whilst remaining inside the illiterals.
+ ;; (t . literal): No BOS found: only a comment/string. We _might_ be at
+ ;; a BOS - the caller must check this.
+ ;; (nil . macro-boundary): only happens with non-nil macro-start. We've
+ ;; moved and reached the opening # of the macro.
+ ;; (t . macro-boundary): Every other circumstance in which we're at a
+ ;; macro-boundary. We might be at a BOS.
+ ;;
+ ;; Point is left either at the beginning-of-statement, or at the last non-ws
+ ;; code before encountering the literal/BOB or macro-boundary.
+ ;;
+ ;; Note that this function moves within either preprocessor commands
+ ;; (macros) or normal code, but will not cross a boundary between the two,
+ ;; or between two distinct preprocessor commands.
+ ;;
+ ;; Stop before `{' and after `;', `{', `}' and `};' when not followed by `}'
+ ;; or `)', but on the other side of the syntactic ws. Move by sexps and
+ ;; move into parens. Also stop before `#' when it's at boi on a line.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let ((here (point))
+ last) ; marks the position of non-ws code, what'll be BOS if, say, a
+ ; semicolon precedes it.
+ (catch 'done
+ (while t ;; We go back one "token" each iteration of the loop.
+ (setq last (point))
+ (cond
+ ;; Stop at the token after a comment.
+ ((c-backward-single-comment) ; Also functions as backwards-ws.
+ (goto-char last)
+ (throw 'done '(t . literal)))
+
+ ;; If we've gone back over a LF, we might have moved into or out of
+ ;; a preprocessor line.
+ ((and (save-excursion
+ (beginning-of-line)
+ (re-search-forward "\\(^\\|[^\\]\\)[\n\r]" last t))
+ (if macro-start
+ (< (point) macro-start)
+ (c-beginning-of-macro)))
+ (goto-char last)
+ ;; Return a car of NIL ONLY if we've hit the opening # of a macro.
+ (throw 'done (cons (or (eq (point) here)
+ (not macro-start))
+ 'macro-boundary)))
+
+ ;; Have we found a virtual semicolon? If so, stop, unless the next
+ ;; statement is where we started from.
+ ((and (c-at-vsemi-p)
+ (< last here)
+ (not (memq (char-after last) '(?\) ?})))) ; we've moved back from ) or }
+ (goto-char last)
+ (throw 'done '(nil . nil)))
+
+ ;; Hit the beginning of the buffer/region?
+ ((bobp)
+ (if (/= here last)
+ (goto-char last))
+ (throw 'done '(nil . nil)))
+
+ ;; Move back a character.
+ ((progn (backward-char) nil))
+
+ ;; Stop at "{" (unless it's a PIKE special brace list.)
+ ((eq (char-after) ?\{)
+ (if (and c-special-brace-lists
+ (c-looking-at-special-brace-list))
+ (skip-syntax-backward "w_") ; Speedup only.
+ (if (/= here last)
+ (goto-char last))
+ (throw 'done '(nil . nil))))
+
+ ;; Have we reached the start of a macro? This always counts as
+ ;; BOS. (N.B. I don't think (eq (point) here) can ever be true
+ ;; here. FIXME!!! ACM 2004/3/29)
+ ((and macro-start (eq (point) macro-start))
+ (throw 'done (cons (eq (point) here) 'macro-boundary)))
+
+ ;; Stop at token just after "}" or ";".
+ ((looking-at "[;}]")
+ ;; If we've gone back over ;, {, or }, we're done.
+ (if (or (= here last)
+ (memq (char-after last) '(?\) ?}))) ; we've moved back from ) or }
+ (if (and (eq (char-before) ?}) ; If };, treat them as a unit.
+ (eq (char-after) ?\;))
+ (backward-char))
+ (goto-char last) ; To the statement starting after the ; or }.
+ (throw 'done '(nil . nil))))
+
+ ;; Stop at the token after a string.
+ ((looking-at c-string-limit-regexp) ; Just gone back over a string terminator?
+ (goto-char last)
+ (throw 'done '(t . literal)))
+
+ ;; Nothing special: go back word characters.
+ (t (skip-syntax-backward "w_")) ; Speedup only.
+ ))))))
+
+(defun c-forward-over-illiterals (macro-end allow-early-stop)
+ ;; Move forwards over code, stopping before reaching EOB or a literal
+ ;; (i.e. a comment/string) or the boundary of a preprocessor statement or
+ ;; the "end of a statement". MACRO-END is the position of the EOL/EOB which
+ ;; terminates the current preprocessor directive, or NIL if we're not in
+ ;; such.
+ ;;
+ ;; ALLOW-EARLY-STOP is non-nil if it is permissible to return without moving
+ ;; forward at all, should we encounter a `{'. This is an ugly kludge, but
+ ;; seems unavoidable. Depending on the context this function is called
+ ;; from, we _sometimes_ need to stop there. Currently (2004/4/3),
+ ;; ALLOW-EARLY-STOP is applied only to open braces, not to virtual
+ ;; semicolons, or anything else.
+ ;;
+ ;; Return a cons (A.B), where
+ ;; A is NIL if we moved forward to an EOS, or stay at one (when
+ ;; ALLOW-EARLY-STOP is set), T otherwise (we hit a literal).
+ ;; B is 'MACRO-BOUNDARY if we are about to cross the boundary out of or
+ ;; into a macro, otherwise 'LITERAL if we've hit a literal, otherwise NIL
+ ;;
+ ;; Point is left either after the end-of-statement, or at the last non-ws
+ ;; code before encountering the literal, or the # of the preprocessor
+ ;; statement, or at EOB [or just after last non-WS stuff??].
+ ;;
+ ;; As a clarification of "after the end-of-statement", if a comment or
+ ;; whitespace follows a completed AWK statement, that statement is treated
+ ;; as ending just after the last non-ws character before the comment.
+ ;;
+ ;; Note that this function moves within either preprocessor commands
+ ;; (macros) or normal code, but not both within the same invocation.
+ ;;
+ ;; Stop before `{', `}', and `#' when it's at boi on a line, but on the
+ ;; other side of the syntactic ws, and after `;', `}' and `};'. Only
+ ;; stop before `{' if at top level or inside braces, though. Move by
+ ;; sexps and move into parens. Also stop at eol of lines with `#' at
+ ;; the boi.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (let ((here (point))
+ last)
+ (catch 'done
+ (while t ;; We go one "token" forward each time round this loop.
+ (setq last (point))
+
+ ;; If we've moved forward to a virtual semicolon, we're done.
+ (if (and (> last here) ; Should we check ALLOW-EARLY-STOP, here? 2004/4/3
+ (c-at-vsemi-p))
+ (throw 'done '(nil . nil)))
+
+ (c-skip-ws-forward)
+ (cond
+ ;; Gone past the end of a macro?
+ ((and macro-end (> (point) macro-end))
+ (goto-char last)
+ (throw 'done (cons (eq (point) here) 'macro-boundary)))
+
+ ;; About to hit a comment?
+ ((save-excursion (c-forward-single-comment))
+ (goto-char last)
+ (throw 'done '(t . literal)))
+
+ ;; End of buffer?
+ ((eobp)
+ (if (/= here last)
+ (goto-char last))
+ (throw 'done '(nil . nil)))
+
+ ;; If we encounter a '{', stop just after the previous token.
+ ((and (eq (char-after) ?{)
+ (not (and c-special-brace-lists
+ (c-looking-at-special-brace-list)))
+ (or allow-early-stop (/= here last))
+ (save-excursion ; Is this a check that we're NOT at top level?
+;;;; NO! This seems to check that (i) EITHER we're at the top level; OR (ii) The next enclosing
+;;;; level of bracketing is a '{'. HMM. Doesn't seem to make sense.
+;;;; 2003/8/8 This might have something to do with the GCC extension "Statement Expressions", e.g.
+;;;; while ({stmt1 ; stmt2 ; exp ;}). This form excludes such Statement Expressions.
+ (or (not (c-safe (up-list -1) t))
+ (= (char-after) ?{))))
+ (goto-char last)
+ (throw 'done '(nil . nil)))
+
+ ;; End of a PIKE special brace list? If so, step over it and continue.
+ ((and c-special-brace-lists
+ (eq (char-after) ?})
+ (save-excursion
+ (and (c-safe (up-list -1) t)
+ (c-looking-at-special-brace-list))))
+ (forward-char)
+ (skip-syntax-forward "w_")) ; Speedup only.