Initial Commit
[packages] / xemacs-packages / oo-browser / br-c++-ft.el
1 ;;!emacs
2 ;;
3 ;; FILE:         br-c++-ft.el
4 ;; SUMMARY:      C++ OO-Browser class and member functions.
5 ;; USAGE:        GNU Emacs Lisp Library
6 ;; KEYWORDS:     c, oop, tools
7 ;;
8 ;; AUTHOR:       Bob Weiner
9 ;; ORG:          BeOpen.com
10 ;;
11 ;; ORIG-DATE:    03-Oct-90
12 ;; LAST-MOD:     10-May-01 at 03:02:42 by Bob Weiner
13 ;;
14 ;; Copyright (C) 1990-1999  BeOpen.com
15 ;; See the file BR-COPY for license information.
16 ;;
17 ;; This file is part of the OO-Browser.
18 ;;
19 ;; DESCRIPTION:  
20 ;; DESCRIP-END.
21
22 ;;; ************************************************************************
23 ;;; Other required Elisp libraries
24 ;;; ************************************************************************
25
26 (require 'br-c++)
27
28 ;;; ************************************************************************
29 ;;; Public variables
30 ;;; ************************************************************************
31
32 (defvar c++-cpp-include-dirs '("/usr/include/")
33   "*Ordered list of include directories by default searched by C preprocessor.
34 Each directory must end with a directory separator.  See also
35 `c++-include-dirs'.")
36
37 (defvar c++-include-dirs nil
38   "*Ordered list of directories to search for C++ include files.
39 Each directory must end with a directory separator.  Directories normally
40 searched by the C++ pre-processor should be set instead in
41 `c++-cpp-include-dirs'.")
42
43 ;; Modified on 3/28/95 to handle C++ names with multiple template
44 ;; parameters, e.g. class<T1,T2,T3>.  Unfortunately for our pattern matcher,
45 ;; we also have to allow spaces within the template parameters section.  We
46 ;; consciously do not allow newlines within the parameters section to avoid
47 ;; grabbing too much of the expression that follows.
48 (defconst c++-return-type-identifier
49   (concat "[\[_\<a-zA-Z]"
50           "[\]" c++-template-identifier-chars "]*"
51           "[ \t\n\r]*\\(::[ \t\n\r]*[\]" c++-template-identifier-chars "]+\\)?"
52           "[ \t\n\r]*\<[" c++-return-type-chars " ,]+\>[ \t\n\r]*[*&]*"
53           "\\|[\[_\<a-zA-Z][\]" c++-return-type-chars "]*"
54           "\\([ \t\n\r]*::[ \t\n\r]*[\[\<a-zA-Z][\]" c++-return-type-chars "]+\\)?"
55           "[ \t\n\r]*[*&]*"))
56
57 (defconst c++-type-identifier
58   (concat "\\([ \t\n\r]*::\\|[\[_\<a-zA-Z][\]"
59           c++-template-identifier-chars "]*"
60           "[ \t\n\r]*\<[^\>\;{}]+\>[ \t\n\r]*[*&]*[ \t\n\r]*::"
61           "\\|[\[_\<a-zA-Z][\]" c++-identifier-chars
62           "]*[ \t\n\r]*[*&]*[ \t\n\r]*::\\)"))
63
64 (defconst c++-type-tag-separator "@"
65   "String that separates a tag's type from its normalized definition form.
66 This should be a single character which is unchanged when quoted for use as a
67 literal in a regular expression.")
68
69 (defconst c++-tag-fields-regexp
70   ;; The \\\\? below is necessary because we sometimes use this expression to
71   ;; test against a string that has been regexp-quoted and some of the
72   ;; characters in br-feature-type-regexp will then be preceded by \\.
73   (format "^\\([^%s\n]+\\)%s\\\\?\\(%s \\)\\([^%s\n]+\\)%s"
74           c++-type-tag-separator c++-type-tag-separator br-feature-type-regexp
75           c++-type-tag-separator c++-type-tag-separator)
76  "Regexp matching the fields of a C++ feature tag line.
77 Group 1 is the class of the feature.  Group 2 is the prefix preceding the
78 feature when displayed within a listing buffer.  Group 3 is the feature name.
79 The feature definition signature begins at the end of the regexp match,
80 i.e. (match-end 0), and goes to the end of the string or line.")
81
82 ;;; ************************************************************************
83 ;;; Private variables
84 ;;; ************************************************************************
85
86 (defconst c++-code-file-regexp "\\.\\(cxx\\|[cC][cC]?P?\\)$"
87   "Regular expression matching a unique part of C++ source (non-header) file name and no others.")
88
89 (defconst c++-include-regexp
90   "[ \t/*]*#[ \t]*include[ \t]+\\([\"\<]\\)\\([^\"\>]+\\)[\"\>]"
91   "Regexp to match to C++ include file lines.  File name is grouping 2.  Type
92 of include, user-specified via double quote, or system-related starting with
93 `\<' is given by grouping 1.")
94
95 (defvar   c++-tmp-buffer-name (concat br-buffer-prefix-info "Tmp*")
96   "Name of the buffer for short-term OO-Browser scratch work.")
97
98 (defconst c++-type-def-modifier
99   "\\(auto\\|const\\|inline\\|mutable\\|register\\|static\\|typedef\\|unsigned\\)")
100
101 (defconst c++-type-modifier-keyword
102   (concat "\\(\\(auto\\|const\\|explicit\\|extern[ \t\n\r]+\"[^\"]+\"\\|"
103           "extern\\|friend\\|inline\\|mutable\\|overload\\|"
104           "register\\|static\\|typedef\\|typename\\|unsigned\\|virtual\\)"
105           "[ \t\n\r]+\\)"))
106
107 (defconst c++-routine-modifier-keyword
108   (concat
109    "\\(\\)" ;; placeholder to align with c++-attribute-modifier-keyword
110    "\\(\\([ \t\n\r]+const\\|[ \t\n\r]+mutable\\|[ \t\n\r]+restrict\\)?"
111    "\\([ \t\n\r]*:[^\;\{]+\\|[ \t\n\r]*=[ \t]*0\\)?\\)"))
112
113 (defconst c++-type-identifier-group
114   ;; It is critical that the final part of this expression, [*& \t\n\r]+,
115   ;; stay exactly as it is or certain feature definitions may be missed or
116   ;; segmented improperly.
117   ;; If you remove the `*&', "Int &operator=(int j) {}", will not be found
118   ;; because the & will be missed.  If you change the `+' to a `*', "main()"
119   ;; will show up as "- n" in listing buffers.
120   (concat "\\(\\(" c++-return-type-identifier "\\)[*& \t\n\r]+\\)"))
121
122 ;; Final optional expression is to handle new C++ array operators, e.g.
123 ;;    void operator delete [] (void*);
124 (defconst c++-operator-identifier "operator[ \t\n\r]*[^ \t\n\r\f:\;.,?~{}]+\\([ \t\n\r]*\\[\\]\\)?"
125   "Regular expression matching a C++ or G++ operator name.")
126
127 (defconst c++-feature-decl-or-def
128   (concat c++-template-prefix
129           "\\(\\(" c++-type-modifier-keyword "*\\)"
130           c++-type-identifier-group "\\)?"
131           "\\(" c++-type-identifier "[ \t\n\r]*\\)?"
132           "\\(" c++-operator-identifier "\\|" c++-function-identifier "\\|"
133           "[*&]?" c++-identifier "\\)" "[ \t\n\r]*")
134   "Regexp matching the first part of a C++ method declaration or definition.")
135
136 (defconst c++-attribute-modifier-keyword
137   (concat
138    ;; Allow for array brackets, [...]
139    "\\(\\[[\]\[_:~<>a-zA-Z0-9]*\\][ \t\n\r]*\\)*"
140    "\\(\\([ \t\n\r]+const\\|[ \t\n\r]+mutable\\|[ \t\n\r]+restrict\\)?"
141    "[ \t\n\r]*\\(=[^\;\{]+\\)?\\)"))
142
143 ;; Empty groupings are for group numbering compatibility with
144 ;; `c++-at-feature-regexp'.
145 (defconst c++-attribute-tag-regexp
146   (concat "^[ \t]*" c++-template-prefix
147           "\\(\\(" c++-type-modifier-keyword "*\\)"
148           c++-type-identifier-group "\\)?"
149           "\\(\\)\\(\\)"
150           "\\(\\(\\)[*&]?" c++-identifier "\\)"
151           "[ \t\n\r]*"
152           c++-comment-regexp
153           "\\(" c++-attribute-modifier-keyword "?\\)"
154           "\\(\\)" ;; placeholder to align with `c++-comment-regexp' in
155                    ;; `c++-at-feature-regexp'
156           ))
157
158 (defconst c++-routine-def-terminator-regexp
159   "\\(\{\\)")
160
161 (defconst c++-feature-decl-terminator-regexp
162   "\\(\;\\)")
163
164 (defconst c++-feature-def-terminator-regexp
165   "\\([\{\;]\\)")
166
167 (defconst c++-attribute-decl
168   ;; Must use `c++-feature-def-terminator-regexp' here since need to match to 
169   ;; constructs like: enum ENUM_NAME {} ENUM_VAR;
170   (concat c++-attribute-tag-regexp c++-feature-def-terminator-regexp)
171   "Regexp matching a C++ attribute declaration within a class declaration.
172 Member modifier keywords are grouped expression `c++-feature-mod-grpn'.
173 Member type is grouped expression `c++-feature-type-grpn', unless scoping
174 type name, grouped expression `c++-feature-scope-grpn' is non-nil, in which
175 case, grouping `c++-feature-scope-grpn' is the type plus \"::\". 
176 Member name is group `c++-feature-name-grpn'.  Any text following the
177 attribute name but preceding the terminating semicolon is group
178 `c++-feature-post-args-grpn'.  Optional modifier keyword following the arguments
179 is group `c++-feature-post-modifier-grpn'.  Group `c++-feature-defaults-grpn'
180 optionally matches the default value of the attribute (including the preceding
181 equal sign).")
182
183 (defconst c++-feature-mod-grpn 3)
184 (defconst c++-feature-type-grpn 6)
185 (defconst c++-feature-scope-grpn 11)
186 (defconst c++-feature-name-grpn 12)
187 (defconst c++-feature-parens-grpn 16)
188 (defconst c++-feature-post-args-grpn 17)
189 ;; Optional array square brackets is group 18.
190 (defconst c++-feature-post-modifier-grpn 19)
191 (defconst c++-feature-defaults-grpn 20)
192 ;;
193 ;; Match the attribute value including the leading =.
194 (defconst c++-attribute-value-grpn 21) 
195 ;; Match the `c++-routine-in-class' or
196 ;; `c++-routine-def-in-class' terminating semicolon, opening brace or
197 ;; = 0 for pure virtual functions.
198 (defconst c++-feature-terminator-grpn 21)
199
200 (defconst c++-at-feature-regexp
201   (concat c++-feature-decl-or-def
202           ;; This old version of the next line matched to things such as:
203           ;;   enum name {};.  Since such matches improperly end up in the
204           ;;   [function] default class, we only accept matches with () in
205           ;;   them.
206           ;;   "[ \t\n\r]*\\(\\[[^\{\;]+\\|([^:\{\;]*)"
207           "\\(\\(([^-+!:{}\;]*)\\|([^-+!(){}\;]*)\\)"
208           c++-routine-modifier-keyword "?\\)"
209           c++-comment-regexp)
210   "Regexp matching a C++ method declaration or definition.
211 Member modifier keywords are grouped expression `c++-feature-mod-grpn'.
212 Member type is grouped expression `c++-feature-type-grpn', unless scoping
213 type name, grouped expression `c++-feature-scope-grpn' is non-nil, in which
214 case, grouping `c++-feature-scope-grpn' is the type plus \"::\". 
215 Member name is group `c++-feature-name-grpn'.  Function argument parentheses,
216 if any, are group `c++-feature-parens-grpn'.  All text following the argument
217 parentheses but preceding the opening brace is group
218 `c++-feature-post-args-grpn'.  Optional modifier keyword following the arguments
219 is group `c++-feature-post-modifier-grpn'.  Group
220 `c++-feature-defaults-grpn' optionally matches one of the three following
221 constructs: 
222   1. base class constructor defaults (including the preceding colon);
223   2. tail part of a pure virtual function (abstract method) declaration (= 0);
224   3. the default value of an attribute (including the preceding equal sign).")
225
226 (defconst c++-feature-decl
227   (concat c++-at-feature-regexp c++-feature-decl-terminator-regexp)
228   "See documentation of `c++-at-feature-regexp' for grouping expressions.")
229
230 (defconst c++-friend-in-class
231   (concat "^[ \t]*friend[ \t\n\r]+" c++-at-feature-regexp c++-feature-def-terminator-regexp)
232   "See documentation of `c++-at-feature-regexp' for grouping expressions.
233 See `c++-friend-regexp' for that.")
234
235 (defconst c++-friend-class-regexp "^[ \t]*friend[ \t\n\r]+class[ \t\n\r]"
236   "Regexp matching a C++ friend class declaration at the start of a line or the start of a string.")
237
238 (defconst c++-friend-regexp "^[ \t]*friend[ \t\n\r]"
239   "Regexp matching a C++ friend declaration at the start of a line or the start of a string.")
240
241 (defconst c++-routine-def
242   (concat "^" c++-at-feature-regexp c++-routine-def-terminator-regexp)
243   "See documentation of `c++-at-feature-regexp' for grouping expressions.")
244
245 (defconst c++-routine-prefix-in-class
246   (concat "^[ \t]*" c++-feature-decl-or-def
247           "\\(\\(([^:{}\;]*\\|([^(){}\;]*))\\)"
248           "\\([ \t\n\r]+const\\|[ \t\n\r]+mutable\\|[ \t\n\r]+restrict\\)?"
249           "[ \t\n\r]*"
250           "\\(\\(:[^\;\{]+\\)?" c++-comment-regexp))
251
252 (defconst c++-routine-in-class
253   (concat c++-routine-prefix-in-class
254           "\\([\{\;]\\|=[ \t]*0[ \t]*\;\\)\\)\\)")
255   "See documentation of `c++-at-feature-regexp' for grouping expressions.")
256
257 (defconst c++-routine-def-in-class
258   (concat c++-routine-prefix-in-class
259           "\\(\{\\|=[ \t]*0[ \t]*\;\\)\\)\\)")
260   "See documentation of `c++-at-feature-regexp' for grouping expressions.")
261
262 (defconst c++-feature-def
263   (concat "^" c++-at-feature-regexp c++-feature-def-terminator-regexp)
264   "See documentation of `c++-at-feature-regexp' for grouping expressions.")
265
266 (defconst c++-class-modifier-keyword
267   "\\(\\(friend\\|public\\|protected\\)[ \t\n\r]+\\)")
268
269 (defconst c++-class-decl
270   (concat c++-class-modifier-keyword "?"
271           c++-template-prefix
272           c++-class-keyword c++-identifier "[ \t]*[\;,]")
273   "Regexp matching a C++ class declaration.
274 Template match, if any, is grouping `c++-decl-template-grpn'.
275 Class name is grouping `c++-class-name-grpn'.")
276
277 (defconst c++-decl-template-grpn 3)
278 (defconst c++-class-name-grpn 5)
279
280 (defconst c++-arg-identifier
281   (concat "[_a-zA-Z][" c++-identifier-chars "]*")
282   "Regular expression matching a C++ or G++ function argument identifier.")
283
284 (defconst c++-pure-virtual-function-regexp "\)[^=]*=[ \t]*0[ \t]*\;\\'"
285   "Regexp matching the trailing part of a C++ pure virtual function signature.")
286
287 (defconst c++-c-type-htable
288   (hash-make '(("enum"    . "[enumeration]")
289                ("struct"  . "[structure]")
290                ("typedef" . "[type]")
291                ("union"   . "[union]"))
292              t)
293   "Hash table of complex C type keywords and associated default class names.")
294
295 (defconst c-identifier-chars "_a-zA-Z0-9"
296   "String of chars and char ranges that may be used within a standard C++ template identifier.
297 This excludes the template arguments.")
298
299 (defconst c-identifier
300   (concat "[\[_a-zA-Z]" "[\]" c-identifier-chars "]*"))
301
302 (defconst c-type-identifier
303   (concat "[\[_a-zA-Z]" "[\]" c-identifier-chars "]*[ \t\n\r]*[*&]*"))
304
305 (defconst c-type-identifier-group
306   ;; It is critical that the final part of this expression, [*& \t\n\r]+,
307   ;; stay exactly as it is or certain feature definitions may be missed or
308   ;; segmented improperly.
309   ;; If you remove the `*&', "Int &operator=(int j) {}", will not be found
310   ;; because the & will be missed.  If you change the `+' to a `*', "main()"
311   ;; will show up as "- n" in listing buffers.
312   (concat "\\(\\(" c-type-identifier "\\)[*& \t\n\r]+\\)"))
313
314 (defconst c-feature-decl-or-def
315   (concat "\\(\\(" c++-type-modifier-keyword "*\\)"
316           c-type-identifier-group "\\)?"
317           "\\(" c-type-identifier "[ \t\n\r]*\\)?"
318           "[*&]?" c-identifier "[ \t\n\r]*")
319   "Regexp matching the first part of a C feature declaration or definition.")
320
321 (defconst c-at-function-regexp
322   (concat c-feature-decl-or-def
323           "\\(\\(([^-+!:{}\;]*)\\|([^-+!(){}\;]*)\\)"
324           c++-routine-modifier-keyword "?\\)"
325           c++-comment-regexp)
326   "Regexp matching a C function declaration or definition.")
327
328 (defconst c-function-def-terminator-regexp
329   "\\(\{\\)")
330
331 (defconst c-function-def
332   (concat "^" c-at-function-regexp c-function-def-terminator-regexp))
333
334 ;;; ************************************************************************
335 ;;; Public functions
336 ;;; ************************************************************************
337
338 (defun c++-add-default-classes ()
339   (if br-c-tags-flag (c-add-default-classes)))
340
341 (defun c++-member-p ()
342   "Prints whether entity at point is a C++ member definition or declaration."
343   (interactive)
344   (let ((name))
345     (save-excursion
346       (message
347        (concat
348         "Is " (if (c++-feature-def-p)
349                   (progn (setq name
350                                (br-buffer-substring (match-beginning
351                                                      c++-feature-name-grpn)
352                                                     (match-end
353                                                      c++-feature-name-grpn)))
354                          "")
355                 "not ")
356         "a def.  "
357         "Is " (if (and (c++-skip-to-statement) (c++-feature-decl))
358                   (progn (setq name
359                                (br-buffer-substring (match-beginning
360                                                      c++-feature-name-grpn)
361                                                     (match-end
362                                                      c++-feature-name-grpn)))
363                          "")
364                 "not ")
365         "a member decl.  "
366         (if name (concat "  Name = " name)))))))
367
368 (defun c++-feature-class-name ()
369   "Return the class name for the function defined at point or nil if none.
370 If point is not within the brace delimited body of the function or class
371 declaration of a member function, then nil is returned."
372   (let* ((opoint (point)))
373     (save-excursion
374       (if (or
375            ;;
376            ;; Case 1: Within a method whose definition includes its class name
377            ;;         which is also not within a class declaration.
378            ;;
379            (re-search-backward c++-routine-def nil t)
380            ;;
381            ;; Case 2: Within a method whose definition does include a class
382            ;;         name and which also is defined within a class declaration.
383            ;; Case 3: Within a function whose definition does not include a class
384            ;;         name and which is also not within a class declaration.
385            ;; Case 4: Within a method whose definition does not include a class
386            ;;         name but which is defined within a class declaration.
387            ;;
388            (re-search-backward c++-routine-def-in-class nil t))
389           (let ((class (if (match-beginning c++-feature-scope-grpn)
390                            (buffer-substring
391                             (match-beginning c++-feature-scope-grpn)
392                             (- (match-end c++-feature-scope-grpn) 2)))))
393             (if class
394                 ;; Case 2
395                 (progn (goto-char (1- (match-end 0)))
396                        (if (eq (following-char) ?\{)
397                            (condition-case ()
398                                (progn (forward-list)
399                                       (if (> (point) opoint)
400                                           (c++-normalize-template-arguments
401                                            (br-delete-space class))))
402                              (error nil))))
403               ;; Case 3 or 4
404               (c++-normalize-template-arguments
405                (c++-get-class-name-from-source))))))))
406
407 (defun c++-feature-implementors (name)
408   "Return unsorted list of C++ feature tags which implement feature NAME.
409 This includes classes which define the interface for NAME as a pure virtual
410 function."
411   (c++-feature-matches (concat "^" (regexp-quote name) "$")))
412
413 (defun c++-feature-edit-declaration (class-and-feature)
414   "Edit in the other window (or the OO-Browser viewer window) the declaration source for CLASS-AND-FEATURE or for the listing entry at point.
415
416 If point is within the signature of a feature definition within a source code
417 buffer and a nil value for CLASS-AND-FEATURE is given, the feature's
418 declaration is displayed for editing.
419
420 With a prefix argument or outside of an OO-Browser listing buffer, prompt
421 with completion for CLASS-AND-FEATURE.  Point is left in the viewer window.
422 Signal an error if the declaration is not found."
423   (interactive (list (if (or current-prefix-arg (not (br-browser-buffer-p)))
424                          (let ((default (br-feature-default))
425                                (class-and-feature
426                                 (br-feature-complete 'must-match
427                                                      "Edit feature declaration:")))
428                            (if (and (equal default class-and-feature)
429                                     (save-excursion (c++-feature-def-p)))
430                                ;; feature definitions are handled specially
431                                nil
432                              class-and-feature)))))
433   (c++-feature-view-declaration class-and-feature t))
434
435 (defun c++-feature-view-declaration (&optional class-and-feature edit-flag)
436   "View in the other window (or OO-Browser viewer window) the declaration source for optional CLASS-AND-FEATURE or for the listing entry at point.
437
438 If point is within the signature of a feature definition within a source code
439 buffer and a nil value for CLASS-AND-FEATURE is given, the feature's
440 declaration is displayed for viewing..
441
442 With a prefix argument or outside of an OO-Browser listing buffer, prompt
443 with completion for CLASS-AND-FEATURE.
444
445 Point is left in the original window unless the optional second argument
446 EDIT-FLAG is non-nil.  Signal an error if the declaration is not found."
447   (interactive (list (if (or current-prefix-arg (not (br-browser-buffer-p)))
448                          (let ((default (br-feature-default))
449                                (class-and-feature
450                                 (br-feature-complete 'must-match
451                                                      "View feature declaration:")))
452                            (if (and (equal default class-and-feature)
453                                     (save-excursion (c++-feature-def-p)))
454                                ;; feature definitions are handled specially
455                                nil
456                              class-and-feature)))
457                      nil))
458   ;;
459   ;; Pseudo-code (may be out dated):
460   ;;   Move to class def of given feature or feature at point.
461   ;;   Use the sig associated with feature listing to compute
462   ;;     a regexp that matches to its declaration or definition
463   ;;     within the class.
464   ;;   Search forward for a match.
465   ;;   If no match, then go to the first entry with the same name
466   ;;     as feature.
467   ;;
468   (let ((oo-browser-listing (and (br-browser-buffer-p) (br-listing-window-p)))
469         ftr-class)
470
471     (cond (class-and-feature)
472           ;; If on an OO-Browser feature listing entry or within C++ source
473           ;; code on a feature definition signature, then leave
474           ;; class-and-feature as nil for now.
475           ((or (and oo-browser-listing (br-at-feature-p))
476                (save-excursion (c++-feature-def-p))))
477           ;; Otherwise, look for a default value around point.
478           (t (setq class-and-feature (br-feature-default))))
479
480     (setq ftr-class (and (stringp class-and-feature)
481                          (not (string-match "::" class-and-feature))
482                          class-and-feature))
483     (cond
484
485      ((or ftr-class
486           (and (not class-and-feature)
487                oo-browser-listing
488                (not (br-at-feature-p))))
489       ;; Assume is a class entry to display.
490       (or (br-view nil edit-flag ftr-class)
491           (error "(OO-Browser):  `%s' declaration not found"
492                  ftr-class)))
493
494      ;; Show definitions of [default class] features rather than giving an
495      ;; error since a user may invoke this command on them thinking he can
496      ;; jump to them.
497      ((and oo-browser-listing
498            (stringp class-and-feature) (eq (aref class-and-feature 0) ?\[))
499       (if (if edit-flag
500               (br-edit-entry)
501             (br-view-entry))
502           ;; Above calls will either signal an error or return t or nil
503           ;; depending on whether the entry definition was found.
504           (message "(OO-Browser):  found definition of `%s'"
505                    class-and-feature)))
506
507      (t (let ((owind (selected-window))
508               (oframe (selected-frame))
509               (wconfig (current-window-configuration))
510               (err)
511               (ftr-tag)
512               (ftr-name)
513               (viewer-obuf)
514               (case-fold-search) ;; case-sensitive matching
515               class-end match ftr-sig)
516
517           (if (and (null class-and-feature)
518                    (cond
519                     (oo-browser-listing
520                      (setq ftr-tag (br-feature-get-tag)
521                            ftr-sig (and ftr-tag (br-feature-tag-signature ftr-tag)))
522                      t)
523                     ((save-excursion (c++-feature-def-p))
524                      ;; Within a feature definition signature
525                      (setq ftr-sig (buffer-substring
526                                     (match-beginning 0) (match-end 0)))
527                      t)))
528               (setq class-and-feature (br-feature-signature-to-name ftr-sig t)
529                     match (string-match "::" class-and-feature)
530                     ftr-class (if match (substring
531                                          class-and-feature 0 match))
532                     ftr-name (if match (substring class-and-feature (match-end 0))
533                                class-and-feature))
534             ;; else
535             (if (stringp class-and-feature)
536                 (setq match (string-match "::" class-and-feature)
537                       ftr-class (if match (substring class-and-feature 0 match)
538                                   "[function]")
539                       ftr-name (if match (substring class-and-feature (match-end 0))
540                                  class-and-feature)
541                       ftr-tag (car (br-feature-tag-and-file class-and-feature))))
542             (setq ftr-tag (or ftr-tag (br-feature-get-tag))
543                   ftr-class (or ftr-class (and ftr-tag
544                                                (br-feature-tag-class ftr-tag)))
545                   ftr-name (or ftr-name (and ftr-tag
546                                              (br-feature-tag-name ftr-tag)))
547                   ftr-sig (and ftr-tag (br-feature-tag-signature ftr-tag))
548                   class-and-feature (or class-and-feature
549                                         (and ftr-class ftr-name
550                                              (concat ftr-class "::" ftr-name)))))
551
552           (unwind-protect
553               (cond ((and (not ftr-sig) ftr-class ftr-name)
554                      (cond ((not (br-class-defined-p ftr-class))
555                             (setq err
556                                   (format "(OO-Browser):  %s's class `%s' not defined within the Environment"
557                                           ftr-name ftr-class)))
558                            ;; Try as a method and then as an attribute since
559                            ;; it is not in the tags table.
560                            ((or (c++-feature-method-display ftr-class ftr-name
561                                                             ftr-name nil)
562                                 (c++-feature-attribute-display ftr-class ftr-name
563                                                                ftr-name nil))
564                             (message
565                              "(OO-Browser):  found declaration of `%s'"
566                              class-and-feature))
567                            (t (setq err (format
568                                          "(OO-Browser):  `%s' declaration not found"
569                                          class-and-feature)))))
570
571                     ((not (and ftr-sig ftr-class ftr-name))
572                      (setq err (format
573                                 "(OO-Browser):  `%s' not declared within the Environment"
574                                 class-and-feature)))
575
576                     (t (if (br-in-browser) (br-to-view-window))
577                        (setq viewer-obuf (current-buffer))
578                        (if (and (br-find-class ftr-class nil)
579                                 (search-forward "\{" nil t)
580                                 (save-excursion
581                                   (backward-char)
582                                   ;; Move to class close brace but ignore
583                                   ;; any error if braces are unbalanced.
584                                   ;; Let the compiler tell the user about
585                                   ;; this.
586                                   (condition-case ()
587                                       (progn (forward-sexp)
588                                              (setq class-end (point)))
589                                     (error nil))))
590                            (let ((case-fold-search)) ;; case-sensitive matching
591                              (br-major-mode)
592                              (let ((ftr-regexp
593                                     ;; Include args.
594                                     (c++-feature-declaration-regexp
595                                      ftr-sig t)))
596                                (if (re-search-forward ftr-regexp class-end t)
597                                    (progn (br-display-code
598                                            (match-beginning 0))
599                                           (message
600                                            "(OO-Browser):  found declaration of `%s'"
601                                            class-and-feature))
602                                  ;; Try a simpler match without args
603                                  ;; as a fall back.
604                                  (setq ftr-regexp
605                                        (c++-feature-declaration-regexp
606                                         ftr-sig nil))
607                                  (if (re-search-forward ftr-regexp class-end t)
608                                      (progn (br-display-code
609                                              (match-beginning 0))
610                                             (message "(OO-Browser):  Matched declaration by name only; failed to match arguments"))
611                                    (setq err
612                                          (format "(OO-Browser):  `%s' declaration not found"
613                                                  class-and-feature)))))
614                              (if err
615                                  nil
616                                (setq buffer-read-only
617                                      (not (and edit-flag
618                                                (file-writable-p
619                                                 buffer-file-name))))))
620                          (setq err (format
621                                     "(OO-Browser):  %s's class `%s' not defined within the Environment"
622                                     ftr-name ftr-class)))))
623             ;; unwindforms
624             (if err
625                 (progn
626                   (if (not edit-flag) (select-window owind))
627                   (if (eq (selected-frame) oframe)
628                       (set-window-configuration wconfig))
629                   (error err))
630               ;;
631               ;; Kill previous viewer buffer if unmodified and
632               ;; `br-keep-viewed-classes' is nil.
633               (if (and (buffer-live-p viewer-obuf)
634                        (not (eq (current-buffer) viewer-obuf)))
635                   (save-excursion
636                     (set-buffer viewer-obuf)
637                     (if (and (not br-keep-viewed-classes) buffer-read-only
638                              (null (buffer-modified-p)))
639                         (kill-buffer viewer-obuf))))
640               (if (not edit-flag) (select-window owind)))))))))
641
642 (defun c++-feature-locate-p (feature-tag &optional regexp-flag)
643   "Leave point at the start of FEATURE-TAG's definition in the current buffer.
644 Assume caller has moved point to the beginning of the buffer or to the point
645 of desired search start.
646 Optional REGEXP-FLAG means FEATURE-TAG is a regular expression."
647   ;; Match to function definitions, not declarations, except for pure virtual
648   ;; functions and friends which are declared, not defined, and so end with a
649   ;; `;'.
650   (let ((found t) (start) (case-fold-search)
651         feature-sig feature-regexp class)
652     (if (br-feature-tag-p feature-tag)
653         (setq feature-sig (br-feature-tag-signature feature-tag)
654               class (br-feature-tag-class feature-tag))
655       (setq feature-sig feature-tag
656             class nil))
657     (if regexp-flag
658         (if (stringp feature-tag)
659             (setq feature-regexp feature-tag)
660           (error "(c++-feature-locate-p): Not a regexp, %s" feature-tag)))
661     ;;
662     ;; First move to the proper class implementation if feature-sig does not
663     ;; include a <class>:: part and this is not a [default-class], so that if
664     ;; two classes in the same file have the same feature signature, we still
665     ;; end up at the right one.
666     (cond (class
667            (if (or (string-match "\\`\\[" class)
668                    (and feature-sig (string-match "::" feature-sig)))
669                nil
670              (setq found (re-search-forward
671                           (c++-class-definition-regexp class nil) nil t))))
672           ((string-match c++-tag-fields-regexp feature-sig)
673            (setq class (substring feature-sig
674                                   (match-beginning 1) (match-end 1))
675                  feature-sig (substring feature-sig (match-end 0)))
676            (if (or (and regexp-flag
677                         (not (string-match "\\`\\\\\\[\\|::" feature-regexp)))
678                    (not (or regexp-flag
679                             (string-match "\\`\\[\\|::" feature-tag))))
680                (setq found
681                      (re-search-forward
682                       (c++-class-definition-regexp class regexp-flag)
683                       nil t)))))
684     ;;
685     ;; If class was searched for and not found, return nil.
686     (if (not found)
687         nil
688       ;; Otherwise, look for feature expression.
689       (setq found nil)
690       (or regexp-flag (setq feature-regexp
691                             (c++-feature-signature-to-regexp feature-sig nil)))
692       (while (and (or (re-search-forward feature-regexp nil t)
693                       (and (not regexp-flag)
694                            ;; Allow for comments between parameters.
695                            (re-search-forward
696                             (c++-feature-signature-to-regexp feature-sig t)
697                             nil t)))
698                   (setq start (match-beginning 0))
699                   (not (setq found (not 
700                                     (if (c-within-comment-p)
701                                         (progn (search-forward "*/" nil t)
702                                                t)))))))
703       (if found
704           (progn
705             (message "(OO-Browser):  found definition of `%s'"
706                      (c++-feature-signature-to-name feature-sig t nil))
707             (br-display-code start))))))
708
709 (defun c++-feature-name-to-regexp (name)
710   "Converts feature NAME into a regular expression matching the feature's name tag."
711   (concat "\\<" (c++-feature-signature-to-regexp name) "\\>"))
712
713 (defun c++-feature-args-regexp (func-args)
714   (let* ((space "%%%")
715          (comment "!!!")
716          (obuf (current-buffer))
717          (tmp-buf (get-buffer-create c++-tmp-buffer-name)))
718     (or tmp-buf (error "(OO-Browser):  (c++-feature-args-regexp) - Can't create tmp-buf"))
719     (set-buffer tmp-buf)
720     (setq buffer-read-only nil)
721     (erase-buffer)
722     ;; Fill tmp-buffer with all func-args, including parens.
723     (insert (br-regexp-quote func-args))
724
725     (goto-char (point-min))
726     (if (looking-at "(\\s-*)")
727         (replace-match "(\\s-*)" t t)
728
729       ;; Replace all "\( +" with "\(" temporarily
730       (br-buffer-replace "\\(^\\|[^\\]\\)\([ \t\n\r]+" "\\1\(")
731     
732       ;; Replace all "+ \)" with "\)" temporarily
733       (br-buffer-replace "[ \t\n\r]+\)" "\)")
734     
735       ;; Replace all "...\)" with "@@@" temporarily
736       (br-buffer-replace "\\\\\\.\\\\\\.\\\\\\.\)" "@@@")
737
738       ;; If an arg consists of 2 or more words and does not end with [*&>],
739       ;; replace the last word with <identifier>.
740       ;; Do this in two steps to avoid paren conflict with future replaces.
741       (br-buffer-replace
742        "\\([\(,][^=,\)]*[^ \t\n\r=,\)]+[ \t\n\r\\*&]+\\)[^ \t\n\r*&<>=,\)]+\\([ \t\n\r]*[,=\)]\\)"
743        "\\1###\\2")
744
745       ;; If an arg consists of only 1 word and does not end with [*&>], add an
746       ;; <identifier> following it.
747       ;; Do this in two steps to avoid paren conflict with future replaces.
748       (br-buffer-replace
749        "\\([\(,][ \t\n\r]*\\)\\([^ \t\n\r*&<>=,\)]+\\)\\([ \t\n\r]*[,=\)]\\)"
750        "\\1\\2 ###\\3")
751
752       ;; If an arg ends with [*&>], add an <identifier> following it.
753       ;; Do this in two steps to avoid paren conflict with future replaces.
754       (br-buffer-replace
755        "\\([\(,][ \t\n\r]*\\)\\([^=,\)]+\\([\\]*[*&>]+\\)+\\)\\([ \t\n\r]*[,=\)]\\)"
756        "\\1\\2 ###\\4")
757
758       ;; Optionalize right hand side of argument defaults.
759       ;; Do this after literal variable names have been changed to regexps or
760       ;; variable names preceding the parentheses that this inserts will not
761       ;; be changed to regexps.
762       (br-buffer-replace "\\([^=,\( \t\n\r]+\\)\\([ \t\n\r]*=[^,\)]+\\)"
763                          "\\1\\\\(\\2\\\\)?")
764
765       ;; Replace all  " *, *" with "<comment>,<comment>"
766       (br-buffer-replace "[ \t\n\r]*,[ \t\n\r]*" (concat comment "," comment))
767     
768       ;; Replace all " +" with "<spc>"
769       (br-buffer-replace "[ \t\n\r]+" space)
770
771       ;; Replace all "\(" with "\(<comment>"
772       (br-buffer-replace "\\(^\\|[^\\]\\)\(" (concat "\\1\(" comment))
773     
774       ;; Replace all "\)" with "<comment>\)"
775       (br-buffer-replace "\\([^\\]\\)\)" (concat "\\1" comment "\)"))
776
777       ;; Replace all & and quoted \\* with "<spc>[*&]+<spc>"
778       (br-buffer-replace "\\(\\(&\\|\\\\\\*\\)+\\)" (concat space "\\1" space))
779
780       ;; Replace all "<spc>" with "[ \t\n\r]*"
781       (br-buffer-replace space "[ \t\n\r]*" t)
782
783       ;; Replace all "<comment>" with a comment regexp
784       (br-buffer-replace comment c++-comment-regexp t)
785
786       ;; Replace all "@@@" with any # of args
787       (br-buffer-replace "@@@" "[^\)]*\)" t)
788
789       (br-buffer-replace "###" (concat "\\\\(" c++-arg-identifier
790                                        "\\\\)?\\\\([ \t\n\r]*=[^,\)]+\\\\)?"))
791       )
792
793     ;; Return final buffer as a string.
794     (prog1 (buffer-substring (point-min) (point-max))
795       (set-buffer-modified-p nil)
796       (set-buffer obuf))))
797
798 (defun c++-feature-signature-to-name (feature-sig-or-tag &optional with-class for-display)
799   "Extracts the feature name from FEATURE-SIG-OR-TAG.
800 The feature's class name is dropped from FEATURE-SIG-OR-TAG unless optional
801 WITH-CLASS is non-nil.  If optional FOR-DISPLAY is non-nil, a feature type
802 character is prepended to the name for display in a browser listing."
803   (if (br-feature-tag-p feature-sig-or-tag)
804       (br-feature-tag-name feature-sig-or-tag with-class for-display)
805     (let ((name))
806       (cond
807        ;; member
808        ((string-match c++-tag-fields-regexp feature-sig-or-tag)
809         (setq name (substring feature-sig-or-tag
810                               (match-beginning (if for-display 2 3))
811                               (match-end 3)))
812         (if with-class
813             (setq name (concat
814                         (substring feature-sig-or-tag
815                                    (match-beginning 1) (match-end 1))
816                         "::" name)))
817         ;; Remove any trailing whitespace.
818         (br-delete-space name))
819
820        ((or (string-match c++-at-feature-regexp feature-sig-or-tag)
821             (string-match c++-attribute-tag-regexp feature-sig-or-tag))
822         (setq name (substring feature-sig-or-tag
823                               (match-beginning c++-feature-name-grpn)
824                               (match-end c++-feature-name-grpn)))
825         (if with-class
826             (if (match-beginning c++-feature-scope-grpn)
827                 (setq name (concat
828                             (substring feature-sig-or-tag
829                                        (match-beginning c++-feature-scope-grpn)
830                                        (match-end c++-feature-scope-grpn))
831                             name))
832               (if (br-class-in-table-p name)
833                   ;; Constructor
834                   (setq name (concat name "::" name)))))
835         (if for-display (c++-feature-add-prefix
836                          name "" feature-sig-or-tag) name))
837        ;;
838        ;; unknown
839        (t;; Remove any trailing whitespace and add display prefix.
840         (setq name (br-delete-space feature-sig-or-tag))
841         (if (and with-class (br-class-in-table-p name))
842             ;; Constructor
843             (setq name (concat name "::" name)))
844         (if for-display (c++-feature-add-prefix
845                          name "" feature-sig-or-tag) name))))))
846
847 (defun c++-feature-signature-to-regexp (signature &optional comments-flag)
848   "Given a C++ SIGNATURE, return regexp used to match to its definition."
849   (setq signature (br-regexp-quote signature))
850   (let ((prefix-info) (class))
851     (if (string-match c++-tag-fields-regexp signature)
852         (setq prefix-info (substring signature (match-beginning 0) (match-end 0))
853               class (substring signature (match-beginning 1) (match-end 1))
854               signature (substring signature (match-end 0))))
855     ;; Add () to [function] tags whose signatures need them.
856     (if (and (equal class "[function]")
857              (not (string-match "\(" signature)))
858         (setq signature (concat signature " ( )")))
859     (if (string-match "[^<>*&  \t]+\\(\<[^\>]+\>\\)[ \t\n\r]*::" signature)
860         ;; Method from a template class.  Match to a method with the same
861         ;; number of template parameters, regardless of parameter names.
862         (let ((pre (substring signature 0 (match-beginning 1)))
863               (mid (substring signature (match-beginning 1) (match-end 1)))
864               (post (substring signature (match-end 1))))
865           (setq signature (concat pre (c++-template-args-regexp mid) post))))
866     (if comments-flag
867         (concat prefix-info
868                 (c++-feature-signature-commented-regexp signature))
869       (concat prefix-info (c++-feature-signature-whitespace-regexp
870                            signature)))))
871
872 (defun c++-feature-signature-commented-regexp (signature-regexp)
873   (let* ((space "%%%")
874          (comment "!!!")
875          (obuf (current-buffer))
876          (tmp-buf (get-buffer-create c++-tmp-buffer-name)))
877     (or tmp-buf (error "(OO-Browser):  (c++-feature-args-regexp) - Can't create tmp-buf"))
878     (set-buffer tmp-buf)
879     (setq buffer-read-only nil)
880     (erase-buffer)
881     ;; Fill tmp-buffer with all of signature-regexp.
882     (insert signature-regexp)
883
884     (goto-char (point-min))
885
886     ;; Replace all  " *, *" with "<comment>,<comment>"
887     ;; Avoid commas separating template parameters which have already
888     ;; been substituted for with "[^,<>]+".
889     (br-buffer-replace "\\([^^,]\\)[ \t\n\r]*,[ \t\n\r]*"
890                        (concat "\\1" comment "," comment))
891     
892     ;; Replace all "\(" with "<comment>\(<comment>"
893     (br-buffer-replace "\\(^\\|[^\\]\\)\(" (concat "\\1" comment "\(" comment))
894     
895     ;; Replace all "\)" with "<comment>\)<comment>"
896     (br-buffer-replace "\\([^\\]\\)\)" (concat "\\1" comment "\)" comment))
897
898     ;; Replace all " +" with "<spc>"
899     (br-buffer-replace "[ \t\n\r]+" space)
900
901     ;; Replace any "<comment><comment>" with one "<comment>"
902     (br-buffer-replace (concat comment comment) comment t)
903
904     ;; Replace all "<comment>" with a comment regexp
905     (br-buffer-replace (concat "\\(" space "\\)?" comment
906                                "\\(" space "\\)?")
907                        c++-comment-regexp t)
908
909     ;; Replace all "<spc>" with "[ \t\n\r]*"
910     (br-buffer-replace space "[ \t\n\r]*" t)
911
912     ;; Return final buffer as a string.
913     (prog1 (buffer-substring (point-min) (point-max))
914       (set-buffer-modified-p nil)
915       (set-buffer obuf))))
916
917 (defun c++-feature-signature-whitespace-regexp (signature-regexp)
918   (let* ((obuf (current-buffer))
919          (tmp-buf (get-buffer-create c++-tmp-buffer-name)))
920     (or tmp-buf (error "(OO-Browser):  (c++-feature-args-regexp) - Can't create tmp-buf"))
921     (set-buffer tmp-buf)
922     (setq buffer-read-only nil)
923     (erase-buffer)
924     ;; Fill tmp-buffer with all of signature-regexp.
925     (insert signature-regexp)
926     (goto-char (point-min))
927     (br-buffer-replace "[ \t\n\r]+" "[ \t\n\r]*" t)
928     ;; Return final buffer as a string.
929     (prog1 (buffer-substring (point-min) (point-max))
930       (set-buffer-modified-p nil)
931       (set-buffer obuf))))
932
933 (defun c++-feature-to-end ()
934   ;; Move point to precede feature opening brace or declaration semicolon.
935   (backward-char) 
936   (if (eq (following-char) ?\{)
937       (condition-case ()
938           ;; Move to end of feature but ignore any error if braces are
939           ;; unbalanced.  Let the compiler tell the user about this.
940           (forward-sexp)
941         (error nil))))
942
943 (defun c++-scan-features ()
944   "Return reverse ordered list of C++ routine definitions in current buffer.
945 Assume point is at the beginning of widened buffer and that all comments have
946 been removed by the caller.
947 This processes only those routines defined outside of the declaration of a
948 class; see `c++-scan-features-in-class' for the code that processes routines
949 and attributes defined within class declarations. It doesn't process global
950 variables since those are handled by separate code that deals with C constructs."
951   (save-excursion
952     (c-remove-functions) ;; Prevent any mis-scans within C function bodies.
953     (let ((routines) class type name rout)
954       (while (re-search-forward c++-routine-def nil t)
955         (setq class ""
956               name (br-buffer-substring
957                     (match-beginning c++-feature-name-grpn)
958                     (match-end c++-feature-name-grpn))
959               type (if (match-beginning c++-feature-type-grpn)
960                        (br-buffer-substring
961                         (match-beginning c++-feature-type-grpn)
962                         (match-end c++-feature-type-grpn))
963                      ""))
964         ;;
965         ;; This code is very subtle but it does the right thing so don't
966         ;; change it unless you know exactly what you are doing.
967         (if (not (match-beginning c++-feature-scope-grpn))
968             ;; This is a non-class function since we did not find a ::
969             ;; scoping operator.
970             ;; (setq class "[function]")
971             ;; Ignore global functions since these are found by a call to the
972             ;; `ootags' program.
973             (c++-feature-to-end)
974           (setq rout (br-buffer-substring (match-beginning 0) (match-end 0)))
975           ;;
976           ;; Is a member function, but this may set class = "" since prior
977           ;; regexp grouping may have grabbed the type.  Be careful to
978           ;; handle this.
979           (setq class (br-delete-space
980                        (br-buffer-substring
981                         (match-beginning c++-feature-scope-grpn)
982                         (- (match-end c++-feature-scope-grpn) 2))))
983           (if (string-equal class "")
984               (setq class type))
985
986           (c++-feature-to-end)
987           ;; Ignore matches to class constructs and ::function references.
988           (if (or (string-equal class "")
989                   (string-match c++-class-name-before rout))
990               nil
991             (setq rout (c++-feature-normalize rout class name)
992                   routines (cons rout routines)))))
993       routines)))
994
995 (defun c++-to-definition (&optional other-win)
996   "Jumps to the definition of a selected C++ construct.
997 With OTHER-WIN non-nil, show it in another window.
998
999 It assumes that its caller has already checked that the key was pressed in an
1000 appropriate buffer and has moved the cursor to the selected buffer.
1001
1002 If key is pressed:
1003  (1) on a `#include' statement, the include file is displayed;
1004      Look for include file in directory lists `smart-c-cpp-include-dirs'
1005      and `smart-c-include-dirs'.
1006  (2) within a method definition before the opening brace, its declaration is
1007      displayed; 
1008  (3) within a method declaration, its definition is displayed;
1009  (4) on a class name, the class definition is shown;
1010  (5) on a member reference (past any :: scoping operator), the member
1011      definition or a listing of possible definitions or a matching
1012      declaration (if no definitions exist within the Environment) is shown;
1013  (6) on a global variable or function identifier, its definition is shown.
1014
1015  (2-5) require that an OO-Browser Environment has been loaded with
1016        the {M-x br-env-load RET} command."
1017   (interactive)
1018   (let ((obuf (current-buffer))
1019         (opoint (point)))
1020     (cond
1021      ((c++-include-file other-win))
1022      ((c++-feature other-win))
1023      ((and (goto-char opoint)
1024            ;; If point is after a :: scoping operator or in front of a method
1025            ;; call opening paren, then don't treat it as a class or search
1026            ;; backward for the class name preceding ::.
1027            (save-excursion
1028              (skip-chars-forward "^\(\):\;,.?{}")
1029              (not (looking-at "\(")))
1030            (br-check-for-class (c++-find-class-name) other-win)))
1031      ((br-check-for-class (save-excursion (c++-class-decl-p)) other-win))
1032      ;; Look it up as a member reference.
1033      ((and (goto-char opoint) (c++-feature-reference-definition)))
1034      ;; Look it up as a regular tag to find global variable and function definitions.
1035      ((progn
1036         (set-buffer obuf)
1037         (goto-char opoint)
1038         (smart-c++-tag))))))
1039
1040 ;;; ************************************************************************
1041 ;;; Private functions
1042 ;;; ************************************************************************
1043
1044 (defun c++-class-decl-p ()
1045   "Return nil unless point is within a class declaration, referenced by another
1046 class.  Commented declarations also return nil.  When value is non-nil, it is
1047 the class name from the declaration.  Leave point at start of statement for
1048 visual clarity."
1049   (c++-skip-to-statement)
1050   (save-excursion
1051     (let ((class))
1052       (and (looking-at c++-class-decl)
1053            (setq class (buffer-substring
1054                         (match-beginning c++-class-name-grpn)
1055                         (match-end c++-class-name-grpn)))
1056            (if (match-beginning c++-decl-template-grpn)
1057                (setq class
1058                      (c++-get-class-name
1059                       class (buffer-substring
1060                              (match-beginning c++-decl-template-grpn)
1061                              (match-end c++-decl-template-grpn))
1062                       t))
1063              t)
1064            (not (c-within-comment-p))
1065            (progn (beginning-of-line)
1066                   (not (looking-at "[ \t]*//")))
1067            class))))
1068
1069 (defun c++-feature (&optional other-win)
1070   "Move point to the definition/declaration of a method given by the declaration/definition at point.
1071 This will immediately return nil if point is not within the signature, prior
1072 to any arguments and any brace-delimited body."
1073   (interactive)
1074   (let ((feature-def) (ftr) (class) (ftr-pat)
1075         (opoint (point)))
1076     (c++-skip-to-statement)
1077     (if (and (= (point) (save-excursion (back-to-indentation) (point)))
1078              (not (c-within-comment-p))
1079              (save-excursion (beginning-of-line)
1080                              (not (looking-at "[ \t]*//")))
1081              (not (looking-at c++-class-decl))
1082              (looking-at (concat c++-at-feature-regexp "[\{\;,]")))
1083         (cond ((c++-feature-def-p)
1084                ;; Within a feature definition
1085                (if (c++-get-class-name-from-source)
1086                    ;; Definition is within a class, so it serves as its own
1087                    ;; declaration.
1088                    (progn
1089                      (message "(OO-Browser):  Method declaration/definition is one and the same.")
1090                      (recenter 0)
1091                      t)
1092                  (progn (c++-feature-edit-declaration nil)
1093                         t)))
1094               ((c++-view-friend other-win t))
1095               ;; Now look for feature definition in code (non-header) files.
1096               ((progn (setq feature-def (c++-feature-def-pat)
1097                             ftr (car (cdr (cdr feature-def)))
1098                             class (car (cdr feature-def))
1099                             ftr-pat (car feature-def))
1100                       (c++-locate-feature ftr class ftr-pat other-win)))
1101               ((progn (goto-char opoint)
1102                       ;; Only match to declarations if within a class
1103                       ;; declaration.  Otherwise, unqualified method calls will
1104                       ;; improperly match as declarations, assuming non-ANSI C
1105                       ;; code may be used, e.g. method ();. 
1106                       (if (c++-get-class-name-from-source)
1107                           (save-excursion
1108                             (and (c++-skip-to-statement)
1109                                  (c++-feature-decl)))))
1110                (beep)
1111                (message "(OO-Browser):  `%s' feature definition not found" ftr)
1112                t))
1113       (goto-char opoint)
1114       nil)))
1115
1116 (defun c++-feature-add-prefix (feature-name class signature &optional friend-flag)
1117   "Add a browser listing display prefix to FEATURE-NAME from CLASS based on feature's SIGNATURE."
1118   (concat (cond
1119            ;; friend declaration
1120            (friend-flag "% ")
1121            ;; pure virtual function (abstract method)
1122            ((string-match c++-pure-virtual-function-regexp signature)
1123             "> ")
1124            ;; attribute
1125            ((or (memq (aref signature (1- (length signature))) '(?\; ?=))
1126                 (and (not (string-match "\(" signature))
1127                      ;; Don't match to complex C types like enumerations.
1128                      (not (br-default-class-p class))))
1129             (if (string-match "\\<static\\>" signature)
1130                 "& " ;; attribute shared by all instances
1131               ;; regular attribute
1132               "= "))
1133            ;; constructor or destructor
1134            ((or (eq ?~ (aref feature-name 0))
1135                 (equal feature-name (c++-class-non-template-name class))
1136                 (br-member feature-name
1137                            '("operator new" "operator delete")))
1138             "+ ")
1139            ;;
1140            ;; Type declaration: enum, struct, union or typedef
1141            ((and (string-match "\\`\\(struct\\|enum\\|union\\|typedef\\) " signature)
1142                  (not (string-match "\(" signature)))
1143             "= ")
1144            ;;
1145            ;; Don't use the next clause since method declarations may contain
1146            ;; a `static' when the definition does not and method declarations
1147            ;; are ignored.
1148            ;; ((string-match "\\<static\\>" signature) "1 ")
1149            ;;
1150            ;; methods
1151            (t "- "))
1152           feature-name))
1153
1154 (defun c++-feature-at-reference-p ()
1155   "Return C++ member reference name that point is within, else nil.
1156 The return value is a list of:
1157 \(variable member-reference-prefix class-name scoping-operator member-name method-flag)
1158 where member-reference-prefix if non-nil is either \".\" or \"->\",
1159 scoping-operator if non-nil is \"::\" and class-name may also be nil.
1160 Method-flag is non-nil if this is a method reference."
1161   (let* ((identifier-chars "_:~<>a-zA-Z0-9")
1162          (member-ref-regexp
1163           (concat "\\(\\([_a-zA-Z][" identifier-chars "]*\\)"
1164                   ;; Allow for array references
1165                   "\\(\\s-*\\[[\]\[" identifier-chars "]*\\]\\)?\\)?"
1166                   ;; Match to . or -> and after
1167                   "\\(\\(\\(\\.\\|->\\)[_~:\<a-zA-Z][" identifier-chars "]*\\)?"
1168                   "\\([ \t]*\\([^\]\) \t:\;.,?~{}]\\)[^\[\( \t:\;.,~^!|?{}]?[=*]?\\)?\\)"))
1169          variable op-identifier identifier class-name method-flag)
1170     (save-excursion
1171       (skip-chars-backward identifier-chars)
1172       (skip-chars-backward "-.>")
1173       ;; Move back over any array [] indexes
1174       (while (not (zerop (skip-chars-backward "\]")))
1175         (skip-chars-backward identifier-chars)
1176         (skip-chars-backward " \["))
1177       ;; Skip back over variable name itself
1178       (skip-chars-backward identifier-chars)
1179       (if (looking-at member-ref-regexp)
1180           ;; Don't flash button here since it was already flashed before
1181           ;; this was called.
1182           (progn (setq variable
1183                        (if (match-beginning 2)
1184                            (buffer-substring (match-beginning 2) (match-end 2)))
1185                        op-identifier
1186                        (buffer-substring (match-beginning 4) (match-end 4))
1187                        identifier (if (match-beginning 5)
1188                                       (buffer-substring
1189                                        (match-beginning 5) (match-end 5)))
1190                        method-flag (if (match-beginning 8)
1191                                        (equal "\(" (buffer-substring
1192                                                     (match-beginning 8)
1193                                                     (match-end 8)))))
1194                  (if (and variable (not identifier))
1195                      ;; e.g. unqualified_method();
1196                      (setq identifier variable
1197                            variable nil))
1198                  ;; Have to allow for identifiers such as, `operator () (int, int)'
1199                  ;; yet not include the opening parenthesis in `min ()'.
1200                  (if (string-match "\\<operator\\>" op-identifier)
1201                      (setq identifier op-identifier))
1202                  (if (and identifier
1203                           (string-match
1204                            "\\`\\(\\.\\|->\\)?\\([_<>a-zA-Z0-9]+[ \t\n\r]*::\\|[ \t\n\r]*::\\)?\\(.+\\)\\'"
1205                            identifier))
1206                      (list
1207                       ;; name of variable to which reference refers,
1208                       ;; this is nil if a more complicated expression is the
1209                       ;; reference anchor
1210                       variable
1211                       ;; . or -> variable-based reference
1212                       (if (match-beginning 1)
1213                           (substring identifier (match-beginning 1) (match-end 1)))
1214                       ;; class name
1215                       (or (and (match-beginning 2)
1216                                (> (length (setq class-name
1217                                                 (substring identifier
1218                                                            (match-beginning 2)
1219                                                            (- (match-end 2) 2))))
1220                                   0)
1221                                (save-match-data
1222                                  (c++-normalize-template-arguments class-name)))
1223                           (and variable
1224                                (save-match-data (c++-feature-variable-class
1225                                                  variable))))
1226                       ;; scoping operator, ::
1227                       (if (match-beginning 2) "::")
1228                       ;; member name
1229                       (if (match-beginning 3)
1230                           (substring identifier (match-beginning 3) (match-end 3)))
1231                       ;; t if this is a method and not an attribute reference
1232                       method-flag)))))))
1233
1234 (defun c++-feature-attribute-display (class-name member-name reference-name message-flag)
1235   "Display CLASS-NAME's MEMBER-NAME attribute derived from REFERENCE-NAME.
1236 MESSAGE-FLAG non-nil means display messages explaining whether the attribute was
1237 found or not.  Return t if found and nil otherwise."
1238   (if (br-edit nil class-name)
1239       (let ((case-fold-search)) ;; case-sensitive matching
1240         (message "")
1241         (if (save-excursion (c++-feature-to-variable-declaration member-name))
1242             (progn (br-display-code (match-beginning 5))
1243                    (if message-flag
1244                        (message
1245                         "(OO-Browser):  `%s' declaration found within class `%s'"
1246                         member-name class-name))
1247                    t)
1248           (if message-flag
1249               (progn (message "(OO-Browser):  `%s' not declared within class `%s'"
1250                               member-name class-name)
1251                      (beep)))
1252           nil))
1253     (if message-flag
1254         (progn (message
1255                 "(OO-Browser):  %s's class `%s' not defined within the Environment"
1256                 reference-name member-name class-name)
1257                (beep)))
1258     nil))
1259
1260 (defun c++-feature-decl ()
1261   (and (not (looking-at
1262              "\\(if\\|else if\\|else\\|for\\|while\\|switch\\)\\s-*\("))
1263        (not (looking-at c++-class-decl))
1264        (looking-at c++-feature-decl)))
1265
1266 (defun c++-feature-declaration-regexp (def-sig &optional args-flag)
1267   "Return a regular expression that matches to the declaration of DEF-SIG.
1268 If DEF-SIG is not a valid C++ declaration or definition, return nil.
1269 Optional ARGS-FLAG non-nil means include argument matches in the regexp to
1270 handle overloading."
1271   (and (not (string-match "\\<\\(if\\|else if\\|else\\|for\\|while\\|switch\\)\\s-*\("
1272                           def-sig))
1273        (string-match c++-at-feature-regexp def-sig)
1274        ;; Don't regexp-quote member-name yet.
1275        (let* ((member-name (substring def-sig
1276                                       ;; Work around regexp bug that can drop
1277                                       ;; leading [*&] char when there is no
1278                                       ;; class:: preceding member-name.
1279                                       (if (and (match-end c++-feature-type-grpn)
1280                                                (= (match-end c++-feature-type-grpn)
1281                                                   (1- (match-beginning
1282                                                        c++-feature-name-grpn))))
1283                                           (match-end c++-feature-type-grpn)
1284                                         (match-beginning c++-feature-name-grpn))
1285                                       (match-end c++-feature-name-grpn)))
1286               (member-modifiers (if (match-end c++-feature-mod-grpn)
1287                                     (regexp-quote
1288                                      (substring
1289                                       def-sig
1290                                       (match-beginning c++-feature-mod-grpn)
1291                                       (match-end c++-feature-mod-grpn)))))
1292               ;; Don't regexp-quote member-type yet.
1293               (member-type (and (match-end c++-feature-type-grpn)
1294                                 ;; member-type must be followed by whitespace
1295                                 ;; or end with a [*&] character or we don't
1296                                 ;; use it
1297                                 (memq (aref def-sig
1298                                             (1- (match-end
1299                                                  c++-feature-type-grpn)))
1300                                       '(?\  ?\n ?\t ?\r ?* ?&))
1301                                 ;; Handle possible regexp bugs
1302                                 (not (equal
1303                                       (match-beginning c++-feature-type-grpn)
1304                                       (match-beginning c++-feature-name-grpn)))
1305                                 (substring
1306                                  def-sig
1307                                  (match-beginning c++-feature-type-grpn)
1308                                  (match-end c++-feature-type-grpn))))
1309               (func-args (if (and args-flag (match-end c++-feature-parens-grpn))
1310                              (br-feature-delete-c-comments
1311                               (substring
1312                                def-sig
1313                                (match-beginning c++-feature-parens-grpn)
1314                                (match-end c++-feature-parens-grpn)))))
1315               (friend)
1316               )
1317          ;; Eliminate any leading or trailing whitespace in some matches.
1318          (and member-type (string-match "[ \t\n\r]+\\'" member-type)
1319               (setq member-type (substring member-type 0
1320                                            (match-beginning 0))))
1321          (and member-name (string-match "\\`[ \t\n\r]+" member-name)
1322               (setq member-name (substring member-name (match-end 0))))
1323
1324          ;; Move any [*&] preceding member-name to member-type.
1325          (if (string-match "\\`[*&]+" member-name)
1326              (setq member-type (concat member-type
1327                                        (substring member-name 0
1328                                                   (match-end 0)))
1329                    member-name (substring member-name (match-end 0))))
1330
1331          (setq member-type (br-regexp-quote member-type))
1332
1333          ;; Allow for different whitespace between declaration and definition
1334          ;; when * or & is part of name and/or type, e.g. "char* id" and "char
1335          ;; *id".
1336          (if (and (stringp member-type)
1337                   (string-match "[\\*&]+\\'" member-type))
1338              (setq member-type
1339                    (concat (substring member-type 0 (match-beginning 0))
1340                            "[ \t\n\r]*" (substring member-type
1341                                                    (match-beginning 0)))))
1342          ;; Allow for trailing whitespace.
1343          (and (stringp member-type)
1344               (not (string-equal member-type ""))
1345               (setq member-type (concat member-type "[ \t\n\r]*")))
1346
1347          (concat
1348           "^[ \t]*"
1349           c++-template-prefix
1350           "\\(\\(auto\\|inline\\|overload\\|static\\|virtual\\)[ \t\n\r]+\\)?"
1351           (if member-modifiers
1352               (let ((def-mods "") (mod))
1353                 (while (string-match "\\([a-z]+\\)[ \t\n\r]+"
1354                                      member-modifiers)
1355                   (setq mod (substring member-modifiers
1356                                        (match-beginning 1)
1357                                        (match-end 1))
1358                         member-modifiers (substring member-modifiers
1359                                                     (match-end 0)))
1360                   (if (not friend)
1361                       (setq friend (string-equal mod "friend")))
1362                   (if (equal (string-match
1363                               c++-type-def-modifier mod) 0)
1364                       (setq def-mods (concat def-mods "\\(" mod
1365                                              "[ \t\n\r]+\\)?"))))
1366                 def-mods))
1367           (if (and member-type (equal (string-match "virtual" member-type) 0))
1368               nil member-type)
1369           (br-regexp-quote member-name)
1370           "[ \t\n\r]*"
1371           (if func-args (c++-feature-args-regexp func-args))))))
1372
1373 (defun c++-feature-def-p ()
1374   "Return nil unless point is within the first line of the signature of a member definition or pure virtual function.
1375 The definition must be the first thing on the line and must not be commented
1376 and point must be prior to any arguments or nil is returned.  Leaves point at
1377 the start of the definition for visual clarity if t is returned."
1378   (let ((opoint (point)))
1379     (c++-skip-to-statement)
1380     (if (and (= (point) (save-excursion (back-to-indentation) (point)))
1381              (not (c-within-comment-p))
1382              (save-excursion (beginning-of-line)
1383                              (not (looking-at "[ \t]*//")))
1384              (not (looking-at c++-class-decl))
1385              (not (looking-at
1386                    "\\(if\\|else if\\|else\\|for\\|while\\|switch\\)\\s-*\("))
1387              (looking-at (concat c++-at-feature-regexp "[\{\;,]"))
1388              (let ((end-punct))
1389                (or (eq ?\{ (setq end-punct (char-after (1- (match-end 0)))))
1390                    ;; If ends with a `[;,]' then must not have func parens
1391                    ;; nor simply be a scoped name in order to be a def.
1392                    ;; If it begins with `virtual', ends with "= 0" and has
1393                    ;; parens, then is a deferred virtual function declaration.
1394                    (if (match-end c++-feature-parens-grpn)
1395                        (save-restriction
1396                          (narrow-to-region (match-beginning 0) (match-end 0))
1397                          (if (looking-at
1398                               "\\s *\\<virtual\\>[^\;{}]+=[ \t]*0[ \t]*[,\;]")
1399                              (progn (message "(OO-Browser):  Pure virtual function, definition deferred to descendants")
1400                                     t)))
1401                      (or (null (match-end c++-feature-scope-grpn))
1402                          (not (equal (concat
1403                                       (buffer-substring
1404                                        (match-beginning c++-feature-scope-grpn)
1405                                        (match-end c++-feature-name-grpn))
1406                                       (char-to-string end-punct))
1407                                      (buffer-substring (match-beginning 0)
1408                                                        (match-end 0)))))))))
1409         t
1410       (goto-char opoint)
1411       nil)))
1412
1413 (defun c++-feature-def-pat ()
1414   "Return (list <feature-def-pat> <feature-class> <feature-name>) associated with declaration at point.
1415 A call of: (funcall <feature-def-pat> <feature-class>) will generate a regexp 
1416 which will match to the signature component of the feature's OO-Browser tag entry."
1417   (and (c++-skip-to-statement)
1418        (c++-feature-decl)
1419        ;; Don't regexp-quote member-name yet.
1420        (let* ((member-name (buffer-substring
1421                             ;; Work around regexp bug that can drop
1422                             ;; leading [*&] char when there is no class::
1423                             ;; preceding member-name.
1424                             (if (and (match-end c++-feature-type-grpn)
1425                                      (= (match-end c++-feature-type-grpn)
1426                                         (1- (match-beginning
1427                                              c++-feature-name-grpn))))
1428                                 (match-end c++-feature-type-grpn)
1429                               (match-beginning c++-feature-name-grpn))
1430                             (match-end c++-feature-name-grpn)))
1431               (member-modifiers (if (match-end c++-feature-mod-grpn)
1432                                     (br-quote-match c++-feature-mod-grpn)))
1433               (class (if (match-end c++-feature-scope-grpn)
1434                          (buffer-substring
1435                           (match-beginning c++-feature-scope-grpn)
1436                           (- (match-end c++-feature-scope-grpn) 2))))
1437               (scoped-name (match-end c++-feature-scope-grpn))
1438               ;; Don't regexp-quote member-type yet.
1439               (member-type (and (match-end c++-feature-type-grpn)
1440                                 ;; Handle possible regexp bug
1441                                 (not
1442                                  (equal 
1443                                   (match-beginning c++-feature-type-grpn)
1444                                   (match-beginning c++-feature-name-grpn)))
1445                                 (buffer-substring
1446                                  (match-beginning c++-feature-type-grpn)
1447                                  (match-end c++-feature-type-grpn))))
1448               (func-args (if (match-end c++-feature-parens-grpn)
1449                              (br-feature-delete-c-comments
1450                               (buffer-substring
1451                                (match-beginning c++-feature-parens-grpn)
1452                                (match-end c++-feature-parens-grpn)))))
1453               (friend)
1454               )
1455
1456          (if (equal class "") (setq class nil))
1457
1458          ;; Eliminate any leading or trailing whitespace in some matches.
1459          (and member-type (string-match "[ \t]+$" member-type)
1460               (setq member-type (substring member-type 0
1461                                            (match-beginning 0))))
1462          (and member-name (string-match "^[ \t]+" member-name)
1463               (setq member-name (substring member-name (match-end 0))))
1464
1465          ;; Set class if need be.
1466          (cond (scoped-name)
1467                (friend
1468                 (if member-type
1469                     (progn
1470                       (setq class 
1471                             (string-match c++-identifier member-type))
1472                       (if class (setq class (substring
1473                                              member-type class
1474                                              (match-end 0)))))))
1475                ;; Class name is not part of declaration
1476                ;; nor a `friend' declaration, so look
1477                ;; for declaration within a class
1478                ;; definition and locate the class name.
1479                ;; If not within a class, assume
1480                ;; declaration is global.
1481                (t (setq class (c++-get-class-name-from-source))))
1482
1483          ;; Move any [*&] preceding member-name to member-type.
1484          (if (string-match "^[*&]+" member-name)
1485              (setq member-type (concat member-type
1486                                        (substring member-name 0
1487                                                   (match-end 0)))
1488                    member-name (substring member-name (match-end 0))))
1489
1490          (setq member-type (br-regexp-quote member-type))
1491
1492          ;; Allow for different whitespace between declaration and definition
1493          ;; when * or & is part of name and/or type, e.g. "char* id" and "char
1494          ;; *id".
1495          (if (and (stringp member-type)
1496                   (string-match "[ \t\n\r]*\\([\\*&]+\\)\\'" member-type))
1497              (setq member-type
1498                    (concat (substring member-type 0 (match-beginning 0))
1499                            "[ \t\n\r]*" (substring member-type
1500                                                    (match-beginning 1)))))
1501          ;; Allow for trailing whitespace.
1502          (and (stringp member-type)
1503               (not (string-equal member-type ""))
1504               (setq member-type (concat member-type "[ \t\n\r]*")))
1505
1506          (let ((pre-member-regexp
1507                 (concat
1508                  c++-template-prefix
1509                  "\\(\\(auto\\|inline\\|overload\\|static\\|virtual\\)[ \t\n\r]+\\)?"
1510                  (if member-modifiers
1511                      (let ((def-mods "") (mod))
1512                        (while (string-match "\\([a-z]+\\)[ \t\n\r]+"
1513                                             member-modifiers)
1514                          (setq mod (substring member-modifiers
1515                                               (match-beginning 1)
1516                                               (match-end 1))
1517                                member-modifiers (substring member-modifiers
1518                                                            (match-end 0)))
1519                          (if (not friend)
1520                              (setq friend (string-equal mod "friend")))
1521                          (if (equal (string-match
1522                                      c++-type-def-modifier mod) 0)
1523                              (setq def-mods (concat def-mods "\\(" mod
1524                                                     "[ \t\n\r]+\\)?"))))
1525                        def-mods))
1526                  (if (and (stringp member-type)
1527                           (equal (string-match "virtual" member-type) 0))
1528                      nil member-type)))
1529                (post-member-regexp
1530                 (concat
1531                  ;; Point at beginning of line may imply a non-member func.
1532                  (if (or scoped-name (not (bolp))) "[ \t\n\r]*::[ \t\n\r]*")
1533                  (br-regexp-quote member-name)
1534                  "[ \t\n\r]*"
1535                  (if func-args
1536                      (concat "\\(" (c++-func-args-regexp func-args)
1537                              "\\|" (c++-func-args-string func-args)
1538                              "\\)"))
1539                  ;; If is a constructor member function, then can have some
1540                  ;; default values for base class constructors after a `:'
1541                  ;; but preceding the `{'.
1542                  "[ \t\n\r]*"
1543                  (and func-args
1544                       (equal member-name class)
1545                       "\\(:[^;{}]*\\)?")
1546                  c++-comment-regexp)))
1547            (list
1548             (` (lambda (class)
1549                  (concat "\\`" (, pre-member-regexp)
1550                          (if (not (eq (aref class 0) ?\[))
1551                              (br-regexp-quote class))
1552                          (, post-member-regexp))))
1553             class member-name)))))
1554
1555 (defun c++-feature-map-tags (function regexp)
1556   "Apply FUNCTION to all current feature tags that match REGEXP and return a list of the results."
1557   (let ((identifier-chars (concat "[" c++-identifier-chars "]*"))
1558         (case-fold-search))
1559     ;; Ensure handle "^" and "$" meta-chars.
1560     (setq regexp
1561           (concat (format "\\`%s " br-feature-type-regexp)
1562                   (if (equal (substring regexp 0 1) "^")
1563                       (progn (setq regexp (substring regexp 1)) nil)
1564                     identifier-chars)
1565                   (if (equal (substring regexp -1) "$")
1566                       (substring regexp 0 -1)
1567                     (concat regexp identifier-chars))
1568                   "\\'"))
1569     (br-feature-map-tags function regexp)))
1570
1571 (defun c++-feature-matches (regexp)
1572   "Return an unsorted list of feature tags whose names match in part or whole to REGEXP.
1573 ^ and $ characters may be used to match to the beginning and end of a feature name,
1574 respectively."
1575   (c++-feature-map-tags 'identity regexp))
1576
1577 (defun c++-feature-method-declaration (class-and-method-name)
1578   "Return a regexp matching the declaration of CLASS-AND-METHOD-NAME.
1579 \(The class:: part is optional).  Grouping 0 starts the class name if given.
1580 Grouping 1 matches the method name within the declaration."
1581   (let (class method)
1582     (if (string-match "::" class-and-method-name)
1583         (setq class (substring class-and-method-name 0 (match-beginning 0))
1584               method (substring class-and-method-name (match-end 0)))
1585       (setq class nil
1586             method class-and-method-name))
1587     (if class
1588         (format "\\<%s\\s-*::\\s-*\\(\\<%s\\>\\)\\s-*\("
1589                 (regexp-quote class) (regexp-quote method))
1590       (format "\\(\\<%s\\>\\)\\s-*\(" (regexp-quote method)))))
1591
1592 (defun c++-feature-method-display (class-name method-name reference-name message-flag)
1593   "Display CLASS-NAME's METHOD-NAME method derived from REFERENCE-NAME.
1594 MESSAGE-FLAG non-nil means display messages explaining whether the attribute was
1595 found or not.  Return t if found and nil otherwise."
1596   (if (br-edit nil class-name)
1597       (let ((case-fold-search)) ;; case-sensitive matching
1598         (message "")
1599         (if (save-excursion
1600               (re-search-forward
1601                (c++-feature-method-declaration method-name)
1602                nil t))
1603             (progn (br-display-code (match-beginning 0))
1604                    (if message-flag
1605                        (message
1606                         "(OO-Browser):  `%s' found within class `%s'"
1607                         method-name class-name))
1608                    t)
1609           (if message-flag
1610               (progn (message "(OO-Browser):  `%s' not declared within class `%s'"
1611                               method-name class-name)
1612                      (beep)))
1613           nil))
1614     (if message-flag
1615         (progn (message
1616                 "(OO-Browser):  %s's class `%s' not defined within the Environment"
1617                 reference-name method-name class-name)
1618                (beep)))
1619     nil))
1620
1621 (defun c++-feature-normalize (feature class name &optional friend-flag)
1622   "Return a feature tag based on FEATURE, CLASS, NAME and optional FRIEND-FLAG."
1623   (setq class (br-delete-space class)
1624         name (c++-feature-add-prefix name class feature friend-flag))
1625   (concat class c++-type-tag-separator
1626           name c++-type-tag-separator 
1627           (br-feature-delete-c-comments feature)))
1628
1629 (defun c++-feature-reference-definition ()
1630   "Jumps to the definition of or lists possible definitions of a C++ member reference.
1631 If no definitions are found and there is a . or -> reference prefix, then it
1632 attempts to display the declaration for the reference.
1633 Returns t if a member (non-global) definition or declaration is found,
1634 otherwise returns nil."
1635   (let* ((member-elts (c++-feature-at-reference-p))
1636          (variable (nth 0 member-elts))
1637          (member-reference-prefix (nth 1 member-elts))
1638          (class-name (nth 2 member-elts))
1639          (scoping-operator (nth 3 member-elts))
1640          (member-name (nth 4 member-elts))
1641          (method-flag (nth 5 member-elts))
1642          (found)
1643          (err)
1644          result)
1645     (setq result
1646           (if (and member-elts (fboundp 'br-feature-display-implementors))
1647               (condition-case ()
1648                   (progn
1649                     (message "Looking for `%s'..." member-name)
1650                     (cond
1651                      ;;
1652                      ;;      1. ::global_function(...) or ::variable
1653                      ;;        * Ignore, global functions and variables are
1654                      ;;          handled by another function.
1655                      ((and (null class-name) scoping-operator)
1656                       (setq found t)
1657                       (message "")
1658                       nil)
1659                      ;;
1660                      ;;      2. class::scoped_method(...) or class::scoped_attribute
1661                      ((and class-name scoping-operator)
1662                       ;;       * Look up scoped_member in class.
1663                       ;;       * Look up scoped_member in each
1664                       ;;         ancestor until find a match.
1665                       ;;
1666                       ;;         Refine this procedure in the future
1667                       ;;         by accepting only those methods with the same
1668                       ;;         number of arguments as the call.
1669                       ;;
1670                       ;;         Also refine by looking for declarations through
1671                       ;;         all ancestors of class if no definitions are
1672                       ;;         found.
1673                       ;;
1674                       ;;         Also refine to handle class::construct->member()
1675                       ;;         situations where the class is known.
1676                       ;;
1677                       (setq found
1678                             (if method-flag
1679                                 (if (zerop (br-feature-ancestor-implementors
1680                                             class-name member-name method-flag))
1681                                     (progn
1682                                       (setq err
1683                                             (format
1684                                              "(OO-Browser):  `%s::%s' definition not found"
1685                                              class-name member-name))
1686                                       nil)
1687                                   t)
1688                               ;; attribute - goto class def and then search for it
1689                               (c++-feature-attribute-display
1690                                class-name member-name member-name t)))
1691                       t)
1692                      ;;
1693                      ;;      3. variable.method(...) or variable.attribute
1694                      ;;         variable-ptr->method(...) or variable-ptr->attribute
1695                      (member-reference-prefix
1696                       ;;
1697                       ;;       * Determine the static class of the variable.
1698                       ;;         If it is declared within the current file:
1699                       ;;           follow the steps in #2 except list all
1700                       ;;           ancestral matches rather than just the
1701                       ;;           first to account for dynamic binding.
1702                       ;;         Else if no variable type can be determined,
1703                       ;;           list all known implementors of the method or
1704                       ;;           display the definition if there is only one 
1705                       ;;           match.
1706                       ;;
1707                       (setq found
1708                             (if (and variable
1709                                      (or class-name
1710                                          (setq class-name
1711                                                (c++-feature-variable-class
1712                                                 variable))))
1713                                 (if method-flag
1714                                     (if (zerop (br-feature-ancestor-implementors
1715                                                 class-name member-name method-flag))
1716                                         (progn
1717                                           (setq err
1718                                                 (format
1719                                                  "(OO-Browser):  `%s::%s' definition not found"
1720                                                  class-name member-name))
1721                                           nil)
1722                                       t)
1723                                   ;; attribute - goto class def and then
1724                                   ;;             search for it
1725                                   (c++-feature-attribute-display
1726                                    class-name member-name
1727                                    (concat variable member-reference-prefix
1728                                            member-name) t))
1729                               (if method-flag
1730                                   (if (br-feature-display-implementors member-name)
1731                                       (progn (message "") t)))))
1732                       t)
1733                      ;;
1734                      ;;      4. method(...)
1735                      ;;         ~destructor(...)
1736                      ((and (null class-name) (null scoping-operator))
1737                       ;;
1738                       ;;       * Get the class of the method/function
1739                       ;;         in which the call is made.  If this
1740                       ;;         enclosing context is not a global function,
1741                       ;;         follow the steps in #3.
1742                       ;;       * If not found yet, ignore it and it will be
1743                       ;;         looked up as a global function by another
1744                       ;;         function.
1745                       ;;
1746                       (if (setq class-name (c++-feature-class-name))
1747                           (setq found (not (zerop (br-feature-ancestor-implementors
1748                                                    class-name member-name
1749                                                    method-flag))))
1750                         (setq found t)
1751                         (message "")
1752                         nil))
1753                      (t (setq err "(OO-Browser):  (c++-feature-reference-definition) - unrecognized context")
1754                         nil)))
1755                 (error nil))))
1756
1757       (if (and (not found) member-reference-prefix class-name member-name)
1758           ;; This will signal an error if no declaration is found; return t
1759           ;; in case it does not.
1760           (progn (c++-feature-view-declaration
1761                   (concat class-name "::" member-name) t)
1762                  t)
1763         (if err
1764             (progn (message err) (beep)))
1765         result)))
1766
1767 (defun c++-feature-variable-class (variable)
1768   "Search backward from point looking for a type declaration of VARIABLE.
1769 Return the class of the variable which may differ from its type (due to * and & operators)."
1770   ;; Pseudo-variable `this' refers to the current class.
1771   (if (string-equal variable "this")
1772       (c++-feature-class-name)
1773     (save-excursion
1774       (let ((class))
1775         (while (and (c++-feature-to-item-declaration variable)
1776                     (setq class (buffer-substring
1777                                  (match-beginning 3) (match-end 3)))
1778                     (br-member class '("delete" "new")))
1779           (setq class nil))
1780         (if class (c++-normalize-template-arguments class))))))
1781
1782 (defvar c++-feature-item-regexp1
1783    "\\(^\\|[\;\(]\\)\\s-*\\(\\(%s\\)[*& \t\n\r]+\\)\\([_a-zA-Z][^\;,\(\)]*,\\)*\\s-*\\(\\<%s\\>\\)\\s-*"
1784    "Grouping 2 matches the item's type, possibly with trailing whitespace.
1785 Grouping 3 matches its class (dropping any * or & characters).  Grouping 5
1786 matches the item name within the declaration.")
1787
1788 (defvar c++-feature-item-regexp2
1789    "\\(,\\)\\s-*\\(\\(%s\\)[*& \t\n\r]+\\)\\(\\)\\s-*\\(\\<%s\\>\\)\\s-*"
1790    "Grouping 2 matches the item's type, possibly with trailing whitespace.
1791 Grouping 3 matches its class (dropping any * or & characters).  Grouping 5
1792 matches the item name within the declaration.")
1793
1794 (defun c++-feature-to-item-declaration (item)
1795   "Search backwards to a match for the declaration of ITEM name and return point or nil if no match.
1796 See the documentation string for `c++-feature-item-regexp' for a description
1797 of matched groupings."
1798   (or (re-search-backward
1799        (format (concat c++-feature-item-regexp1 "[\[\(=\;,*&\)]")
1800                c++-identifier (regexp-quote item)) nil t)
1801       (re-search-backward
1802        (format (concat c++-feature-item-regexp2 "[\[\(=\;,*&\)]")
1803                c++-identifier (regexp-quote item)) nil t)))
1804
1805 (defun c++-feature-to-variable-declaration (variable)
1806   "Search backwards to a match for the declaration of VARIABLE name and return point or nil if no match.
1807 See the documentation string for `c++-feature-item-regexp' for a description
1808 of matched groupings."
1809   (or (re-search-backward
1810        (format (concat c++-feature-item-regexp1 "[\[=\;,*&\)]")
1811                c++-identifier (regexp-quote variable)) nil t)
1812       (re-search-backward
1813        (format (concat c++-feature-item-regexp2 "[\[=\;,*&\)]")
1814                c++-identifier (regexp-quote variable)) nil t)))
1815
1816 (defun c++-files-with-source (class)
1817   "Use CLASS to compute set of files that match to a C++ source file regexp.
1818 Return as a list."
1819   (let ((file (if class (br-class-path class) buffer-file-name)))
1820     (and file
1821          (let* ((src-file-regexp (concat "^" (br-filename-head file)
1822                                          c++-code-file-regexp))
1823                 (dir (file-name-directory file))
1824                 (files (directory-files dir nil src-file-regexp)))
1825            (mapcar (function (lambda (f) (expand-file-name f dir)))
1826                    files)))))
1827
1828 (defun c++-find-ancestors-feature (class-list ftr-pat &optional other-win)
1829   "Scan ancestors of CLASS-LIST and show feature definition matching FTR-PAT.
1830 Optional OTHER-WIN means display the result in another window."
1831   ;; If no class, search for non-member function.
1832   (or class-list (setq class-list '(nil)))
1833   (br-feature-display class-list ftr-pat other-win))
1834
1835 (defun c++-find-class-name ()
1836   "Return current word as a potential class name."
1837   (save-excursion
1838     (let* ((start)
1839            (ignore "-\]\[& \t\n\r\;,.\(\){}*")
1840            (pat (concat "^" ignore)))
1841       (forward-char 1)
1842       (skip-chars-backward ignore)
1843       (skip-chars-backward pat)
1844       (setq start (point))
1845       (skip-chars-forward (concat pat ":"))
1846       (buffer-substring start (point)))))
1847
1848 (defun c++-func-args-regexp (func-args)
1849   (let* ((space "%%%")
1850          (obuf (current-buffer))
1851          (tmp-buf (get-buffer-create c++-tmp-buffer-name)))
1852     (or tmp-buf (error "(OO-Browser):  (c++-func-args-regexp) - Can't create tmp-buf"))
1853     (set-buffer tmp-buf)
1854     (setq buffer-read-only nil)
1855     (erase-buffer)
1856     ;; Fill tmp-buffer with all func-args, including parens.
1857     (insert (br-regexp-quote func-args))
1858
1859     (goto-char (point-min))
1860     (if (looking-at "(\\s-*)")
1861         (replace-match "(\\s-*)" t t)
1862
1863       ;; Replace all "\( +" with "\(" temporarily
1864       (br-buffer-replace "\\(^\\|[^\\]\\)\([ \t\n\r]+" "\\1\(")
1865     
1866       ;; Replace all "+ \)" with "\)" temporarily
1867       (br-buffer-replace "[ \t\n\r]+\)" "\)")
1868     
1869       ;; Replace all "...\)" with "@@@" temporarily
1870       (br-buffer-replace "\\\\\\.\\\\\\.\\\\\\.\)" "@@@")
1871
1872       ;; Optionalize right hand side of argument defaults.
1873       (br-buffer-replace "\\([^=,\( \t\n\r]+\\)\\([ \t\n\r]*=[^,\)]+\\)"
1874                          (concat "\\1\\\\( "
1875                                  c++-arg-identifier
1876                                  "\\\\)? \\\\(\\2\\\\)?"))
1877
1878       ;; Replace all "\)" with "optional <c++-identifier> \)"
1879       (br-buffer-replace
1880        ;; Yes, all this complexity really is necessary.
1881        "\\([\\\(,][^=\)]*[^\\=\)]+\\)\\(\\\\*\)\\)"
1882        (concat "\\1\\\\( " c++-arg-identifier
1883                "\\\\)?\\2"))
1884
1885       ;; Replace all  "," with "optional <c++-identifier>,"
1886       (br-buffer-replace
1887        "\\([\(,][^=,]+\\),"
1888        (concat "\\1\\\\( " c++-arg-identifier "\\\\)?,"))
1889
1890       ;; Replace all  " *, *" with "<space>,<space>"
1891       (br-buffer-replace "[ \t\n\r]*,[ \t\n\r]*" (concat space "," space))
1892     
1893       ;; Replace all " +" with "<spc>"
1894       (br-buffer-replace "[ \t\n\r]+" space)
1895
1896       ;; Replace all "\(" with "\(<space>"
1897       (br-buffer-replace "\\(^\\|[^\\]\\)\(" (concat "\\1\(" space))
1898     
1899       ;; Replace all "\)" with "<space>\)"
1900       (br-buffer-replace "\\([^\\]\\)\)" (concat "\\1" space "\)"))
1901
1902       ;; Replace all & and quoted \\* with "<spc>[*&]+<spc>"
1903       (br-buffer-replace "\\(\\(&\\|\\\\\\*\\)+\\)" (concat space "\\1" space))
1904
1905       ;; Replace all "<spc>"
1906       (br-buffer-replace space " *" t)
1907
1908       ;; Replace all "@@@" with any # of args
1909       (br-buffer-replace "@@@" "[^\)]*\)" t)
1910       )
1911
1912     ;; Return final buffer as a string.
1913     (prog1 (buffer-substring (point-min) (point-max))
1914       (set-buffer-modified-p nil)
1915       (set-buffer obuf))))
1916
1917 (defun c++-func-args-string (func-args)
1918   (let* ((space "%%%")
1919          (obuf (current-buffer))
1920          (tmp-buf (get-buffer-create c++-tmp-buffer-name)))
1921     (or tmp-buf (error "(OO-Browser):  (c++-func-args-string) - Can't create tmp-buf"))
1922     (set-buffer tmp-buf)
1923     (setq buffer-read-only nil)
1924     (erase-buffer)
1925     ;; Fill tmp-buffer with all func-args, including parens.
1926     (insert (br-regexp-quote func-args))
1927
1928     (goto-char (point-min))
1929     (if (looking-at "(\\s-*)")
1930         (replace-match "(\\s-*)" t t)
1931
1932       ;; Replace all "\( +" with "\(" temporarily
1933       (br-buffer-replace "\\(^\\|[^\\]\\)\([ \t\n\r]+" "\\1\(")
1934     
1935       ;; Replace all "+ \)" with "\)" temporarily
1936       (br-buffer-replace "[ \t\n\r]+\)" "\)")
1937     
1938       ;; Replace all "...\)" with "@@@" temporarily
1939       (br-buffer-replace "\\\\\\.\\\\\\.\\\\\\.\)" "@@@")
1940
1941       ;; If an arg consists of 2 or more words and does not end with [*&>],
1942       ;; replace the last word with <identifier>.
1943       (br-buffer-replace
1944        "\\([\(,][^=,\)]*[^ \t\n\r=,\)]+[ \t\n\r\\*&]+\\)[^ \t\n\r*&<>=,\)]+\\([ \t\n\r]*[,=\)]\\)"
1945        (concat "\\1" c++-arg-identifier "\\2"))
1946
1947       ;; If an arg consists of only 1 word and does not end with [*&>], add an
1948       ;; <identifier> following it.
1949       (br-buffer-replace
1950        "\\([\(,][ \t\n\r]*\\)\\([^ \t\n\r*&<>=,\)]+\\)\\([ \t\n\r]*[,=\)]\\)"
1951        (concat "\\1\\2 " c++-arg-identifier "\\3"))
1952
1953       ;; If an arg ends with [*&>], add an <identifier> following it.
1954       (br-buffer-replace
1955        "\\([\(,][ \t\n\r]*\\)\\([^=,\)]+\\([\\]*[*&>]+\\)+\\)\\([ \t\n\r]*[,=\)]\\)"
1956        (concat "\\1\\2 " c++-arg-identifier "\\4"))
1957
1958       ;; Optionalize right hand side of argument defaults.
1959       ;; Do this after literal variable names have been changed to regexps or
1960       ;; variable names preceding the parentheses that this inserts will not
1961       ;; be changed to regexps.
1962       (br-buffer-replace "\\([^=,\( \t\n\r]+\\)\\([ \t\n\r]*=[^,\)]+\\)"
1963                          "\\1\\\\(\\2\\\\)?")
1964
1965       ;; Replace all  " *, *" with "<space>,<space>"
1966       (br-buffer-replace "[ \t\n\r]*,[ \t\n\r]*" (concat space "," space))
1967     
1968       ;; Replace all " +" with "<spc>"
1969       (br-buffer-replace "[ \t\n\r]+" space)
1970
1971       ;; Replace all "\(" with "\(<space>"
1972       (br-buffer-replace "\\(^\\|[^\\]\\)\(" (concat "\\1\(" space))
1973     
1974       ;; Replace all "\)" with "<space>\)"
1975       (br-buffer-replace "\\([^\\]\\)\)" (concat "\\1" space "\)"))
1976
1977       ;; Replace all & and quoted \\* with "<spc>[*&]+<spc>"
1978       (br-buffer-replace "\\(\\(&\\|\\\\\\*\\)+\\)" (concat space "\\1" space))
1979
1980       ;; Replace all "<spc>"
1981       (br-buffer-replace space " *" t)
1982
1983       ;; Replace all "@@@" with any # of args
1984       (br-buffer-replace "@@@" "[^\)]*\)" t)
1985       )
1986
1987     ;; Return final buffer as a string.
1988     (prog1 (buffer-substring (point-min) (point-max))
1989       (set-buffer-modified-p nil)
1990       (set-buffer obuf))))
1991
1992 (defun c++-get-class-name-from-source ()
1993   "Return class name from the class definition that encloses point or nil."
1994   (let ((opoint (point))
1995         (class))
1996     (save-excursion
1997       (if (re-search-backward c++-class-def-regexp nil t)
1998           (progn (goto-char (match-beginning c++-class-def-derived-grpn))
1999                  (setq class (c++-normalize-class-match nil))
2000                  ;; Ensure that declaration occurs within class definition.
2001                  (condition-case ()
2002                      (progn (forward-list)
2003                             (if (> (point) opoint)
2004                                 class))
2005                    (error
2006                     (error "(OO-Browser):  (c++-get-class-name-from-source) - Mismatched class definition braces"))))))))
2007
2008 (defun c++-output-feature-tags (feature-file feature-tags-list)
2009   "Write C++ FEATURE-FILE's FEATURE-TAGS-LIST into `br-feature-tags-file'.
2010 Assume `br-feature-tags-init' has been called."
2011   (interactive)
2012   (save-excursion
2013     (br-feature-set-tags-buffer)
2014     (goto-char 1)
2015     ;; Delete any prior feature tags associated with feature-file.
2016     (let (start)
2017       ;; There may be more than one set of entries for each file name.
2018       (while (search-forward feature-file nil 'end)
2019         (forward-line -1)
2020         (setq start (point))
2021         (search-forward "\^L" nil 'end 2)
2022         (backward-char 1)
2023         (delete-region start (point))))
2024     (if feature-tags-list
2025         (progn (insert "\^L\n")
2026                ;; Quote pathname to avoid read errors on MS OSes.
2027                (prin1 feature-file (current-buffer))
2028                (insert "\n")
2029                (mapcar (function (lambda (tag) (insert tag "\n")))
2030                        feature-tags-list)))))
2031
2032 (defun c++-include-file (&optional other-win)
2033   "If point is on an include file line, try to display file.
2034 Return non-nil iff an include file line, even if file is not found.
2035 Look for include file in `c++-cpp-include-dirs' and in directory list
2036 `c++-include-dirs'."
2037   (let ((opoint (point)))
2038     (beginning-of-line)
2039     (if (looking-at c++-include-regexp)
2040         (let ((incl-type (string-to-char
2041                           (buffer-substring (match-beginning 1)
2042                                                (1+ (match-beginning 1)))))
2043               (file (buffer-substring (match-beginning 2) (match-end 2)))
2044               (path)
2045               (dir-list c++-include-dirs)
2046               (found))
2047           (goto-char opoint)
2048           (setq dir-list (if (eq incl-type ?\<)
2049                              (append dir-list c++-cpp-include-dirs)
2050                            (cons (file-name-directory buffer-file-name)
2051                                  dir-list)))
2052           (while dir-list
2053             (setq path (concat (car dir-list) file)
2054                   dir-list (if (setq found (file-exists-p path))
2055                                nil
2056                              (cdr dir-list))))
2057           ;;
2058           ;; If not found in normal include dirs, check all Env paths also.
2059           ;;
2060           (if (not found)
2061               (let ((paths (delq nil (hash-map 'cdr br-paths-htable))))
2062                 (while paths
2063                   (setq path (car paths))
2064                   (if (string-equal (file-name-nondirectory path) file)
2065                       (setq found t paths nil)
2066                     (setq paths (cdr paths))))))
2067           ;;
2068           ;; If found, display file
2069           ;;
2070           (if found
2071               (if (file-readable-p path)
2072                   (progn
2073                     (funcall br-edit-file-function path other-win)
2074                     (if (not (fboundp 'br-lang-mode))
2075                         (c++-mode-setup))
2076                     (br-major-mode))
2077                 (beep)
2078                 (message "(OO-Browser):  Include file `%s' unreadable" path))
2079             (beep)
2080             (message "(OO-Browser):  Include file `%s' not found" file))
2081           path)
2082       (goto-char opoint)
2083       nil)))
2084
2085 (defun c++-locate-feature (ftr class ftr-pat &optional other-win)
2086   ;; `class' may = nil, implying non-member function
2087   (or class (setq class "[function]"))
2088   (let ((def-class))
2089     (if (and ftr-pat
2090              (setq def-class
2091                    (c++-find-ancestors-feature (list class)
2092                                                ftr-pat other-win)))
2093         (progn (if (and class (not (equal class def-class)))
2094                    (message
2095                      "Member `%s' of class `%s' inherited from class `%s'."
2096                      ftr class def-class))
2097                t))))
2098
2099 (defun c++-scan-ancestors-feature (class-list ftr-pat &optional other-win)
2100   "Display feature definition derived from CLASS-LIST, matching FTR-PAT.
2101 Scan files with same base name as class file."
2102   (let  ((classes class-list)
2103          (found-ftr)
2104          (code-def-files)
2105          (file)
2106          (ftr-sig-regexp)
2107          (class))
2108     (if (null class-list)
2109         nil
2110       (while (and (not found-ftr) classes)
2111         (setq class (car classes)
2112               code-def-files (c++-files-with-source class)
2113               ftr-sig-regexp (funcall ftr-pat class))
2114         (while (and (setq file (car code-def-files))
2115                     (not (setq found-ftr
2116                                (br-feature-found-p file ftr-sig-regexp
2117                                                    nil other-win t))))
2118           (setq code-def-files (cdr code-def-files)))
2119         (setq classes (if found-ftr nil (cdr classes))))
2120       (if found-ftr
2121           (or class t)
2122         (c++-scan-ancestors-feature
2123          (apply 'append (mapcar (function (lambda (cl) (br-get-parents cl)))
2124                                 class-list))
2125          ftr-pat)))))
2126
2127 (defun c++-scan-features-in-class (class start end)
2128   "Return reverse ordered list of C++ feature (attribute and method) definitions within CLASS declaration.
2129 START and END give buffer region to search.
2130 Assume that all comments have been removed by the caller.
2131 This scans only those features defined within the declaration of a class;
2132 see `c++-scan-features' for the code that processes features defined elsewhere."
2133   (setq class (br-delete-space class))
2134   (save-excursion
2135     (save-restriction
2136       (narrow-to-region start end)
2137       (goto-char start)
2138       (let ((features) signature name type type-modifiers)
2139         ;;
2140         ;; Get friend routine declarations.
2141         ;;
2142         (while (re-search-forward c++-friend-in-class nil t)
2143           (setq start (match-beginning 0)
2144                 name (br-buffer-substring
2145                       (match-beginning c++-feature-name-grpn)
2146                       (match-end c++-feature-name-grpn))
2147                 type (if (match-beginning c++-feature-type-grpn)
2148                          (br-buffer-substring
2149                           (match-beginning c++-feature-type-grpn)
2150                           (match-end c++-feature-type-grpn)))
2151                 signature (br-buffer-substring (match-beginning 0)
2152                                                (match-end 0))
2153                 ;; Do this after done getting groupings from the search.
2154                 type (if type (br-delete-space type)))
2155           ;; Get rid of this friend so it doesn't slow down later scanning.
2156           (delete-region start (point))
2157           ;; Handle type conversion ops: operator int() { return i; }
2158           (if (equal type "operator") (setq name (concat type " " name)
2159                                             type nil))
2160           (setq signature (c++-feature-normalize signature class name t)
2161                 features (cons signature features)))
2162         ;;
2163         ;; Get method definitions and pure virtual declarations.
2164         ;;
2165         (goto-char (point-min))
2166         (while (re-search-forward c++-routine-in-class nil t)
2167           (setq start (match-beginning 0)
2168                 name (br-buffer-substring
2169                       (match-beginning c++-feature-name-grpn)
2170                       (match-end c++-feature-name-grpn))
2171                 type (if (match-beginning c++-feature-type-grpn)
2172                          (br-buffer-substring
2173                           (match-beginning c++-feature-type-grpn)
2174                           (match-end c++-feature-type-grpn)))
2175                 signature (br-buffer-substring
2176                            (match-beginning 0) (match-end 0)))
2177           (if (and (string-equal
2178                     "\;" (buffer-substring (match-beginning
2179                                             c++-feature-terminator-grpn)
2180                                            (1+ (match-beginning
2181                                                 c++-feature-terminator-grpn))))
2182                    (not (string-match c++-pure-virtual-function-regexp signature)))
2183               ;; Routine declaration only, ignore and delete
2184               ;; this declaration so that it doesn't slow down later
2185               ;; scanning.
2186               (progn (forward-line 1)
2187                      (delete-region start (point)))
2188             ;; Do this after all other needed groupings are extracted from the
2189             ;; initial regexp match.
2190             (setq type (if type (br-delete-space type)))
2191             ;; Move point to precede signature opening brace or declaration
2192             ;; semicolon.
2193             (backward-char)
2194             (if (eq (following-char) ?\{)
2195                 (condition-case ()
2196                     ;; Move to end of feature but ignore any error if braces
2197                     ;; are unbalanced.  Let the compiler tell the user about
2198                     ;; this.
2199                     (progn (forward-sexp)
2200                            (forward-line 1)
2201                            ;; Get rid of this method so it doesn't slow down
2202                            ;; later scanning.
2203                            (delete-region start (point)))
2204                   (error nil)))
2205             ;; Handle type conversion ops:  operator int() { return i; }
2206             (if (equal type "operator") (setq name (concat type " " name)
2207                                               type nil))
2208             (setq signature (c++-feature-normalize signature class name)
2209                   features (cons signature features))))
2210         ;;
2211         ;; Get attributes and `friend class' declarations.
2212         ;;
2213         (goto-char (point-min))
2214         (while (re-search-forward c++-attribute-decl nil t)
2215           (setq start (match-beginning 0)
2216                 name (br-buffer-substring
2217                       (match-beginning c++-feature-name-grpn)
2218                       (match-end c++-feature-name-grpn))
2219                 type-modifiers
2220                 (if (match-beginning c++-feature-mod-grpn)
2221                     (br-buffer-substring
2222                      (match-beginning c++-feature-mod-grpn)
2223                      (match-end c++-feature-mod-grpn)))
2224                 type (if (match-beginning c++-feature-type-grpn)
2225                          (br-buffer-substring
2226                           (match-beginning c++-feature-type-grpn)
2227                           (match-end c++-feature-type-grpn)))
2228                 signature (br-buffer-substring
2229                            (match-beginning 0)
2230                            (if (match-beginning c++-attribute-value-grpn)
2231                                ;; include the = preceding a value
2232                                (1+ (match-beginning c++-attribute-value-grpn))
2233                              (match-end 0)))
2234                 ;; Do this after done getting groupings from the search.
2235                 type (if type (br-delete-space type)))
2236           ;; Move point to precede declaration opening brace (enum, struct,
2237           ;; union or typedef) or declaration semicolon.
2238           (backward-char)
2239           (if (eq (following-char) ?\{)
2240               (condition-case ()
2241                   ;; Move to end of feature but ignore any error if braces
2242                   ;; are unbalanced.  Let the compiler tell the user about
2243                   ;; this.
2244                   (forward-sexp)
2245                 (error nil)))
2246           (if (or (and type
2247                        (string-match
2248                         "\\(\\`\\|[ \t\n\r]\\)\\(enum\\|struct\\|union\\|typedef\\)\\(\\'\\|[ \t\n\r]\\)"
2249                         type))
2250                   (if (and type-modifiers
2251                        (string-match
2252                         "\\(\\`\\|[ \t\n\r]\\)\\(enum\\|struct\\|union\\|typedef\\)\\(\\'\\|[ \t\n\r]\\)"
2253                         type-modifiers))
2254                       (if (equal (substring type-modifiers
2255                                             (match-beginning 2) (match-end 2))
2256                                  "typedef")
2257                           (progn (setq type "typedef")
2258                                  t))))
2259               ;; This is a type declaration which may be followed
2260               ;; by one or more attribute names of the type.  Add
2261               ;; a feature entry for each attribute.
2262               (progn (while (and (not (eq (preceding-char) ?\;))
2263                                  (looking-at
2264                                   (concat "\\s-*" c++-identifier "\\s-*[,;]")))
2265                        (goto-char (match-end 0))
2266                        (if (equal type "typedef")
2267                            (setq features
2268                                  (cons (c++-feature-normalize
2269                                         signature
2270                                         (hash-get type c++-c-type-htable)
2271                                         (concat class "::"
2272                                                 (br-buffer-substring
2273                                                  (match-beginning 1)
2274                                                  (match-end 1)))
2275                                         nil)
2276                                        features))
2277                          (setq features (cons (c++-feature-normalize
2278                                                signature class
2279                                                (br-buffer-substring
2280                                                 (match-beginning 1)
2281                                                 (match-end 1)) nil)
2282                                               features))))
2283                      ;; If the previously found type declaration has its
2284                      ;; own name, then add a feature attribute for it.
2285                      (if (and type (hash-get type c++-c-type-htable))
2286                          (setq signature (c++-feature-normalize
2287                                           signature
2288                                           (hash-get type c++-c-type-htable)
2289                                           (concat class "::" name)
2290                                           nil)
2291                                features (cons signature features)))
2292                      (forward-line 1))
2293             ;; Ignore false matches to operator= () and the like triggered by
2294             ;; the =.
2295             (or (string-match "\\<operator\\>[^=\n\r]*=" signature)
2296                 (setq signature
2297                       (c++-feature-normalize
2298                        signature class name
2299                        (if (string-match
2300                             c++-friend-class-regexp signature) t))
2301                       features (cons signature features)))))
2302         features))))
2303
2304 (defun c++-skip-to-statement ()
2305   (if (re-search-backward "\\(^\\|[\;{}()]\\)[ \t]*" nil t)
2306       (progn (goto-char (match-end 0))
2307              (skip-chars-forward " \t")
2308              t)))
2309
2310 (defun c++-view-friend (&optional other-win sig-at-point-flag)
2311   "With point on a friend listing entry or friend signature (prior to any arguments) in a source code buffer, view its source code definition.
2312 With optional OTHER-WIN non-nil, display in another window.
2313 With optional SIG-AT-POINT-FLAG non-nil, assume point is within a
2314 signature in a source buffer."
2315   (interactive)
2316   (let ((opoint (point))
2317         (tag
2318          (if (not sig-at-point-flag)
2319              (br-feature-get-tag)
2320            (c++-skip-to-statement)
2321            ;; Must be the first thing on the line.
2322            (and (= (point) (save-excursion (back-to-indentation) (point)))
2323                 (progn (beginning-of-line)
2324                        (looking-at c++-friend-regexp))
2325                 (looking-at c++-friend-in-class)
2326                 (let ((friend (buffer-substring (match-beginning 0)
2327                                                    (match-end 0)))
2328                       (class (c++-get-class-name-from-source)))
2329                   (c++-feature-normalize
2330                    friend class
2331                    (c++-feature-signature-to-name friend) t))))))
2332     (cond ((or (null tag)
2333                ;; Not a friend entry.
2334                (not (eq ?% (aref (c++-feature-signature-to-name tag nil t) 0))))
2335            (goto-char opoint)
2336            nil)
2337           ((eq ?\{ (aref tag (1- (length tag))))
2338            ;; Friend is defined where declared.
2339            (br-feature 'view tag)
2340            t)
2341           ((string-match (format " class \\(%s\\) ?;$"
2342                                  c++-return-type-identifier) tag)
2343            ;; friend class
2344            (br-view nil nil
2345                     (c++-normalize-template-arguments
2346                      (substring tag (match-beginning 1) (match-end 1))))
2347            t)
2348           (t
2349            (if sig-at-point-flag
2350                nil ;; Other feature location code will handle this.
2351              (br-feature t tag) ;; Move point to friend declaration.
2352              (c++-feature other-win))))))
2353
2354 (defun c-remove-functions ()
2355   "Delete any C function definitions from the buffer.
2356 These are handled by the ootags program for the OO-Browser and leaving
2357 them in could cause invalid scans within their bodies.  Assume point is at
2358 the beginning of widened buffer and that all comments have been removed by
2359 the caller.  This processes only those functions defined outside of class
2360 declarations."
2361   (save-excursion
2362     (goto-char (point-min))
2363     (condition-case ()
2364         (while (re-search-forward c-function-def nil t)
2365           (delete-region (match-end 0)
2366                          (progn (c++-feature-to-end) (point))))
2367       (error nil))))
2368
2369 (provide 'br-c++-ft)