diff lisp/packages/func-menu.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 0293115a14e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/packages/func-menu.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,2231 @@
+;;; func-menu.el         --- Jump to a function within a buffer.
+;;;
+;;; David Hughes <ukchugd@ukpmr.cs.philips.nl>
+;;; Last modified: David Hughes 2nd May 1996
+;;; Version: 2.43
+;;; Keywords: tools, c, lisp
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2, or (at your option)
+;;; any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;;
+;;; Synched up with: Not in FSF.
+;;;
+;;; Installation:
+;;; =============
+;;; (require 'func-menu)
+;;; (define-key global-map 'f8 'function-menu)
+;;; (add-hook 'find-file-hooks 'fume-add-menubar-entry)
+;;; (define-key global-map "\C-cl" 'fume-list-functions)
+;;; (define-key global-map "\C-cg" 'fume-prompt-function-goto)
+;;; (define-key global-map '(shift button3) 'mouse-function-menu)
+;;; (define-key global-map '(meta  button1) 'fume-mouse-function-goto)
+;;;
+;;; Description:
+;;; ============
+;;; Suppose you have a file with a lot of functions in it. Well, this package
+;;; makes it easy to jump to any of those functions. The names of the
+;;; functions in the current buffer are automatically put into a popup menu,
+;;; you select one of the function-names and the point is moved to that very
+;;; function. The mark is pushed on the mark-ring, so you can easily go back
+;;; to where you were. Alternatively, you can use enter the name of the
+;;; desired function via the minibuffer which offers completing read input. In
+;;; addition, the name of the function before point is optionally displayed in
+;;; the modeline.
+;;;
+;;; Support for non X Windows versions of Emacs:
+;;; ============================================
+;;; This package can also be used for non X versions of Emacs. In this case,
+;;; only modeline display and completing read input from the minibuffer are
+;;; possible.
+;;;
+;;; Modes supported:
+;;; ================
+;;; Ada, Assembly, Bacis2, BibTex, C++, C, Dired, Ehdm, ELisp, FORTRAN, Ksh,
+;;; Latex, Lelisp, Makefile, Maple, Modula2, Modula3, Outline, Pascal, Perl,
+;;; Postscript, Prolog, PVS, Python, SGML, Scheme, Tcl, Verilog
+;;;
+;;; Acknowledgements:
+;;; =================
+;;;
+;;; Fortran90 regexp
+;;; John Turner <turner@xdiv.lanl.gov>
+;;;
+;;; Patch to error trap in fume-rescan-buffer
+;;; Andy Piper <andyp@parallax.co.uk>
+;;;
+;;; Java support
+;;; Heddy Boubaker <boubaker@dgac.fr>
+;;;
+;;; Patch for fume-rescan-buffer{-trigger}
+;;; Christoph Wedler <wedler@vivaldi.fmi.uni-passau.de>
+;;;
+;;; Patch for fume-tickle-f-to-b
+;;; Michael Sperber <sperber@informatik.uni-tuebingen.de>
+;;;
+;;; Cleanup suggestions
+;;; Jonathan Stigelman <stig@hackvan.com>
+;;;
+;;; Idea for jumping directly with a mouse click
+;;; Marc Paquette <Marc.Paquette@Softimage.COM>
+;;;
+;;; Prolog mode additions based on functions for Postscript mode
+;;; Laszlo Teleki <laszlo@ipb.uni-bonn.de>
+;;;
+;;; Idea for displaying function name in modeline
+;;; Paul Filipski <filipski@blackhawk.com>
+;;;
+;;; Fame mode support
+;;; Cooper Vertz <cooper@prod2.imsi.com>
+;;;
+;;; Made fume-match-find-next-function-name iterative, not recursive, to avoid
+;;; blowing out the emacs stack on big files with lots of prototypes.
+;;; Joe Marshall <jrm@odi.com>
+;;;
+;;; Verilog support
+;;; Matt Sale <mdsale@icdc.delcoelect.com>
+;;;
+;;; Minibuffer interface & Pascal support
+;;; Espen Skoglund <espensk@stud.cs.uit.no>
+;;;
+;;; Python support
+;;; Shuichi Koga <skoga@virginia.edu>
+;;;
+;;; Maple support
+;;; Luc Tancredi <Luc.Tancredi@sophia.inria.fr>
+;;;
+;;; Combined Tcl and C++ function finder
+;;; Andy Piper <ajp@eng.cam.ac.uk>
+;;;
+;;; Perl Support
+;;; Alex Rezinsky <alexr@msil.sps.mot.com>
+;;; Michael Lamoureux <lamour@engin.umich.edu>
+;;;
+;;; Suggested mouse interface
+;;; Raymond L. Toy <toy@soho.crd.ge.com>
+;;;
+;;; Dired support
+;;; Improved modula support
+;;; Numerous code cleanups
+;;; Norbert Kiesel <norbert@i3.informatik.rwth-aachen.de>
+;;;
+;;; Makefile support
+;;; Suggested multi-choice sublisting
+;;; Paul Filipski & Anthony Girardin <{filipski,girardin}@blackhawk.com>
+;;;
+;;; Suggestions for menubar entry
+;;; Andy Piper <ajp@eng.cam.ac.uk>
+;;;
+;;; Ada support
+;;; Scott Evans  <gse@ocsystems.com>
+;;; Michael Polo <mikep@polo.mn.org> <mikep@cfsmo.honeywell.com>
+;;;
+;;; Scheme, BibTeX, Ehdm & PVS support
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+;;;
+;;; Modula support
+;;; Geoffrey Wyant <gwyant@cloyd.east.sun.com>
+;;;
+;;; SGML support; submenu indexing
+;;; Thomas Plass <thomas.plass@mid-heidelberg.de>
+;;;
+;;; Extensions to fume-function-name-regexp-lisp
+;;; Kari Heinola <kph@dpe.fi>
+;;; Milo A. Chan <chan@jpmorgan.com>
+;;; Jack Repenning <jackr@step7.informix.com>
+;;; Cedric Beust <Cedric.Beust@sophia.inria.fr>
+;;; Joachim Krumnow <krumnow@srsir02.ext.sap-ag.de>
+;;;
+;;; ksh support
+;;; Philippe Bondono <bondono@vnet.ibm.com>
+;;;
+;;; FORTRAN support
+;;; Paul Emsley <paule@chem.gla.ac.uk>
+;;; Raymond L. Toy <toy@soho.crd.ge.com>
+;;; Richard Cognot <cognot@elfgrc.co.uk>
+;;; Greg Sjaardema <gdsjaar@sandia.gov>
+;;;
+;;; Latex support
+;;; Wolfgang Mettbach <wolle@uni-paderborn.de>
+;;; Paolo Frasconi <paolo@mcculloch.ing.unifi.it>
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+;;; Philippe Queinnec <queinnec@cenatls.cena.dgac.fr>
+;;;
+;;; Assembly support
+;;; Bob Weiner <weiner@mot.com>
+;;;
+;;; Removal of cl dependencies
+;;; Russell Ritchie <russell@gssec.bt.co.uk>
+;;;
+;;; C++ mode enhancemencements for func-menu
+;;; Andy Piper      <ajp@eng.cam.ac.uk>
+;;; Kevin R. Powell <powell@csl.ncsa.uiuc.edu>
+;;; Mats Lidell     <mats.lidell@eua.ericsson.se>
+;;; Mike Battaglia  <mbattagl@spd.dsccc.com>
+;;; Oliver Schittko <schittko@fokus.gmd.de>
+;;; Tom Murray      <tmurray@hpindck.cup.hp.com>
+;;; Russell Ritchie <russell@gssec.bt.co.uk>
+;;;
+;;; Tcl mode additions for func-menu
+;;; Andy Piper <ajp@eng.cam.ac.uk>
+;;; Jean-Michel Augusto <augusto@eurecom.fr>
+;;; Dr P.G. Sjoerdsma <pgs1002@esc.cam.ac.uk>
+;;;
+;;; Postscript mode additions for func-menu
+;;; Leigh Klotz <klotz@adoc.xerox.com>
+;;;
+;;; Suggestions for popup menu positioning
+;;; Marc Gemis <makke@wins.uia.ac.be>
+;;;
+;;; Original FSF package
+;;; Ake Stenhoff <etxaksf@aom.ericsson.se>
+
+;;; Code
+
+(eval-when-compile
+  (byte-compiler-options
+    (optimize t)
+    (new-bytecodes t)
+    (warnings (- free-vars unresolved))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;  Environment Initialisation  ;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst fume-version "2.43")
+
+(defconst fume-developer "David Hughes <ukchugd@ukpmr.cs.philips.nl>")
+
+(defun fume-about ()
+  (interactive)
+  (sit-for 0)
+  (message "Func-Menu version %s, ¨ 1996 %s" fume-version fume-developer))
+
+(defconst fume-running-xemacs (string-match "XEmacs\\|Lucid" emacs-version))
+
+(defmacro fume-defvar-local (var value &optional doc)
+  "Defines SYMBOL as an advertised variable.
+Performs a defvar, then executes `make-variable-buffer-local' on
+the variable.  Also sets the `permanent-local' property, so that
+`kill-all-local-variables' (called by major-mode setting commands)
+won't destroy func-menu control variables."
+  (` (progn
+       (if (, doc)
+           (defvar (, var) (, value) (, doc))
+         (defvar (, var) (, value)))
+       (make-variable-buffer-local '(, var))
+       (put '(, var) 'permanent-local t))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;  Backward compatibility hacks for older versions of XEmacs  ;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(or (fboundp 'defalias)
+    ;; poor man's defalias
+    (defun defalias (sym newdef)
+      "Set SYMBOL's function definition to NEWVAL, and return NEWVAL.
+Associates the function with the current load file, if any."
+      (fset sym (symbol-function newdef))))
+
+(or (fboundp 'selected-frame)
+    (defalias 'selected-frame 'selected-screen))
+
+(if (fboundp 'locate-window-from-coordinates)
+    ;; Older versions of XEmacs need a more robust version of 'event-window'
+    (defun fume-event-window (event)
+      (or (event-window event)
+          (locate-window-from-coordinates
+           (selected-frame) (list (event-x event) (event-y event)))
+          (locate-window-from-coordinates
+           (selected-frame) (list (event-x event) (1- (event-y event))))))
+  ;; In post 19.11 versions of XEmacs 'event-window' now works acceptably
+  (defalias 'fume-event-window 'event-window))
+
+(or (fboundp 'shrink-window-if-larger-than-buffer)
+    ;; Win-Emacs doesn't have this goodie
+    (defun shrink-window-if-larger-than-buffer (&optional window reqd-height)
+      "Shrink WINDOW to the smallest no of lines needed to display its buffer,
+or to optional REQUIRED-HEIGHT if and only if that is larger. Does nothing if
+the buffer contains more lines than the present window height."
+      (interactive)
+      (let* ((OriginalWindow (selected-window))
+	     (TargetWindow (select-window (or window OriginalWindow))))
+	(or (one-window-p t)
+	    (and reqd-height (>= reqd-height (window-height)))
+	    (< (window-height) (1+ (count-lines (point-min) (point-max))))
+	    (let ((calc-reqd-height
+		   (if truncate-lines
+		       (1+ (count-lines (point-min) (point-max)))
+		     (save-excursion
+		       (let ((count 0)
+			     linew
+			     (windw (window-width)))
+			 (goto-char (point-min))
+			 (while (not (eobp))
+			   (setq linew (1+ (progn (end-of-line)
+						  (current-column)))
+				 count (+ count
+					  (/ linew windw)
+					  (min (% linew windw) 1)))
+			   (beginning-of-line 2))
+			 count)))))
+	      (setq reqd-height (1+ (max calc-reqd-height
+                                         (1- window-min-height)
+					 (or reqd-height 0))))
+	      (if (> (window-height) reqd-height)
+		  (let* (wc spare bonus share wins shrunkwins)
+		    (walk-windows
+		     '(lambda (w)
+			(select-window w)
+			(if (or (eq w TargetWindow)
+				(> (1+ (count-lines (point-min) (point-max)))
+				   (1- (window-height w))))
+			    (setq wins (cons w wins))
+			  (if (= (1+ (count-lines (point-min) (point-max)))
+				 (1- (window-height w)))
+			      (setq shrunkwins (cons w shrunkwins)))))
+		     'nomini)
+		    (setq wc (1- (length wins))
+			  spare (- (window-height TargetWindow) reqd-height)
+			  share (if (> wc 0) (/ spare wc))
+			  bonus (if (> wc 0) (% spare wc))
+			  shrunkwins (if (zerop wc) nil shrunkwins)
+			  wins (mapcar (function
+					(lambda (w)
+					  (cons w (list
+						   (if (eq w TargetWindow)
+						       reqd-height
+						     (+ (window-height w)
+							share
+							(if (zerop bonus)
+							    0
+							  (setq bonus
+								(1- bonus))
+							  1)))
+						   (window-start w)))))
+				       wins))
+		    (let (ok (trys 2))
+		      (while (and (not ok) (> trys 0))
+			(setq trys (1- trys))
+			(mapcar
+			 (function
+			  (lambda (info)
+			    (select-window (car info))
+                            (enlarge-window
+                             (- (car (cdr info)) (window-height)))))
+			 wins)
+			(setq ok t)
+			(mapcar
+			 (function
+			  (lambda (info)
+			    (setq ok
+				  (and ok
+				       (<= (abs (- (car (cdr info))
+						   (window-height
+						    (car info))))
+					   1)))))
+			 wins)))
+		    (mapcar
+		     (function
+		      (lambda (info)
+			(select-window (car info))
+			(if (eq (car info) TargetWindow)
+                            (shrink-window
+                             (- (window-height TargetWindow) reqd-height)))
+			(set-window-start (car info) (car (cdr (cdr info))))))
+		     wins)
+		    (mapcar
+		     (function
+		      (lambda (w)
+			(select-window w)
+			(if (< (1+ (count-lines (point-min) (point-max)))
+                               (1- (window-height w)))
+                            (shrink-window-if-larger-than-buffer))))
+		     shrunkwins)))))
+	(select-window OriginalWindow))))
+
+(defconst fume-modeline-buffer-identification
+  (if (boundp 'modeline-buffer-identification)
+      'modeline-buffer-identification
+    'mode-line-buffer-identification))
+
+(defconst fume-use-local-post-command-hook
+  (boundp 'local-post-command-hook))
+
+(cond ((fboundp 'add-submenu)
+       (defconst fume-add-submenu 'add-submenu)
+       (defun fume-munge-menu-args (menu-name submenu before)
+         (list nil (cons menu-name submenu) before)))
+      (t
+       (defconst fume-add-submenu 'add-menu)
+       (defun fume-munge-menu-args (menu-name submenu before)
+         (list nil menu-name submenu before))))
+
+(defun fume-add-submenu (menu-name submenu before)
+  (apply fume-add-submenu (fume-munge-menu-args menu-name submenu before)))
+
+(defconst fume-not-tty
+  (or (and (fboundp 'device-type) (not (eq 'tty (device-type))))
+      (and (symbol-value 'window-system) t))) ; obsolete test
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;  Customizable Variables  ;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar fume-auto-position-popup t
+  "*Set to nil if you don't want the menu to appear in the corner of the window
+in which case it will track the mouse position instead.")
+
+(fume-defvar-local fume-display-in-modeline-p t
+  "*Set to nil if you don't want the function name appearing in the modeline.
+If your modeline is already full, then you can set this variable to something
+besides nil or t and the current function will replace the normal
+modeline-buffer-identification
+
+Note, this is a buffer-local variable.")
+
+(defvar fume-buffer-name "*Function List*"
+  "Name of buffer used to list functions when fume-list-functions called")
+
+(fume-defvar-local
+ fume-menubar-menu-name "Functions"
+ "*Set this to the string you want to appear in the menubar")
+
+(defvar fume-menubar-menu-location "Buffers"
+  "*Set this nil if you want the menu to appear last on the menubar.
+Otherwise set this to the menu you want \"Functions\" to appear in front of.")
+
+(defvar fume-max-items 24
+  "*Maximum number of elements in a function (sub)menu.")
+
+(defvar fume-fn-window-position 3
+  "*Number of lines from top of window at which to show function.
+If nil, display function start from the centre of the window.")
+
+(defvar fume-index-method 3
+  "*Set this to the method number you want used.
+
+Methods currently supported:
+0 = if you want submenu names to be numbered
+1 = if you want submenu range indicated by first character
+2 = if you want submenu range indicated by first 12 characters
+3 = if you want submenu range indicated by as many characters as needed")
+
+(defvar fume-scanning-message "Scanning buffer... (%3d%%)"
+  "*Set to nil if you don't want progress messages during manual scanning
+of the buffer.")
+
+(defvar fume-rescanning-message nil
+  "*Set to non-nil if you want progress messages during automatic scanning
+of the buffer. For example \"Re-Scanning buffer...\"")
+
+(defvar fume-rescan-trigger-counter-buffer-size 10000
+  "Used to tune the frequency of automatic checks on the buffer.
+The function fume-rescan-buffer-trigger only works whenever the value of the
+variable fume-rescan-trigger-counter reaches zero, whereupon it gets reset to
+buffer-size/fume-rescan-trigger-counter-buffer-size.")
+
+(fume-defvar-local
+ fume-sort-function 'fume-sort-by-name
+ "*The function to use for sorting the function menu.
+
+Set this to nil if you don't want any sorting (faster).
+The items in the menu are then presented in the order they were found
+in the buffer.
+
+The function should take two arguments and return T if the first
+element should come before the second.  The arguments are cons cells;
+(NAME . POSITION).  Look at 'fume-sort-by-name' for an example.")
+
+(fume-defvar-local
+ fume-rescan-buffer-hook nil
+ "*Buffer local hook to call at the end of each buffer rescan")
+
+;;; This hook is provided for outl-mouse and must not be made buffer local as
+;;; this appears to break outl-mouse for some reason.
+;;;
+(defvar fume-found-function-hook nil
+  "*Hook to call after every function match.")
+
+;;; Idea for jumping directly with a mouse click
+;;; Marc Paquette <Marc.Paquette@Softimage.COM>
+;;;
+(defvar fume-no-prompt-on-valid-default nil
+  "*Set non-nil if 'fume-prompt-function-goto' should jump without prompting
+when a valid default exists.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;  Buffer local variables  ;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(fume-defvar-local
+ fume-auto-rescan-buffer-p t
+ "Buffer local variable which if non-nil permits automatic buffer rescanning
+by func-menu.
+
+Usage:
+By default, fume-auto-rescan-buffer-p is set to non-nil. If you feel that
+a given mode 'foo' is becoming too slow as a result of automatic rescanning
+by func-menu, then do something along the lines of the following:
+
+   (defun remove-func-menu-auto-rescan ()
+      (setq fume-auto-rescan-buffer-p nil))
+
+   (add-hook 'foo-mode-hook 'remove-func-menu-auto-rescan)")
+
+(fume-defvar-local
+ fume-funclist nil
+ "The latest list of function names in the buffer")
+
+(fume-defvar-local
+ fume-function-name-regexp nil
+ "The keywords to show in a menu")
+
+(fume-defvar-local
+ fume-find-next-function-name-method nil
+ "The function to use to find the next function name in the buffer")
+
+(fume-defvar-local
+ fume-modeline-funclist nil
+ "The latest list of function names in the buffer to display in the modeline")
+
+(fume-defvar-local
+ fume-funclist-dirty-p nil
+ "Flags whether the buffer is in need of a fresh scan")
+
+(fume-defvar-local
+ fume-rescan-inhibit-p nil
+ "Internal variable only. DO NOT TOUCH.")
+
+(fume-defvar-local
+ fume-rescan-trigger-counter 0
+ "Used in large buffers to optimise checking frequency")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;  Mode specific regexp's and hooks  ;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Every fume-function-name-regexp-<language> should uniquely identify a
+;;; function for that certain language.
+
+;;; Lisp
+;;;
+;;; Jack Repenning <jackr@step7.informix.com>
+;;; Cedric Beust <Cedric.Beust@sophia.inria.fr>
+(defvar fume-function-name-regexp-lisp
+  (concat
+   "\\(^(defun+\\s-*[#:?A-Za-z0-9_+->]+\\s-*(\\)"
+   "\\|"
+   "\\(^(defsubst+\\s-*[#:?A-Za-z0-9_+->]+\\s-*(\\)"
+   "\\|"
+   "\\(^(defmacro+\\s-*[#:?A-Za-z0-9_+->]+\\s-*(\\)"
+   "\\|"
+   "\\(^(defadvice+\\s-*[#:?A-Za-z0-9_+->]+\\s-*(\\)"
+   "\\|"
+   "\\(^(de+\\s-*[#:?A-Za-z0-9_+->]+\\s-*(\\)"
+   "\\|"
+   "\\(^(dmd+\\s-*[#:?A-Za-z0-9_+->]+\\s-*(\\)"
+   )
+  "Expression to get lisp function names")
+
+;;; C
+;;;
+;;; Danny Bar-Dov <danny@acet02.amil.co.il>
+(defvar fume-function-name-regexp-c
+  (concat
+   "^[a-zA-Z0-9]+\\s-?"                ; type specs; there can be no
+   "\\([a-zA-Z0-9_*]+\\s-+\\)?"        ; more than 3 tokens, right?
+   "\\([a-zA-Z0-9_*]+\\s-+\\)?"
+   "\\([*&]+\\s-*\\)?"                 ; pointer
+   "\\([a-zA-Z0-9_*]+\\)[ \t\n]*("     ; name
+   )
+  "Expression to get C function names")
+
+;;; C++
+;;;
+;;; Andy Piper      <ajp@eng.cam.ac.uk>
+;;; Kevin R. Powell <powell@csl.ncsa.uiuc.edu>
+;;; Mats Lidell     <mats.lidell@eua.ericsson.se>
+;;; Mike Battaglia  <mbattagl@spd.dsccc.com>
+;;; Oliver Schittko <schittko@fokus.gmd.de>
+;;; Tom Murray      <tmurray@hpindck.cup.hp.com>
+(defvar fume-function-name-regexp-c++
+  (cons
+   (concat
+    "^\\(template\\s +<[^>]+>\\s +\\)?"          ; template formals
+    "\\([a-zA-Z0-9_*&<,>:]+\\s-+\\)?"            ; type specs; there can be no
+    "\\([a-zA-Z0-9_*&<,>\"]+\\s-+\\)?"           ; more than 3 tokens, right?
+    "\\([a-zA-Z0-9_*&<,>]+\\s-+\\)?"
+    "\\(\\([a-zA-Z0-9_&~:<,>*]\\|\\(\\s +::\\s +\\)\\)+\\)"
+    "\\(o?perator\\s *.[^(]*\\)?\\(\\s-\\|\n\\)*(" ; name
+    ) 5)
+  "Expression to get C++ function names")
+
+;;; FORTRAN
+;;;
+;;; Paul Emsley <paule@chem.gla.ac.uk>
+;;; Raymond L. Toy <toy@soho.crd.ge.com>
+;;; Richard Cognot <cognot@elfgrc.co.uk>
+;;; Greg Sjaardema <gdsjaar@sandia.gov>
+(defvar fume-function-name-regexp-fortran
+  (concat
+   ;; >= six spaces
+   "^      \\s-*"
+   ;; type specs
+   "+[a-zA-Z0-9*]*\\s-*"
+   ;; continuation lines
+   "\\(\n     [^ 0]\\s-*\\)*"
+   ;; function or subroutine
+   "\\(entry\\|ENTRY\\|function\\|FUNCTION\\|subroutine\\|SUBROUTINE\\)\\s-*"
+   ;; continuation lines
+   "\\(\n     [^ 0]\\s-*\\)*"
+   )
+  "Expression to get Fortran 77 function and subroutine names")
+
+;;; John Turner <turner@xdiv.lanl.gov>
+(defvar fume-function-name-regexp-fortran90
+  (concat
+   ;; type specs
+   "+[a-zA-Z0-9*]*\\s-*"
+   ;; function or subroutine
+   "\\(entry\\|ENTRY\\|function\\|FUNCTION\\|module\\|MODULE\\|subroutine\\|SUBROUTINE\\)\\s-*"
+   )
+  "Expression to get Fortran 90 function, module and subroutine names")
+
+;;; Modula
+(defvar fume-function-name-regexp-modula
+  "^\\s-*PROCEDURE\\s-+[A-Za-z0-9_-]+"
+  "Expression to get Modula function names")
+
+;;; Bacis2
+;;;
+;;; CV MEDUSA's 4th generation language
+(defvar fume-function-name-regexp-bacis
+  "module_define(!\\|define_constant(!\\|sys_sysdefine(!\\|<<dbgid +\\s-*"
+  "Expression to get Bacis2 function names")
+
+;;; Maple
+;;;
+;;; Luc Tancredi <Luc.Tancredi@sophia.inria.fr>
+(defvar fume-function-name-regexp-maple
+  "^[ \t]*[a-zA-Z0-9_]+[ \t]*:=[ \t]*proc[ \t]*("
+  "Expression to get maple function/procedure names")
+
+;;; Tcl
+;;;
+;;; Andy Piper <ajp@eng.cam.ac.uk>
+;;; Jean-Michel Augusto <augusto@eureecom.fr>
+;;; Dr P.G. Sjoerdsma <pgs1002@esc.cam.ac.uk>
+(defvar fume-function-name-regexp-tcl
+  (cons "^\\s *proc\\s +\\(\\S-+\\)\\s *{" 1)
+  "Expression to get Tcl function Names")
+
+;;; Java
+;;;
+;;; Heddy Boubaker <boubaker@dgac.fr>
+(defvar fume-function-name-regexp-java
+  "\\s-+\\([A-Za-z_][A-Za-z0-9_]+\\)[\n \t\r]*\\((\\)"
+  "Expression to get Java methods names")
+
+;;; Perl
+;;;
+;;; Alex Rezinsky <alexr@msil.sps.mot.com>
+;;; Michael Lamoureux <lamour@engin.umich.edu>
+(defvar fume-function-name-regexp-perl "^sub[ \t]+\\([A-Za-z0-9_]+\\)"
+  "Expression to get Perl function Names")
+
+;;; Python support
+;;; Shuichi Koga <skoga@virginia.edu>
+;;;
+(defvar fume-function-name-regexp-python
+  "^\\s-*\\(class\\|def\\)+\\s-*\\([A-Za-z0-9_]+\\)\\s-*[(:]"
+  "Expression to get Python class and function names")
+
+;;; Postscript
+;;;
+;;; Leigh L. Klotz <klotz@adoc.xerox.com>
+(defvar fume-function-name-regexp-postscript
+  "^/[^][ \t{}<>]*"
+  "Expression to get postscript function names")
+
+;;; Prolog
+;;;
+;;; Laszlo Teleki <laszlo@ipb.uni-bonn.de>
+(defvar fume-function-name-regexp-prolog
+  "^[a-z][a-zA-Z0-9_]+"
+  "Expression to get prolog fact and clause names")
+
+;;; Ehdm
+;;;
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+(defvar fume-function-name-regexp-ehdm
+  (concat
+   "[A-Za-z0-9_]*:[ ]*"
+   "\\([Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]\\|"
+   "[Ll][Ee][Mm][Mm][Aa]\\|"
+   "[Aa][Xx][Ii][Oo][Mm]\\|"
+   "[Pp][Rr][Oo][Vv][Ee]\\|"
+   "[Tt][Hh][Ee][Oo][Rr][Ee][Mm]"
+   "\\)"
+   )
+  "*Expression to get Ehdm function, theorems, axioms, lemmas, and proofs.")
+
+;;; PVS
+;;;
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+(defvar fume-function-name-regexp-pvs
+  (concat
+   "\\([A-Za-z0-9_]*:[ ]*"
+   "\\([Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]\\|"
+   "[Ll][Ee][Mm][Mm][Aa]\\|"
+   "[Aa][Xx][Ii][Oo][Mm]\\|"
+   "[Tt][Hh][Ee][Oo][Rr][Ee][Mm]\\|"
+   "[Ff][Or][Rr][Mm][Uu][La][Aa]"
+   "\\|"
+   "\\[.*\\]"
+   "\\)\\)\\|"
+   "[A-Za-z0-9_]*(.*)[ ]*:"
+   )
+  "*Expression to get PVS functions, theorems, axioms, lemmas")
+
+;;; Tex, LaTex
+;;;
+;;; Philippe Queinnec <queinnec@cenatls.cena.dgac.fr>
+;;; Paolo Frasconi <paolo@mcculloch.ing.unifi.it>
+(fume-defvar-local fume-tex-chapter 0)
+(fume-defvar-local fume-tex-section 0)
+(fume-defvar-local fume-tex-subsection 0)
+(fume-defvar-local fume-tex-subsubsection 0)
+
+(defun fume-tex-rescan-buffer-hook ()
+  (setq fume-tex-chapter 0
+        fume-tex-section 0
+        fume-tex-subsection 0
+        fume-tex-subsubsection 0))
+
+(defun fume-tweak-tex-mode ()
+  (setq fume-sort-function nil)
+  (add-hook 'fume-rescan-buffer-hook 'fume-tex-rescan-buffer-hook))
+
+(add-hook 'tex-mode-hook 'fume-tweak-tex-mode)
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+(add-hook 'TeX-mode-hook 'fume-tweak-tex-mode)
+;;; Wolfgang Mettbach <wolle@uni-paderborn.de>
+(add-hook 'latex-mode-hook 'fume-tweak-tex-mode)
+(add-hook 'LaTeX-mode-hook 'fume-tweak-tex-mode)
+
+;;; Philippe Queinnec <queinnec@cenatls.cena.dgac.fr>
+(defvar fume-section-name-regexp-latex
+  (concat
+   "^\\s-*\\\\\\("
+   "\\(sub\\)*section\\|chapter\\)"
+   "\\*?\\(\\[[^]]*\\]\\)?{\\([^}]*\\)}"
+   )
+  "Expression to get latex section names")
+
+;;; ksh
+;;;
+;;; Philippe Bondono <bondono@vnet.ibm.com>
+(defvar fume-function-name-regexp-ksh
+  (concat
+   "\\(^\\s-*function\\s-+[A-Za-z_][A-Za-z_0-9]*\\)"
+   "\\|"
+   "\\(^\\s-*[A-Za-z_][A-Za-z_0-9]*\\s-*()\\)")
+  "Expression to get ksh function names")
+
+;;; Scheme
+;;;
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+(defvar fume-function-name-regexp-scheme
+  "^(define [ ]*"
+  "Expression to get Scheme function names")
+
+;;; BibTeX
+;;;
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+(defvar fume-function-name-regexp-bibtex
+  ;; "^@[A-Za-z]*[({]\\([A-Za-z0-9:;&-]*\\),"
+  ;; Christoph Wedler <wedler@fmi.uni-passau.de>
+  ;; According to the LaTeX Companion, this should be
+  "^@[A-Za-z]*[({]\\([A-Za-z][^ \t\n\"#%'()={}]*\\),"
+  "Expression to get bibtex citation headers.")
+
+;;; SGML
+;;;
+;;; Thomas Plass <thomas.plass@mid-heidelberg.de>
+(defvar fume-function-name-regexp-sgml
+  "<!\\(element\\|entity\\)[ \t\n]+%?[ \t\n]*\\([A-Za-z][-A-Za-z.0-9]*\\)"
+  "Expression to find declaration of SGML element or entity")
+
+;;; Ada
+;;;
+;;; Michael Polo <mikep@polo.mn.org> <mikep@cfsmo.honeywell.com>
+(defvar fume-function-name-regexp-ada
+  (cons "^[ \t]*\\(procedure\\|PROCEDURE\\|function\\|FUNCTION\\)[ \n\t]+\\([a-zA-Z0-9_]+\\|\"[^\"]\"\\)" 2)
+  "Expression to find declaration of Ada function")
+
+;;; ignore prototypes, 'renames', 'is new' to eliminate clutter
+;;;
+;;; Scott Evans <gse@ocsystems.com>
+(defvar fume-function-name-regexp-ada-ignore
+  "[ \n\t]*\\(([^()]+)[ \n\t]*\\)?\\(return[ \t\n]+[^ \t\n;]+[ \n\t]*\\)?\\(;\\|is[ \n\t]+new[ \n\t]\\|renames\\)"
+  "ignore if ada function name matches this string")
+
+;;; Makefiles
+;;;
+;;; Paul Filipski & Anthony Girardin <{filipski,girardin}@blackhawk.com>
+(defvar fume-function-name-regexp-make
+  "^\\(\\(\\$\\s(\\)?\\(\\w\\|\\.\\)+\\(:sh\\)?\\(\\s)\\)?\\)\\s *\\(::?\\|\\+?=\\)"
+  "Expression to get makefile target names")
+
+;;; Directory Listings
+;;;
+;;; Norbert Kiesel <norbert@i3.informatik.rwth-aachen.de>
+;;; regexp stolen from font-lock-mode
+(defvar fume-function-name-regexp-dired
+  "^. +d.*\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\) +[0-9]+ +[0-9:]+ \\(.*\\)$"
+  "Expression to get directory names")
+
+;;; Pascal
+;;;
+;;; Espen Skoglund <espensk@stud.cs.uit.no>
+(defvar fume-function-name-regexp-pascal
+  "^\\(function\\|procedure\\)[ \t]+\\([_a-zA-Z][_a-zA-Z0-9]*\\)"
+  "Expression to get function/procedure names in pascal.")
+
+
+;;; Fame
+;;;
+;;; Cooper Vertz <cooper@prod2.imsi.com>
+(defvar fume-function-name-regexp-fame
+  "^\\(function\\|procedure\\)[ \t]+\\([#\\$%_a-zA-Z][#\\$%_a-zA-Z0-9]*\\)"
+  "Expression to get function/procedure names in fame.")
+
+
+;;; Verilog
+;;;
+;;; Matt Sale <mdsale@icdc.delcoelect.com>
+(defvar fume-function-name-regexp-verilog
+  "^\\(task\\|function\\|module\\|primitive\\)[ \t]+\\([A-Za-z0-9_+-]*\\)[ \t]*(?"
+  "Expression to get verilog module names")
+
+
+;;; Assembly
+(defvar fume-function-name-regexp-asm
+  "^\\([a-zA-Z_.$][a-zA-Z0-9_.$]*\\)[ \t]*:"
+  "Expression to get assembly label names")
+
+;;; This is where the mode specific regexp's are hooked in
+;;;
+(defvar fume-function-name-regexp-alist
+  '(;; Lisp
+    (emacs-lisp-mode              . fume-function-name-regexp-lisp)
+    (common-lisp-mode             . fume-function-name-regexp-lisp)
+    (fi:common-lisp-mode          . fume-function-name-regexp-lisp)
+    (fi:emacs-lisp-mode           . fume-function-name-regexp-lisp)
+    (fi:franz-lisp-mode           . fume-function-name-regexp-lisp)
+    (fi:inferior-common-lisp-mode . fume-function-name-regexp-lisp)
+    (fi:inferior-franz-lisp-mode  . fume-function-name-regexp-lisp)
+    (fi:lisp-listener-mode        . fume-function-name-regexp-lisp)
+    (lisp-mode                    . fume-function-name-regexp-lisp)
+    (lisp-interaction-mode        . fume-function-name-regexp-lisp)
+
+    ;; C
+    (c-mode      . fume-function-name-regexp-c)
+    (elec-c-mode . fume-function-name-regexp-c)
+    (c++-c-mode  . fume-function-name-regexp-c)
+
+    ;; C++
+    (c++-mode . fume-function-name-regexp-c++)
+
+    ;; Fortran
+    (fortran-mode . fume-function-name-regexp-fortran)
+    (f90-mode     . fume-function-name-regexp-fortran90)
+
+    ;; Modula
+    (modula-2-mode . fume-function-name-regexp-modula)
+    (modula-3-mode . fume-function-name-regexp-modula)
+
+    ;; Bacis2
+    (bacis-mode . fume-function-name-regexp-bacis)
+
+    ;; Maple
+    (maple-mode . fume-function-name-regexp-maple)
+
+    ;; Perl
+    (perl-mode . fume-function-name-regexp-perl)
+
+    ;; Java
+    (java-mode . fume-function-name-regexp-java)
+
+    ;; Python
+    (alice-mode  . fume-function-name-regexp-python)
+    (python-mode . fume-function-name-regexp-python)
+
+    ;; Postscript
+    (postscript-mode . fume-function-name-regexp-postscript)
+
+    ;; Prolog
+    (prolog-mode . fume-function-name-regexp-prolog)
+
+    ;; Tcl
+    (tcl-mode . fume-function-name-regexp-tcl)
+
+    ;; ksh
+    (ksh-mode . fume-function-name-regexp-ksh)
+
+    ;; LaTeX
+    (latex-mode . fume-section-name-regexp-latex)
+    (LaTeX-mode . fume-section-name-regexp-latex)
+
+    ;; Scheme
+    (scheme-mode . fume-function-name-regexp-scheme)
+
+    ;; BibTeX
+    (bibtex-mode . fume-function-name-regexp-bibtex)
+
+    ;; Ehdm & PVS
+    (ehdm-mode . fume-function-name-regexp-ehdm)
+    (pvs-mode  . fume-function-name-regexp-pvs)
+
+    ;; SGML
+    (sgml-mode . fume-function-name-regexp-sgml)
+
+    ;; Ada
+    (ada-mode . fume-function-name-regexp-ada)
+
+    ;; Makefiles
+    (makefile-mode . fume-function-name-regexp-make)
+
+    ;; Dired
+    (dired-mode . fume-function-name-regexp-dired)
+
+    ;; Pascal
+    (pascal-mode . fume-function-name-regexp-pascal)
+
+    ;; Fame
+    (fame-mode . fume-function-name-regexp-fame)
+
+    ;; Verilog
+    (verilog-mode . fume-function-name-regexp-verilog)
+
+    ;; Assembly
+    (asm-mode . fume-function-name-regexp-asm)
+    )
+
+  "The connection between a mode and the regexp that matches function names.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;  Mode specific finding functions  ;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Default routine : Note, most modes will need a specialised routine
+;;;
+(defun fume-find-next-function-name (buffer)
+  "Searches for the next function in BUFFER."
+  (set-buffer buffer)
+  ;; Search for the function
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((char (progn
+                    (backward-up-list 1)
+                    (save-excursion
+                      (goto-char (scan-sexps (point) 1))
+                      (skip-chars-forward "[ \t\n]")
+                      (following-char)))))
+        ;; Skip this function name if it is a prototype declaration.
+        (if (and (eq char ?\;) (not (eq major-mode 'emacs-lisp-mode)))
+            (fume-find-next-function-name buffer)
+          ;; Get the function name and position
+          (let (beg)
+            (forward-sexp -1)
+            (setq beg (point))
+            (forward-sexp)
+            (cons (buffer-substring beg (point)) beg))))))
+
+;;; General purpose sexp find function
+;;;
+(defun fume-find-next-sexp (buffer)
+  "Searches for the next sexp type function in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (save-excursion (forward-sexp -1) (point))))
+        (cons (buffer-substring beg (point)) beg))))
+
+;;; Specialised routine to get the next ehdm entity in the buffer.
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+;;;
+(defun fume-find-next-ehdm-entity (buffer)
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (match-beginning 0))
+            (end (match-end 0)))
+        (cons (buffer-substring beg end) beg))))
+
+;;; Specialised routine to get the next PVS entity in the buffer.
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+;;;
+(defun fume-find-next-pvs-entity (buffer)
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (match-beginning 0))
+            (end (match-end 0)))
+        (goto-char (1- end))
+        (if (looking-at ":")
+            (setq end (1- end)))
+        (cons (buffer-substring beg end) beg))))
+
+;;; Specialised routine to get the next C function name in the buffer.
+;;;
+(defun fume-find-next-c-function-name (buffer)
+  "Searches for the next C function in BUFFER."
+  (set-buffer buffer)
+  ;; Search for the function
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((char (progn
+                    (backward-up-list 1)
+                    (save-excursion
+                      (goto-char (scan-sexps (point) 1))
+                      (skip-chars-forward "[ \t\n]")
+                      (following-char)))))
+        ;; Skip this function name if it is a prototype declaration.
+        (if (eq char ?\;)
+            (fume-find-next-function-name buffer)
+          (let (beg
+                name)
+            ;; Get the function name and position
+            (forward-sexp -1)
+            (setq beg (point))
+            (forward-sexp)
+            (setq name (buffer-substring beg (point)))
+            ;; ghastly crock for DEFUN declarations
+            (cond ((string-match "^DEFUN\\s-*" name)
+                   (forward-word 1)
+                   (forward-word -1)
+                   (setq beg (point))
+                   (cond ((re-search-forward "\"," nil t)
+                          (re-search-backward "\"," nil t)
+                          (setq name
+                                (format "%s %s"
+                                        name
+                                        (buffer-substring beg (point))))))))
+            ;; kludge to avoid 'void' in menu
+            (if (string-match "^void\\s-*" name)
+                (fume-find-next-function-name buffer)
+              (cons name beg)))))))
+
+(defun fume-cc-inside-comment ()
+  (let ((here (point))
+        (bol-point (save-excursion (beginning-of-line) (point))))
+    (or
+     (save-excursion (and (re-search-backward "\/\/" bol-point t 1) t))
+     (save-excursion
+       (and
+        (re-search-backward "\\(/[*]\\)\\|\\([*]/\\)" (point-min) t 1)
+        (looking-at "/[*]")
+        (goto-char here)
+        (or (beginning-of-line 1) t)
+        (re-search-forward "[ \t]*/?[*][ \t]*" here t 1)
+        t)))))
+
+;;; <jrm@odi.com>
+;;; <ajp@eng.cam.ac.uk>
+;;; <schittko@fokus.gmd.de>
+;;;
+(defun fume-match-find-next-function-name (buffer)
+  "General next function name in BUFFER finder using match.
+The regexp is assumed to be a two item list the car of which is the regexp to
+use, and the cdr of which is the match position of the function name."
+  (set-buffer buffer)
+  (let ((result nil)
+        (continue t)
+        (regexp (car fume-function-name-regexp)))
+    (while continue
+      ;; Search for the function
+      (if (re-search-forward regexp nil t)
+          (if (fume-cc-inside-comment)
+              () ; skip spurious finds in comments
+            (let ((first-token (save-excursion
+                                 (re-search-backward regexp nil t)
+                                 (prog1 (fume-what-looking-at)
+                                   (re-search-forward regexp nil t))))
+                  (last-char (progn
+                               (backward-up-list 1)
+                               (save-excursion
+                                 (goto-char (scan-sexps (point) 1))
+                                 (following-char)))))
+              ;; Skip function name if it's a prototype or typedef declaration
+              (if (or (eq last-char ?\;) (string= first-token "typedef"))
+                  nil
+                (setq result
+                      ;; Get function name and position including scope
+                      (cons (buffer-substring
+                             (match-beginning (cdr fume-function-name-regexp))
+                             (point))
+                            (match-beginning (cdr fume-function-name-regexp)))
+                      continue nil))))
+        (setq continue nil)))
+    result))
+
+;;; Specialised routine to find the next Perl function
+;;;
+(defun fume-find-next-perl-function-name (buffer)
+  "Searches for the next Perl function in BUFFER."
+  (fume-find-next-sexp buffer))
+
+;;; Specialised routine to find the next Java function
+;;; Heddy Boubaker <boubaker@dgac.fr>
+;;;
+(defun fume-find-next-java-function-name (buffer)
+  "Searches for the next Java function in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (match-beginning 1))
+            (end (match-end       1)))
+        (goto-char (match-beginning 2))
+        (forward-sexp)
+        (if (and (looking-at "[^;(]*{")
+                 (not (fume-cc-inside-comment)))
+            ;; This is a method definition and we're not
+            ;; in a comment.
+            (let ((str (buffer-substring beg end)))
+              (or (string-match "if\\|switch\\|catch\\|for\\|while" str)
+                  ;; These constructs look like methods definitions
+                  ;; but are not.
+                  (cons str beg)))
+          (fume-find-next-java-function-name buffer)))))
+
+;;; Specialised routine to find the next Python function
+;;; Shuichi Koga <skoga@virginia.edu>
+;;;
+(defun fume-find-next-python-function-name (buffer)
+  "Searches for the next python function in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (save-excursion
+        (let* ((retpnt (match-beginning 2))
+               (retname (buffer-substring retpnt (match-end 2))))
+          (goto-char (match-beginning 0))
+          (cond ((looking-at "\\s-+def")
+                 (re-search-backward
+                  "^class\\s-*\\([A-Za-z0-9_]+\\)\\s-*[(:]" nil t)
+                 (setq retname
+                       (concat
+                        (buffer-substring (match-beginning 1) (match-end 1))
+                        "."
+                        retname))))
+          (cons retname retpnt)))))
+
+;;; Specialised routine to find the next Modula function or subroutine.
+;;;
+(defun fume-find-next-modula-function-name (buffer)
+  "Searches for the next modula function in BUFFER."
+  (fume-find-next-sexp buffer))
+
+;;; Specialised routine to find the next directory.
+;;; Norbert Kiesel <norbert@i3.informatik.rwth-aachen.de>
+;;;
+(defun fume-find-next-directory-name (buffer)
+  "Searches for the next directory in dired BUFFER."
+  (set-buffer buffer)
+  ;; Search for the function
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (match-beginning 2))
+            (end (match-end 2)))
+        (cons (buffer-substring beg end) beg))))
+
+;;; Specialised routine to find the next Fortran function or subroutine
+;;;
+(defun fume-find-next-fortran-function-name (buffer)
+  "Searches for the next Fortran function in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((pos (point))
+            ;; name may have "_" but must start with a letter
+            (name-regexp "\\s-+[a-zA-Z]+[_a-zA-Z0-9*]*")
+            (eol (save-excursion (end-of-line 1) (point))))
+        (skip-chars-backward " \t")
+        (if (re-search-forward name-regexp eol t)
+            ;; name is ok; so return it
+            (cons (buffer-substring pos (point)) pos)
+          ;; rubbish found; skip to next function
+          (fume-find-next-fortran-function-name buffer)))))
+
+;;; Specialised routine to get the next postscript function name in the buffer
+;;; Leigh L. Klotz <klotz@adoc.xerox.com>
+;;;
+(defun fume-find-next-postscript-function-name (buffer)
+  "Searches for the next postscript function in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (progn (beginning-of-line 1) (point))))
+        (forward-sexp)
+        ;; keep including sexps as long as they
+        ;; start with / or [.
+        (if (looking-at "\\s-+\\(/\\|\\[\\)")
+            (forward-sexp))
+        (cons (buffer-substring beg (point)) beg))))
+
+;;; Specialised routine to get the next prolog fact/clause name in the buffer
+;;; Laszlo Teleki <laszlo@ipb.uni-bonn.de>
+;;;
+(defun fume-find-next-prolog-function-name (buffer)
+  "Searches for the next prolog fact or clause in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (progn (beginning-of-line 1) (point))))
+        (forward-sexp)
+        (cons (buffer-substring beg (point)) beg))))
+
+;;; Specialised routine to get the next bacis2 procedure name in the buffer
+;;;
+(defun fume-find-next-bacis-function-name (buffer)
+  "Searches for the next Bacis2 function in BUFFER"
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((pos (point))
+            (name (condition-case ()
+                      (funcall
+                       (symbol-function (intern "focus-get-function-name")))
+                    (error nil))))
+        (if (null name)
+            (fume-find-next-bacis-function-name buffer)
+          ;; jump past possible function dbgid
+          (re-search-forward
+           (format "<<dbgid +\\s-*%s%s" name "\\s-*>>") nil t)
+          (cons name pos)))))
+
+;;; Specialized routine to get the next Maple function name in the buffer
+;;; Luc Tancredi <Luc.Tancredi@sophia.inria.fr>
+;;;
+(defun fume-find-next-maple-function-name (buffer)
+  "Searches for the next maple function in BUFFER"
+  (set-buffer buffer)
+  ;; Search for the function
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (progn (backward-up-list 1) (forward-sexp -2) (point))))
+        (forward-sexp)
+        (cons (buffer-substring beg (point)) beg))))
+
+;;; Specialised routine to get the next latex section name in the buffer
+;;; Philippe Queinnec <queinnec@cenatls.cena.dgac.fr>
+;;; Paolo Frasconi <paolo@mcculloch.ing.unifi.it>
+;;;
+(defun fume-find-next-latex-section-name (buffer)
+  "Searches for the next latex section in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let* ((secname (buffer-substring (match-beginning 1) (match-end 1)))
+             (beg (match-beginning 4))
+             (name (buffer-substring beg (match-end 4))))
+        (cond ((string= secname "chapter")
+               (setq fume-tex-chapter (1+ fume-tex-chapter)
+                     fume-tex-section 0
+                     fume-tex-subsection 0
+                     fume-tex-subsubsection 0
+                     name (concat fume-tex-chapter " " (upcase name))))
+              ((string= secname "section")
+               (setq fume-tex-section (1+ fume-tex-section)
+                     name (concat
+                           (if (> fume-tex-chapter 0)
+                               (concat fume-tex-chapter ".") "")
+                           fume-tex-section " " name)
+                     fume-tex-subsection 0
+                     fume-tex-subsubsection 0))
+              ((string= secname "subsection")
+               (setq fume-tex-subsection (1+ fume-tex-subsection)
+                     name (concat
+                           (if (> fume-tex-chapter 0)
+                               (concat fume-tex-chapter ".") "")
+                           fume-tex-section "."
+                           fume-tex-subsection " " name)
+                     fume-tex-subsubsection 0))
+              ((string= secname "subsubsection")
+               (setq fume-tex-subsubsection (1+ fume-tex-subsubsection)
+                     name (concat
+                           (if (> fume-tex-chapter 0)
+                               (concat fume-tex-chapter ".") "")
+                           fume-tex-section "."
+                           fume-tex-subsection "."
+                           fume-tex-subsubsection " " name)))
+              ((string= secname "subsubsection")
+               (setq name (concat "   " name))))
+        (cons name beg))))
+
+;;; Specialised routine to get the next ksh function in the buffer
+;;; Philippe Bondono <bondono@vnet.ibm.com>
+;;;
+(defun fume-find-next-ksh-function-name (buffer)
+  "Searches for the ksh type function in BUFFER."
+  (set-buffer buffer)
+  ;; Search for the function
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let (name
+            (beg (match-beginning 0)))
+        (cond ((re-search-backward "\\(^\\|\\s-\\)function\\s-" beg t)
+               (re-search-forward
+                "\\(function\\s-+\\)\\([A-Za-z_][A-Za-z_0-9]*\\)" nil t)
+               (setq beg (match-beginning 2)
+                     name (buffer-substring beg (match-end 2))))
+              (t
+               (re-search-backward
+                "\\(^\\|\\s-\\)\\([A-Za-z_][A-Za-z_0-9]*\\)" beg t)
+               (setq beg (match-beginning 2)
+                     name (buffer-substring beg (match-end 2)))))
+        (if (null name)
+            (fume-find-next-ksh-function-name buffer)
+          (end-of-line)
+          (cons name beg)))))
+
+;;; Specialised routine to get the next Scheme function in the buffer
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+;;;
+(defun fume-find-next-scheme-function (buffer)
+  "Searches for the next Scheme function in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (progn (if (looking-at "(") (forward-char 1)) (point)))
+            (end (save-excursion (forward-sexp) (point))))
+        (cons (buffer-substring beg end) beg))))
+
+;;; Specialised routine to get the next BibTeX citation in the buffer
+;;; C. Michael Holloway <c.m.holloway@larc.nasa.gov>
+;;;
+(defun fume-find-next-bibtex-citation (buffer)
+  "Searches for the next BibTeX citation in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (match-beginning 1))
+            (end (match-end 1)))
+        (cons (buffer-substring beg end) beg))))
+
+;;; Specialised routine to get the next SGML declaration in the buffer
+;;; Thomas Plass <thomas.plass@mid-heidelberg.de>
+;;;
+(defun fume-find-next-sgml-element-name (buffer)
+  "Searches for the next SGML declaration in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((type (buffer-substring (match-beginning 1) (match-end 1)))
+            (beg (match-beginning 2))
+            (name (buffer-substring (match-beginning 2) (match-end 2))))
+        (if (string= (downcase type) "element")
+            (setq name (format "%-17s%3s" name "EL"))
+          (setq name (format "%-17s%3s" name "ENT")))
+        (cons name beg))))
+
+;;; Specialised routine to get the next ada function in the buffer
+;;; Michael Polo <mikep@polo.mn.org> <mikep@cfsmo.honeywell.com>
+;;;
+(defun fume-find-next-ada-function-name (buffer)
+  "Searches for the next ada function in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward (car fume-function-name-regexp-ada) nil t)
+      (let ((beg (match-beginning (cdr fume-function-name-regexp-ada)))
+            (end (match-end (cdr fume-function-name-regexp-ada))))
+
+        (if (looking-at fume-function-name-regexp-ada-ignore)
+            (fume-find-next-ada-function-name buffer)
+          (cons (buffer-substring beg end) beg)))))
+
+;;; Makefiles
+;;; Paul Filipski & Anthony Girardin <{filipski,girardin}@blackhawk.com>
+;;;
+(defun fume-find-next-function-name-make (buffer)
+  "Searches for the next make item in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (match-beginning 1))
+            (end (match-end 1)))
+        (cons (buffer-substring beg end) beg))))
+
+;;; Find next pascal function in the buffer
+;;; Espen Skoglund <espensk@stud.cs.uit.no>
+;;;
+(defun fume-find-next-pascal-function-name (buffer)
+  "Searches for the next pascal procedure in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (match-beginning 2))
+            (end (match-end 2)))
+        (cons (buffer-substring beg end) beg))))
+
+;;; Verilog support
+;;; Matt Sale <mdsale@icdc.delcoelect.com>
+;;;
+(defun fume-find-next-verilog-function-name (buffer)
+  "Searches for the next verilog module in BUFFER."
+  (set-buffer buffer)
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (let ((beg (match-beginning 2))
+            (end (match-end 2)))
+        (cons (buffer-substring beg end) beg))))
+
+;;; Assembly
+;;; Bob Weiner <weiner@mot.com>
+;;;
+(defun fume-find-next-asm-function-name (buffer)
+  "Searches for the next assembler function in BUFFER."
+  (set-buffer buffer)
+  ;; Search for the function
+  (if (re-search-forward fume-function-name-regexp nil t)
+      (cons (buffer-substring (match-beginning 1) (match-end 1))
+            (match-beginning 1))))
+
+;;; This is where you can hook in other languages which may need a different
+;;; method to scan for function names. Otherwise, the default defun used is
+;;; fume-find-next-function-name which is suitable for sexp-based languages
+;;; such as C, C++ and elisp.
+;;;
+(defconst fume-find-function-name-method-alist
+  '((ada-mode        . fume-find-next-ada-function-name)
+    (alice-mode      . fume-find-next-python-function-name)
+    (asm-mode        . fume-find-next-asm-function-name)
+    (bacis-mode      . fume-find-next-bacis-function-name)
+    (bibtex-mode     . fume-find-next-bibtex-citation)
+    (c++-mode        . fume-match-find-next-function-name)
+    (c-mode          . fume-find-next-c-function-name)
+    (dired-mode      . fume-find-next-directory-name)
+    (ehdm-mode       . fume-find-next-ehdm-entity)
+    (fame-mode       . fume-find-next-pascal-function-name)
+    (fortran-mode    . fume-find-next-fortran-function-name)
+    (f90-mode        . fume-find-next-fortran-function-name)
+    (ksh-mode        . fume-find-next-ksh-function-name)
+    (latex-mode      . fume-find-next-latex-section-name)
+    (LaTeX-mode      . fume-find-next-latex-section-name)
+    (makefile-mode   . fume-find-next-function-name-make)
+    (maple-mode      . fume-find-next-maple-function-name)
+    (modula-2-mode   . fume-find-next-modula-function-name)
+    (modula-3-mode   . fume-find-next-modula-function-name)
+    (pascal-mode     . fume-find-next-pascal-function-name)
+    (perl-mode       . fume-find-next-perl-function-name)
+    (java-mode       . fume-find-next-java-function-name)
+    (postscript-mode . fume-find-next-postscript-function-name)
+    (prolog-mode .     fume-find-next-prolog-function-name)
+    (pvs-mode        . fume-find-next-pvs-entity)
+    (python-mode     . fume-find-next-python-function-name)
+    (scheme-mode     . fume-find-next-scheme-function)
+    (sgml-mode       . fume-find-next-sgml-element-name)
+    (tcl-mode        . fume-match-find-next-function-name)
+    (verilog-mode    . fume-find-next-verilog-function-name)
+    )
+
+  "The connection between a mode and the defun that finds function names.
+If no connection is in this alist for a given mode, a default method is used")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;  General utility functions  ;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Routine to refresh the modeline
+;;;
+(if (fboundp 'redraw-modeline)          ; faster built-in method
+    (defalias 'fume-refresh-modeline 'redraw-modeline)
+  (defun fume-refresh-modeline ()       ; use old kludge method
+    (set-buffer-modified-p (buffer-modified-p))))
+
+;;; Smart mouse positioning
+;;;
+(if (fboundp 'window-edges)             ; old method
+    (defun fume-set-mouse-position ()
+      (set-mouse-position
+       (selected-frame)
+       (nth 0 (window-edges)) (nth 1 (window-edges))))
+  (defun fume-set-mouse-position ()     ; new method
+    (set-mouse-position
+     (selected-window)
+     (nth 0 (window-pixel-edges))
+     (nth 1 (window-pixel-edges)))))
+
+;;; Sets 'fume-function-name-regexp' to something appropriate for the current
+;;; mode for this buffer.
+;;;
+(defun fume-set-defaults ()
+  "Returns nil if unsuccessful in setting up buffer-local defaults.
+Otherwise returns fume-function-name-regexp"
+  (setq fume-function-name-regexp
+        (symbol-value
+         (cdr-safe (assoc major-mode fume-function-name-regexp-alist))))
+  (if fume-function-name-regexp
+      (setq fume-find-next-function-name-method
+            (or (cdr-safe (assoc major-mode
+                                 fume-find-function-name-method-alist))
+                'fume-find-next-function-name)))
+  fume-function-name-regexp)
+
+;;; Routines to add/remove/update function menu from menubar
+;;;
+(defsubst fume-add-menubar-entry ()
+  (interactive)
+  (save-window-excursion (function-menu t)))
+
+(defsubst fume-remove-menubar-entry ()
+  (interactive)
+  (cond ((and fume-running-xemacs current-menubar)
+         (delete-menu-item (list fume-menubar-menu-name))
+         ;; force update of the menubar
+         (fume-refresh-modeline))))
+
+(defsubst fume-update-menubar-entry ()
+  "Returns t if menubar was updated. Nil otherwise"
+  (and fume-running-xemacs
+       fume-not-tty
+       (assoc fume-menubar-menu-name current-menubar)
+       (fume-add-menubar-entry)
+       t))
+
+(defsubst fume-trim-string (string)
+  "Returns STRING with leading and trailing whitespace removed."
+  (if (string-match "^[ \t]*" (setq string (format "%s" string)))
+      (setq string (substring string (match-end 0))))
+  (if (string-match "[ \t]*$" string)
+      (setq string (substring string 0 (match-beginning 0))))
+  string)
+
+(defvar fume-syntax-table nil)
+
+(defsubst fume-what-looking-at ()
+  (let (name
+        (orig-syntax-table (copy-syntax-table (syntax-table))))
+    (if fume-syntax-table
+        ()
+      (setq fume-syntax-table (copy-syntax-table))
+      (modify-syntax-entry ?: "w" fume-syntax-table))
+    (unwind-protect
+        (progn
+          (set-syntax-table fume-syntax-table)
+          (save-excursion
+            (while (looking-at "\\sw\\|\\s_") (forward-char 1))
+            (if (re-search-backward "\\sw\\|\\s_" nil t)
+                (let ((beg (progn (forward-char 1) (point))))
+                  (forward-sexp -1)
+                  (while (looking-at "\\s'") (forward-char 1))
+                  (setq name (buffer-substring beg (point)))))))
+      (set-syntax-table orig-syntax-table)
+      name)))
+
+;;; Find function name that point is in.
+;;; The trick is to start from the end...
+;;;
+(defsubst fume-function-before-point ()
+  (if (or fume-modeline-funclist (fume-rescan-buffer) fume-modeline-funclist)
+      (let (result
+            (pt (point)))
+        (save-excursion
+          (catch 'found
+            (mapcar (function
+                     (lambda (p)
+                       (goto-char (cdr p))
+                       (beginning-of-line 1)
+                       (if (>= pt (point))
+                           (throw 'found (setq result (car p))))))
+                    fume-modeline-funclist))
+          result))))
+
+;;; Routines to add a buffer local post command hook
+;;;
+(defsubst fume-post-command-hook-p (hook)
+  (memq hook (if fume-use-local-post-command-hook
+                 local-post-command-hook
+               post-command-hook)))
+
+(defsubst fume-add-post-command-hook (hook &optional append)
+  (or (fume-post-command-hook-p hook)
+      (cond (fume-use-local-post-command-hook
+             (add-hook 'local-post-command-hook hook append))
+            ((fboundp 'make-local-hook)
+             (make-local-hook 'post-command-hook)
+             (add-hook 'post-command-hook hook append t))
+            (t
+             ;; NOT make-variable-buffer-local
+             (make-local-variable 'post-command-hook)
+             (add-hook 'post-command-hook hook append)))))
+
+(defsubst fume-remove-post-command-hook (hook)
+  (and (fume-post-command-hook-p hook)
+       (cond (fume-use-local-post-command-hook
+              (remove-hook 'local-post-command-hook hook))
+             ((fboundp 'make-local-hook)
+              (remove-hook 'post-command-hook hook t))
+             (t
+              (remove-hook 'post-command-hook hook)))))
+
+;;; Routine to install the modeline feature
+;;;
+(defsubst fume-maybe-install-modeline-feature ()
+  (cond ((and fume-display-in-modeline-p (fume-set-defaults))
+         (or fume-modeline-funclist
+             (fume-post-command-hook-p 'fume-tickle-modeline)
+             (fume-rescan-buffer))
+         (fume-add-post-command-hook 'fume-tickle-modeline)
+         (fume-remove-post-command-hook 'fume-maybe-install-modeline-feature)
+         (fume-tickle-modeline-1)
+         (fume-tickle-modeline)
+         t                              ; return success flag
+         )))
+
+(defun fume-toggle-modeline-display ()
+  "Toggles whether func-menu displays function names in the modeline"
+  (interactive)
+  (setq fume-display-in-modeline-p (not fume-display-in-modeline-p))
+  (if (interactive-p) (fume-tickle-modeline)))
+
+;;; Routine to display function before point in the modeline
+;;;
+(defun fume-tickle-modeline ()
+  (let ((fname (and fume-display-in-modeline-p (fume-function-before-point))))
+    (set fume-modeline-buffer-identification
+         (cond ((and fume-display-in-modeline-p (not (null fname)))
+                (setq fname (format "`%s'" (fume-trim-string fname)))
+                (if (eq fume-display-in-modeline-p t)
+                    (list fume-modeline-buffer-identification-1 " " fname)
+                  fname))
+               (t
+                fume-modeline-buffer-identification-0))))
+  (cond ((not fume-display-in-modeline-p)
+         (fume-remove-post-command-hook 'fume-tickle-modeline)
+         (fume-add-post-command-hook 'fume-maybe-install-modeline-feature)))
+  ;; force an update of the mode line
+  (fume-refresh-modeline))
+
+(fume-defvar-local fume-modeline-buffer-identification-0 nil
+  "Storage for original modeline-buffer-identification")
+
+(fume-defvar-local fume-modeline-buffer-identification-1 nil
+  "Storage for munged modeline-buffer-identification")
+
+(defun fume-tickle-f-to-b (str)
+  ;; Change modeline format of "XEmacs: %f" to "XEmacs: %b" in order to make
+  ;; extra room for the function name which is going to be appended to the
+  ;; modeline-buffer-identification component of the modeline-format.
+  (cond ((consp str)
+         (if (extentp (car str))
+             (cons (car str)
+                   (fume-tickle-f-to-b (cdr str)))
+           (mapcar (function fume-tickle-f-to-b) str)))
+        ((not (stringp str))
+         str)
+        ((string-match "%[0-9]*f" str)
+         (let ((newstr (copy-sequence str)))
+           (aset newstr (1- (match-end 0)) (string-to-char "b"))
+           newstr))
+        (t str)))
+
+(defun fume-tickle-modeline-1 ()
+  (or fume-modeline-buffer-identification-0
+      (setq fume-modeline-buffer-identification-0
+            (symbol-value fume-modeline-buffer-identification)))
+  (setq fume-modeline-buffer-identification-1
+        (fume-tickle-f-to-b fume-modeline-buffer-identification-0)))
+
+;;; Routine to toggle auto recanning of the buffer
+(defun fume-toggle-auto-rescanning ()
+  (interactive)
+  (message "Func-Menu buffer auto-rescanning turned %s"
+           (if (setq fume-auto-rescan-buffer-p (not fume-auto-rescan-buffer-p))
+               "ON" "OFF"))
+  (sit-for 0))
+
+;;; Routine to create a shallow separate copy of a list
+;;;
+(if (fboundp 'copy-tree)                ; not built-in in all emacsen
+    (defalias 'fume-shallow-copy-list 'copy-tree)
+  (defun fume-shallow-copy-list (list)
+    (mapcar (function (lambda (i) (cons (car i) (cdr i)))) list)))
+
+;;; Sort function to sort items depending on their function-name
+;;; An item looks like (NAME . POSITION).
+;;;
+(defsubst fume-sort-by-name (item1 item2)
+  (or (string-lessp (car item1) (car item2))
+      (string-equal (car item1) (car item2))))
+
+;;; Sort function to sort items depending on their position
+;;;
+(defsubst fume-sort-by-position (item1 item2)
+  (<= (cdr item1) (cdr item2)))
+
+;;; Support function to calculate relative position in buffer
+;;;
+(defsubst fume-relative-position ()
+  (let ((pos (point))
+        (total (buffer-size)))
+    (if (> total 50000)
+        ;; Avoid overflow from multiplying by 100!
+        (/ (1- pos) (max (/ total 100) 1))
+      (/ (* 100 (1- pos))
+         (max total 1)))))
+
+;;; Split LIST into sublists of max length N
+;;; Example (fume-split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8))
+;;;
+(defsubst fume-split (list n)
+  (let ((i 0)
+        result
+        sublist
+        (remain list))
+    (while remain
+      (if (= n (setq sublist (cons (car remain) sublist)
+                     remain (cdr remain)
+                     i (1+ i)))
+          ;; We have finished a sublist
+          (setq result (cons (nreverse sublist) result)
+                sublist nil
+                i 0)))
+    ;; There might be a sublist (if the length of LIST mod n is != 0)
+    ;; that has to be added to the result list.
+    (if sublist
+        (setq result (cons (nreverse sublist) result)))
+    (nreverse result)))
+
+;;; Routines to create indexes for submenus
+;;;
+
+;;; Method 0
+;;;
+(defun fume-index-sublist-method-0 (sublist count)
+  (concat "Function sublist #" count))
+
+;;; Method 1
+;;; Thomas Plass <thomas.plass@mid-heidelberg.de>
+;;;
+(defun fume-index-sublist-method-1 (sublist &rest count)
+  (interactive)
+  (let ((s (substring (car (car sublist)) 0 1))
+        (e (substring (car (nth (1- (length sublist)) sublist)) 0 1)))
+    (format "Function sublist (%s%s)"
+            s (if (string-equal s e) "<>" (format "<>-%s<>" e)))))
+
+;;; Method 2
+;;; Paul Filipski & Anthony Girardin <{filipski,girardin}@blackhawk.com>
+;;;
+(defun fume-index-sublist-method-2 (sublist &rest count)
+  (let ((s (substring (car (car sublist))
+                      0
+                      (min (length (car (car sublist))) 12)))
+        (e (substring (car (nth (1- (length sublist)) sublist))
+                      0
+                      (min (length (car (nth (1- (length sublist)) sublist)))
+                           12))))
+    (format "%s%s" s (if (string-equal s e) "<>" (format "<> ... %s<>" e)))))
+
+;;; Method 3
+;;;
+(defun fume-index-sublist-method-3-1 (sublist ix limit)
+  (let ((s1 (substring (car (car sublist)) 0 (min limit ix)))
+        (s2 (substring
+             (car (nth (1- (length sublist)) sublist))
+             0 (min (length (car (nth (1- (length sublist)) sublist))) ix))))
+    (cons s1 s2)))
+
+(defun fume-index-sublist-method-3 (sublist &rest count)
+  (let* ((cmplength 12)
+         (limit (length (car (car sublist))))
+         (result (fume-index-sublist-method-3-1 sublist cmplength limit))
+         (str1 (car result))
+         (str2 (cdr result)))
+    (while (and (string-equal str1 str2) (< cmplength limit))
+      (setq cmplength (1+ cmplength)
+            result (fume-index-sublist-method-3-1 sublist cmplength limit)
+            str1 (car result)
+            str2 (cdr result)))
+    (cond ((not (string-equal str1 str2))
+           (format "%s<> ... %s<>" str1 str2))
+          ((< cmplength limit)
+           (format "%s<>" str1))
+          (t
+           (format "%s ..." str1)))))
+
+;;; Buffer rescanning
+;;;
+(defun fume-rescan-buffer-trigger ()
+  "Automatically spots when a buffer rescan becomes necessary"
+  (if fume-auto-rescan-buffer-p
+      (if (> fume-rescan-trigger-counter 0)
+          (setq fume-rescan-trigger-counter (1- fume-rescan-trigger-counter))
+        (setq fume-rescan-trigger-counter
+              (/ (buffer-size) fume-rescan-trigger-counter-buffer-size))
+        (if (or fume-funclist-dirty-p
+                (save-excursion
+                  (let (find fnam)
+                    (condition-case ()
+                        (and fume-function-name-regexp
+                             (setq fnam (fume-function-before-point))
+                             (setq find (symbol-value
+                                         'fume-find-next-function-name-method))
+                             (progn (end-of-line 1)
+                                    (re-search-backward
+                                     fume-function-name-regexp nil t))
+                             (if (eq find 'fume-find-next-latex-section-name)
+                                 (let ((lnam
+                                        (car (fume-find-next-latex-section-name
+                                              (current-buffer)))))
+                                   (fume-tex-rescan-buffer-hook)
+                                   (not (string-equal
+                                         (substring fnam
+                                                    (string-match " " fnam))
+                                         (substring lnam
+                                                    (string-match " " lnam)))))
+                               (not (string-equal
+                                     fnam
+                                     (car (funcall find (current-buffer)))))))
+                      (error nil)))))
+            (let ((fume-scanning-message nil))
+              (fume-rescan-buffer))))))
+
+(defsubst fume-install-rescan-buffer-trigger ()
+  (cond ((not (fume-post-command-hook-p 'fume-rescan-buffer-trigger))
+         (fume-add-post-command-hook 'fume-rescan-buffer-trigger 'append)
+         ;; Make narrow-to-region tickle func-menu
+         (or (fboundp 'fume-narrow-to-region)
+             (fset 'fume-narrow-to-region
+                   (symbol-function 'narrow-to-region)))
+         (defun narrow-to-region (b e)
+           "Restrict editing in this buffer to the current region.
+The rest of the text becomes temporarily invisible and untouchable
+but is not deleted; if you save the buffer in a file, the invisible
+text is included in the file.  C-x n w makes all visible again.
+See also `save-restriction'.
+
+When calling from a program, pass two arguments; positions (integers
+or markers) bounding the text that should remain visible"
+           (interactive "r")
+           (fume-narrow-to-region b e)
+           (if fume-funclist (setq fume-funclist-dirty-p t)))
+         ;; Make widen tickle func-menu
+         (or (fboundp 'fume-widen)
+             (fset 'fume-widen (symbol-function 'widen)))
+         (defun widen ()
+           "Remove restrictions (narrowing) from current buffer.
+This allows the buffer's full text to be seen and edited."
+           (interactive)
+           (fume-widen)
+           (if fume-funclist (setq fume-funclist-dirty-p t))))))
+
+(defun fume-rescan-buffer (&optional popmenu)
+  "Rescans the buffer for function names.
+If optional arg POPMENU is non-nil, brings up the function-menu."
+  (interactive)
+  (let ((find (symbol-value 'fume-find-next-function-name-method))
+        (fnam)
+        (flst '())
+        (buffer-to-scan (current-buffer)))
+    (save-excursion
+      (goto-char (point-min))
+      (cond (fume-scanning-message
+             (message fume-scanning-message 0))
+            (fume-rescanning-message
+             (message fume-rescanning-message)))
+      (while (setq fnam
+                   (condition-case ()
+                       (funcall find buffer-to-scan)
+                     (error
+                      ;; test for more possible fns after this error trap
+                      (if (consp fume-function-name-regexp)
+ 			  (save-excursion
+ 			    (re-search-forward
+ 			     (car fume-function-name-regexp) nil t))
+ 			(and fume-function-name-regexp
+ 			     (save-excursion
+ 			       (re-search-forward
+ 				fume-function-name-regexp nil t)))))))
+        (cond ((listp fnam)
+               (setq flst (cons fnam flst))
+               (if fume-found-function-hook
+                   (save-excursion (run-hooks 'fume-found-function-hook)))))
+        (if fume-scanning-message
+            (message fume-scanning-message (fume-relative-position))))
+      (cond (fume-scanning-message
+             (message "%s done" (format fume-scanning-message 100)))
+            (fume-rescanning-message
+             (message "%s done" fume-rescanning-message)))
+      ;; make a copy of flst sorted by position in buffer
+      (setq fume-modeline-funclist
+            (nreverse
+             (sort (fume-shallow-copy-list flst) 'fume-sort-by-position)))
+      (if fume-sort-function
+          (setq fume-funclist (sort flst fume-sort-function))
+        (setq fume-funclist (nreverse flst)))
+      (if fume-rescan-buffer-hook
+          (run-hooks 'fume-rescan-buffer-hook))))
+  (if popmenu
+      (function-menu)
+    (let ((fume-rescan-inhibit-p t))
+      (fume-update-menubar-entry)))
+  ;; Reset dirty flag
+  (setq fume-funclist-dirty-p nil))
+
+;;; Routine to position cursor
+;;;
+(defun fume-goto-function (fn pos)
+  "Position cursor at function FN at location POS"
+  (let ((orig-pos (point))
+        (case-fold-search nil)
+        (match-fn (cond ((string-match "DEFUN " fn) ; Emacs DEFUN declaration
+                         (substring fn (match-end 0)))
+                        ((string-match "^[ \t]*" fn) ; strip leading spaces
+                         (substring fn (match-end 0)))
+                        (t
+                         fn))))
+
+    (save-excursion
+      (goto-char pos)
+      (or (looking-at match-fn)
+          (let ((fume-scanning-message nil))
+            (fume-rescan-buffer)
+            (setq pos (cdr-safe (assoc fn fume-funclist))))))
+
+    (if pos
+        (progn
+          (goto-char pos)
+          ;; possibly set mark
+          (or (= orig-pos (point))
+              (push-mark orig-pos (null fume-scanning-message)))
+          (if (numberp fume-fn-window-position)
+              (set-window-start
+               (selected-window)
+               (save-excursion
+                 (beginning-of-line
+                  (- 1 (min (- (window-height) 2) fume-fn-window-position)))
+                 (point)))
+            (recenter)))
+      (ding)
+      (message "%s not found" fn)
+      (function-menu))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;  The main entry points for this package  ;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Interface to function-menu for mouse bindings only
+;;;
+(defun mouse-function-menu (event)
+  "Wrapper for mouse button bindings for function-menu"
+  (interactive "e")
+  (let ((currwin (selected-window)))
+    (condition-case ()
+        (progn
+          (select-window (fume-event-window event))
+          (let ((fume-auto-position-popup nil))
+            (call-interactively 'function-menu)))
+      (error (select-window currwin)))))
+
+;;; Interface for Key bindings
+;;;
+(defun function-menu (&optional use-menubar)
+  "Pop up a menu of functions for selection with the mouse.
+
+With a prefix arg adds the menu to the current menubar.
+Jumps to the selected function.  A mark is set at the old position,
+so you can easily go back with C-u \\[set-mark-command]."
+  (interactive "P")
+
+  (setq use-menubar
+        (and use-menubar fume-running-xemacs fume-not-tty current-menubar))
+
+  (catch 'no-functions
+    (or (fume-set-defaults)
+        (if (not (interactive-p))
+            (throw 'no-functions t)
+          (error "func-menu does not support the mode \"%s\"" mode-name)))
+
+    ;; Create a list for this buffer only if there isn't any.
+    (or fume-funclist
+        (if fume-rescan-inhibit-p
+            (fume-remove-menubar-entry)
+          (fume-rescan-buffer)))
+    (or fume-funclist
+        (if (not (interactive-p))
+            (throw 'no-functions t)
+          (error "No functions found in this buffer.")))
+
+    ;; Rescan buffer trigger
+    (fume-install-rescan-buffer-trigger)
+
+    ;; Function name in modeline
+    (fume-maybe-install-modeline-feature)
+
+    ;; The rest of this routine works only for (Lucid) XEmacs
+    (cond (fume-running-xemacs
+           ;; Create the menu
+           (let* ((count 0)
+                  (index-method
+                   (intern (format "fume-index-sublist-method-%d"
+                                   fume-index-method)))
+                  function-menu
+                  (function-menu-items
+                   (mapcar
+                    (function
+                     (lambda (sublist)
+                       (setq count (1+ count))
+                       (cons (format "%s"
+                                     (funcall index-method sublist count))
+                             (mapcar
+                              (function
+                               (lambda (menu)
+                                 (vector (format "%s" (car menu))
+                                         (list 'fume-goto-function
+                                               (car menu) (cdr menu))
+                                         t)))
+                              sublist))))
+                    (fume-split fume-funclist fume-max-items))))
+
+             (or (> count 1)
+                 (setq function-menu-items (cdr (car function-menu-items))))
+
+             (setq function-menu
+                   (` ((,@ function-menu-items)
+                       "----"
+                       ["Display full list of functions"
+                        fume-list-functions t]
+                       [(, (concat "Rescan buffer :  " (buffer-name)))
+                        (fume-rescan-buffer (, (null use-menubar))) t]
+                       "----"
+                       ["Toggle modeline display"
+                        fume-toggle-modeline-display t]
+                       ["Toggle buffer auto rescanning"
+                        fume-toggle-auto-rescanning t]
+                       ["About Func-Menu" fume-about t])))
+
+             (cond (use-menubar
+                    (fume-remove-menubar-entry)
+                    (set-buffer-menubar (copy-sequence current-menubar))
+                    (fume-add-submenu
+                     fume-menubar-menu-name
+                     (` ((,@ function-menu)
+                         "----"
+                         ["Remove Function Menu from menubar"
+                          fume-remove-menubar-entry t]))
+                     fume-menubar-menu-location))
+
+                   ((and fume-not-tty   ; trap tty segmentation faults...
+                         (not (popup-menu-up-p)))
+                    (or (fume-update-menubar-entry)
+                        (setq function-menu
+                              (cons
+                               ["Put Function Menu into menubar"
+                                (function-menu t) t]
+                               (cons "----" function-menu))))
+
+                    (if fume-auto-position-popup
+                        (fume-set-mouse-position))
+
+                    (popup-menu (cons "Functions" function-menu)))))))))
+
+(defun fume-mouse-function-goto (event)
+  "Goto function clicked on or prompt in minibuffer (with completion)."
+  (interactive "@e")
+  (goto-char (event-point event))
+  (let ((fume-no-prompt-on-valid-default t))
+    (fume-prompt-function-goto)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;  Keyboard access to func-menu for tty users  ;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Internal variables only
+;;;
+(defvar fume-list-srcbuffer nil)
+(defvar fume-list-reused-win-p nil)
+(defvar fume-list-trampled-buffer nil)
+
+;;; Espen Skoglund <espensk@stud.cs.uit.no>
+;;; David Hughes <ukchugd@ukpmr.cs.philips.nl>
+;;;
+(defun fume-prompt-function-goto (&optional other-window-p)
+  "Goto function prompted for in minibuffer (with completion).
+With prefix arg, jumps to function in a different window."
+  (interactive "P")
+  (and (interactive-p) current-prefix-arg (setq other-window-p t))
+  (let* ((default-name (fume-what-looking-at))
+         (OrigBuffer (current-buffer))
+         (TargetBuffer
+          (if (eq major-mode 'fume-list-mode) fume-list-srcbuffer OrigBuffer))
+         (fume-no-prompt-on-valid-default
+          (or fume-no-prompt-on-valid-default
+              (eq major-mode 'fume-list-mode))))
+    (switch-to-buffer TargetBuffer)
+    ;; Create funclist and set defaults
+    (cond ((null fume-funclist)
+           (fume-set-defaults)
+           (fume-rescan-buffer)))
+    (let* (;; verify default-name is a valid function name
+           (default-exists-p (assoc default-name fume-funclist))
+           ;; Prompt for function name in minibuffer, unless there is a valid
+           ;; function name at point & fume-no-prompt-on-valid-default set to t
+           (function-name
+            (if (and default-exists-p
+                     fume-no-prompt-on-valid-default)
+                ""
+              (completing-read
+               (format "Goto function%s%s: "
+                       (if other-window-p " other window" "")
+                       (if default-exists-p
+                           (concat " (" default-name ")")
+                         ""))
+               fume-funclist nil t)))
+           ;; Use default function name if just RET was pressed
+           (function-name (if (and default-exists-p (string= "" function-name))
+                              default-name
+                            function-name)))
+      (switch-to-buffer OrigBuffer)
+      ;; Goto function or just return if function name is empty string
+      (cond ((not (string= "" function-name))
+             (if other-window-p
+                 (cond ((prog1 (one-window-p)
+                          (switch-to-buffer-other-window TargetBuffer))
+                        (other-window 1)
+                        (shrink-window-if-larger-than-buffer)
+                        (other-window 1)))
+               (switch-to-buffer TargetBuffer))
+             (fume-goto-function
+              function-name (cdr (assoc function-name fume-funclist))))))))
+
+(defun fume-prompt-function-goto-one-window ()
+  (interactive)
+  (delete-other-windows)
+  (fume-prompt-function-goto))
+
+(defun fume-prompt-function-goto-other-window ()
+  (interactive)
+  (let ((current-prefix-arg 1))
+    (call-interactively 'fume-prompt-function-goto)))
+
+(defun fume-list-functions-show-fn-other-window ()
+  (interactive)
+  (beginning-of-line)
+  (select-window
+   (prog1 (selected-window)
+     (fume-prompt-function-goto-other-window))))
+
+(defun fume-list-functions-show-prev-fn-other-window ()
+  (interactive)
+  (forward-line -1)
+  (fume-list-functions-show-fn-other-window))
+
+(defun fume-list-functions-show-next-fn-other-window ()
+  (interactive)
+  (forward-line 1)
+  (beginning-of-line)
+  (fume-list-functions-show-fn-other-window))
+
+(defun fume-list-functions-help ()
+  (interactive)
+  (fume-about)
+  (sit-for 1)
+  (message "SPC=%s, p=%s, n=%s, o=%s, G=%s, RET=%s,    q=%s"
+           "this"
+           "previous"
+           "next"
+           "other win"
+           "one win"
+           "this win"
+           "quit"))
+
+(defun fume-list-functions-quit ()
+  (interactive)
+  (if (eq major-mode 'fume-list-mode)
+      (kill-buffer (current-buffer)))
+  (if fume-list-reused-win-p
+      (condition-case ()
+          (switch-to-buffer fume-list-trampled-buffer)
+        (error nil))
+    (or (one-window-p)
+        (delete-window (selected-window))))
+  (if (not (eq (current-buffer) fume-list-srcbuffer))
+      (condition-case ()
+          (select-window (get-buffer-window fume-list-srcbuffer))
+        (error
+         (condition-case ()
+             (switch-to-buffer fume-list-srcbuffer)
+           (error nil))))))
+
+(defun fume-list-mouse-select (event)
+  (interactive "e")
+  (let (ws cb cp (wc (current-window-configuration)))
+    (mouse-set-point event)
+    (fume-prompt-function-goto-other-window)
+    (setq ws (save-excursion
+               (beginning-of-line (- 1 fume-fn-window-position)) (point))
+          cb (current-buffer)
+          cp (point))
+    (set-window-configuration wc)
+    (switch-to-buffer cb)
+    (set-window-start (selected-window) ws)
+    (goto-char cp)))
+
+(defvar fume-list-mode-map nil)
+(or fume-list-mode-map
+    (let ((map (make-sparse-keymap)))
+      (define-key map "q"    'fume-list-functions-quit)
+      (define-key map "h"    'fume-list-functions-help)
+      (define-key map "?"    'fume-list-functions-help)
+      (define-key map "g"    'fume-prompt-function-goto)
+      (define-key map "\C-m" 'fume-prompt-function-goto)
+      (define-key map "G"    'fume-prompt-function-goto-one-window)
+      (define-key map "o"    'fume-prompt-function-goto-other-window)
+      (define-key map " "    'fume-list-functions-show-fn-other-window)
+      (define-key map "p"    'fume-list-functions-show-prev-fn-other-window)
+      (define-key map "n"    'fume-list-functions-show-next-fn-other-window)
+      (if fume-not-tty
+          (define-key map [(button2)] 'fume-list-mouse-select))
+      (setq fume-list-mode-map map)))
+
+(defvar fume-list-mode-hook nil "*Hook to run after fume-list-mode entered")
+
+(defun fume-list-functions (&optional this-window)
+  "Creates a temporary buffer listing functions found in the current buffer"
+  (interactive "P")
+  (let ((func-near-point (format "^%s$" (fume-function-before-point))))
+    (cond ((or fume-function-name-regexp (fume-maybe-install-modeline-feature))
+           (save-excursion
+             (let ((srcbuffer (current-buffer)))
+               (set-buffer (get-buffer-create fume-buffer-name))
+               (let (buffer-read-only) (erase-buffer))
+               (use-local-map fume-list-mode-map)
+               (setq buffer-read-only t
+                     mode-name "Func-Menu"
+                     major-mode 'fume-list-mode
+                     fume-list-srcbuffer srcbuffer
+                     fume-list-reused-win-p (not (one-window-p)))
+               (if fume-not-tty
+                   (setq mode-motion-hook 'mode-motion-highlight-symbol))
+               (run-hooks 'fume-list-mode-hook)))
+           (or fume-funclist (fume-rescan-buffer))
+           (if fume-funclist
+               (mapcar (function
+                        (lambda (p)
+                          (save-excursion
+                            (set-buffer fume-buffer-name)
+                            (let (buffer-read-only)
+                              (goto-char (point-max))
+                              (if (= (point-min) (point))
+                                  (insert (car p))
+                                (insert (concat "\n" (car p))))
+                              (set-buffer-modified-p nil)
+                              (goto-char (point-min))))))
+                       fume-funclist))
+           (cond ((interactive-p)
+                  (if current-prefix-arg
+                      (switch-to-buffer fume-buffer-name)
+                    (switch-to-buffer-other-window fume-buffer-name)
+                    (setq fume-list-trampled-buffer (other-buffer))
+                    (or fume-list-reused-win-p
+                        (shrink-window-if-larger-than-buffer)))
+                  (cond (func-near-point
+                         (re-search-forward func-near-point nil t)
+                         (beginning-of-line)))
+                  (fume-list-functions-help))))
+          (t
+           (error "Func-Menu is not operative in this buffer")))))
+
+(provide 'func-menu)