Some fixes to follow coding conventions in files maintained by FSF.
[bpt/emacs.git] / lisp / gud.el
index daa40da..52bfacf 100644 (file)
@@ -4,7 +4,7 @@
 ;; Maintainer: FSF
 ;; Keywords: unix, tools
 
-;; Copyright (C) 1992, 93, 94, 95, 96, 1998 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 93, 94, 95, 96, 1998, 2000 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -68,28 +68,67 @@ Supported debuggers include gdb, sdb, dbx, xdb, perldb, pdb (Python), and jdb."
 (defun gud-marker-filter (&rest args)
   (apply gud-marker-filter args))
 
+(defvar gud-minor-mode nil)
+(put 'gud-minor-mode 'permanent-local t)
+
+(defun gud-symbol (sym &optional soft minor-mode)
+  "Return the symbol used for SYM in MINOR-MODE.
+MINOR-MODE defaults to `gud-minor-mode.
+The symbol returned is `gud-<MINOR-MODE>-<SYM>'.
+If SOFT is non-nil, returns nil if the symbol doesn't already exist."
+  (unless (or minor-mode gud-minor-mode) (error "Gud internal error"))
+  (funcall (if soft 'intern-soft 'intern)
+          (format "gud-%s-%s" (or minor-mode gud-minor-mode) sym)))
+
+(defun gud-val (sym &optional minor-mode)
+  "Return the value of `gud-symbol' SYM.  Default to nil."
+  (let ((sym (gud-symbol sym t minor-mode)))
+    (if (boundp sym) (symbol-value sym))))
+
 (defun gud-find-file (file)
   ;; Don't get confused by double slashes in the name that comes from GDB.
   (while (string-match "//+" file)
     (setq file (replace-match "/" t t file)))
-  (funcall gud-find-file file))
-
-;; Keymap definitions for menu bar entries common to all debuggers and
-;; slots for debugger-dependent ones in sensible places.  (Defined here
-;; before use.)
-(defvar gud-menu-map (make-sparse-keymap "Gud") nil)
-(define-key gud-menu-map [refresh] '("Refresh" . gud-refresh))
-(define-key gud-menu-map [remove] '("Remove Breakpoint" . gud-remove))
-(define-key gud-menu-map [tbreak] nil) ; gdb, sdb and xdb
-(define-key gud-menu-map [break] '("Set Breakpoint" . gud-break))
-(define-key gud-menu-map [up] nil)     ; gdb, dbx, and xdb
-(define-key gud-menu-map [down] nil)   ; gdb, dbx, and xdb
-(define-key gud-menu-map [print] '("Print Expression" . gud-print))
-(define-key gud-menu-map [finish] nil) ; gdb or xdb
-(define-key gud-menu-map [stepi] '("Step Instruction" . gud-stepi))
-(define-key gud-menu-map [step] '("Step Line" . gud-step))
-(define-key gud-menu-map [next] '("Next Line" . gud-next))
-(define-key gud-menu-map [cont] '("Continue" . gud-cont))
+  (let ((minor-mode gud-minor-mode)
+       (buf (funcall gud-find-file file)))
+    (when buf
+      ;; Copy `gud-minor-mode' to the found buffer to turn on the menu.
+      (with-current-buffer buf
+       (set (make-local-variable 'gud-minor-mode) minor-mode))
+      buf)))
+
+(easy-mmode-defmap gud-menu-map
+  '(([refresh] "Refresh" . gud-refresh)
+    ([remove]  "Remove Breakpoint" . gud-remove)
+    ([tbreak]  menu-item "Temporary Breakpoint" gud-tbreak
+                       :enable (memq gud-minor-mode '(gdb sdb xdb)))
+    ([break]   "Set Breakpoint" . gud-break)
+    ([up]      menu-item "Up Stack" gud-up
+                       :enable (memq gud-minor-mode '(gdb dbx xdb)))
+    ([down]    menu-item "Down Stack" gud-down
+                       :enable (memq gud-minor-mode '(gdb dbx xdb)))
+    ([print]   "Print Expression" . gud-print)
+    ([finish]  menu-item "Finish Function" gud-finish
+                       :enable (memq gud-minor-mode '(gdb xdb)))
+    ([stepi]   "Step Instruction" . gud-stepi)
+    ([step]    "Step Line" . gud-step)
+    ([next]    "Next Line" . gud-next)
+    ([cont]    "Continue" . gud-cont))
+  "Menu for `gud-mode'."
+  :name "Gud")
+
+(easy-mmode-defmap gud-minor-mode-map
+  `(([menu-bar debug] . ("Gud" . ,gud-menu-map)))
+  "Map used in visited files.")
+
+(let ((m (assq 'gud-minor-mode minor-mode-map-alist)))
+  (if m (setcdr m gud-minor-mode-map)
+    (push (cons 'gud-minor-mode gud-minor-mode-map) minor-mode-map-alist)))
+
+(defvar gud-mode-map
+  ;; Will inherit from comint-mode via define-derived-mode.
+  (make-sparse-keymap)
+  "`gud-mode' keymap.")
 \f
 ;; ======================================================================
 ;; command definition
@@ -110,6 +149,7 @@ optional doc string DOC.  Certain %-escapes in the string arguments
 are interpreted specially if present.  These are:
 
   %f   name (without directory) of current source file.
+  %F   name (without directory or extension) of current source file.
   %d   directory of current source file.
   %l   number of current source line
   %e   text of the C lvalue or function-call expression surrounding point.
@@ -170,7 +210,7 @@ we're in the GUD buffer)."
 ;;
 ;; The job of the find-file method is to visit and return the buffer indicated
 ;; by the car of gud-tag-frame.  This may be a file name, a tag name, or
-;; something else.  It would be good if it also copied the Gud menubar entry.
+;; something else.
 \f
 ;; ======================================================================
 ;; speedbar support functions and variables.
@@ -249,13 +289,13 @@ off the specialized speedbar mode."
                                  'speedbar-highlight-face
                                  (cond ((eq ff 'gud-gdb-find-file)
                                         'gud-gdb-goto-stackframe)
-                                       (t (error "Should never be here.")))
+                                       (t (error "Should never be here")))
                                  (car frames) t))
        (setq frames (cdr frames)))
 ;      (let ((selected-frame
 ;           (cond ((eq ff 'gud-gdb-find-file)
 ;                  (gud-gdb-selected-frame-info buffer))
-;                 (t (error "Should never be here."))))))
+;                 (t (error "Should never be here"))))))
       )
     (setq gud-last-speedbar-stackframe gud-last-last-frame)))
 
@@ -329,40 +369,34 @@ off the specialized speedbar mode."
     output))
 
 (defun gud-gdb-find-file (f)
-  (save-excursion
-    (let ((buf (find-file-noselect f)))
-      (set-buffer buf)
-      (gud-make-debug-menu)
-      (local-set-key [menu-bar debug tbreak]
-                    '("Temporary Breakpoint" . gud-tbreak))
-      (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish))
-      (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
-      (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
-      buf)))
-
-(defvar gdb-minibuffer-local-map nil
-  "Keymap for minibuffer prompting of gdb startup command.")
-(if gdb-minibuffer-local-map
-    ()
-  (setq gdb-minibuffer-local-map (copy-keymap minibuffer-local-map))
-  (define-key
-    gdb-minibuffer-local-map "\C-i" 'comint-dynamic-complete-filename))
+  (find-file-noselect f 'nowarn))
+
+(easy-mmode-defmap gud-minibuffer-local-map
+  '(("\C-i" . comint-dynamic-complete-filename))
+  "Keymap for minibuffer prompting of gud startup command."
+  :inherit minibuffer-local-map)
+
+(defun gud-query-cmdline (minor-mode &optional init)
+  (let* ((hist-sym (gud-symbol 'history nil minor-mode))
+        (cmd-name (gud-val 'command-name minor-mode)))
+    (unless (boundp hist-sym) (set hist-sym nil))
+    (read-from-minibuffer
+     (format "Run %s (like this): " minor-mode)
+     (or (car-safe (symbol-value hist-sym))
+        (concat (or cmd-name (symbol-name minor-mode)) " " init))
+     gud-minibuffer-local-map nil
+     hist-sym)))
 
 ;;;###autoload
 (defun gdb (command-line)
   "Run gdb on program FILE in buffer *gud-FILE*.
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger."
-  (interactive
-   (list (read-from-minibuffer "Run gdb (like this): "
-                              (if (consp gud-gdb-history)
-                                  (car gud-gdb-history)
-                                "gdb ")
-                              gdb-minibuffer-local-map nil
-                              '(gud-gdb-history . 1))))
+  (interactive (list (gud-query-cmdline 'gdb)))
 
   (gud-common-init command-line 'gud-gdb-massage-args
                   'gud-gdb-marker-filter 'gud-gdb-find-file)
+  (set (make-local-variable 'gud-minor-mode) 'gdb)
 
   (gud-def gud-break  "break %f:%l"  "\C-b" "Set breakpoint at current line.")
   (gud-def gud-tbreak "tbreak %f:%l" "\C-t" "Set temporary breakpoint at current line.")
@@ -410,11 +444,7 @@ This is implemented using the GDB `complete' command which isn't
 available with older versions of GDB."
   (interactive)
   (let* ((end (point))
-        (command (save-excursion
-                   (beginning-of-line)
-                   (and (looking-at comint-prompt-regexp)
-                        (goto-char (match-end 0)))
-                   (buffer-substring (point) end)))
+        (command (buffer-substring (comint-line-beginning-position) end))
         command-word)
     ;; Find the word break.  This match will always succeed.
     (string-match "\\(\\`\\| \\)\\([^ ]*\\)\\'" command)
@@ -434,7 +464,7 @@ available with older versions of GDB."
     (and gud-gdb-complete-list
         (string-match "^Undefined command: \"complete\""
                       (car gud-gdb-complete-list))
-        (error "This version of GDB doesn't support the `complete' command."))
+        (error "This version of GDB doesn't support the `complete' command"))
     ;; Sort the list like readline.
     (setq gud-gdb-complete-list
          (sort gud-gdb-complete-list (function string-lessp)))
@@ -550,7 +580,7 @@ BUFFER is the GUD buffer in which to run the command."
     (set-buffer buffer)
     (if (save-excursion
          (goto-char (point-max))
-         (beginning-of-line)
+         (forward-line 0)
          (not (looking-at comint-prompt-regexp)))
        nil
       ;; Much of this copied from GDB complete, but I'm grabbing the stack
@@ -649,35 +679,24 @@ BUFFER is the GUD buffer in which to run the command."
   string)
 
 (defun gud-sdb-find-file (f)
-  (save-excursion
-    (let ((buf (if gud-sdb-needs-tags
-                  (find-tag-noselect f)
-                (find-file-noselect f))))
-      (set-buffer buf)
-      (gud-make-debug-menu)
-      (local-set-key [menu-bar debug tbreak] '("Temporary Breakpoint" . gud-tbreak))
-      buf)))
+  (if gud-sdb-needs-tags (find-tag-noselect f) (find-file-noselect f)))
 
 ;;;###autoload
 (defun sdb (command-line)
   "Run sdb on program FILE in buffer *gud-FILE*.
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger."
-  (interactive
-   (list (read-from-minibuffer "Run sdb (like this): "
-                              (if (consp gud-sdb-history)
-                                  (car gud-sdb-history)
-                                "sdb ")
-                              nil nil
-                              '(gud-sdb-history . 1))))
+  (interactive (list (gud-query-cmdline 'sdb)))
+
   (if (and gud-sdb-needs-tags
           (not (and (boundp 'tags-file-name)
                     (stringp tags-file-name)
                     (file-exists-p tags-file-name))))
-      (error "The sdb support requires a valid tags table to work."))
+      (error "The sdb support requires a valid tags table to work"))
 
   (gud-common-init command-line 'gud-sdb-massage-args
                   'gud-sdb-marker-filter 'gud-sdb-find-file)
+  (set (make-local-variable 'gud-minor-mode) 'sdb)
 
   (gud-def gud-break  "%l b" "\C-b"   "Set breakpoint at current line.")
   (gud-def gud-tbreak "%l c" "\C-t"   "Set temporary breakpoint at current line.")
@@ -984,26 +1003,14 @@ This was tested using R4.11.")
   (save-excursion
     (let ((realf (gud-dbx-file-name f)))
       (if realf
-         (let ((buf (find-file-noselect realf)))
-           (set-buffer buf)
-           (gud-make-debug-menu)
-           (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
-           (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
-           buf)
-       nil))))
+         (find-file-noselect realf)))))
 
 ;;;###autoload
 (defun dbx (command-line)
   "Run dbx on program FILE in buffer *gud-FILE*.
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger."
-  (interactive
-   (list (read-from-minibuffer "Run dbx (like this): "
-                              (if (consp gud-dbx-history)
-                                  (car gud-dbx-history)
-                                "dbx ")
-                              nil nil
-                              '(gud-dbx-history . 1))))
+  (interactive (list (gud-query-cmdline 'dbx)))
 
   (cond
    (gud-mips-p
@@ -1019,6 +1026,8 @@ and source-file directory for your debugger."
     (gud-common-init command-line 'gud-dbx-massage-args
                     'gud-dbx-marker-filter 'gud-dbx-find-file)))
 
+  (set (make-local-variable 'gud-minor-mode) 'dbx)
+
   (cond
    (gud-mips-p
     (gud-def gud-up     "up %p"         "<" "Up (numeric arg) stack frames.")
@@ -1126,17 +1135,7 @@ containing the executable being debugged."
   (save-excursion
     (let ((realf (gud-xdb-file-name f)))
       (if realf
-         (let ((buf (find-file-noselect realf)))
-           (set-buffer buf)
-           (gud-make-debug-menu)
-           (local-set-key [menu-bar debug tbreak]
-                          '("Temporary Breakpoint" . gud-tbreak))
-           (local-set-key [menu-bar debug finish]
-                          '("Finish Function" . gud-finish))
-           (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
-           (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
-           buf)
-       nil))))
+         (find-file-noselect realf)))))
 
 ;;;###autoload
 (defun xdb (command-line)
@@ -1146,16 +1145,11 @@ and source-file directory for your debugger.
 
 You can set the variable 'gud-xdb-directories' to a list of program source
 directories if your program contains sources from more than one directory."
-  (interactive
-   (list (read-from-minibuffer "Run xdb (like this): "
-                              (if (consp gud-xdb-history)
-                                  (car gud-xdb-history)
-                                "xdb ")
-                              nil nil
-                              '(gud-xdb-history . 1))))
+  (interactive (list (gud-query-cmdline 'xdb)))
 
   (gud-common-init command-line 'gud-xdb-massage-args
                   'gud-xdb-marker-filter 'gud-xdb-find-file)
+  (set (make-local-variable 'gud-minor-mode) 'xdb)
 
   (gud-def gud-break  "b %f:%l"    "\C-b" "Set breakpoint at current line.")
   (gud-def gud-tbreak "b %f:%l\\t" "\C-t"
@@ -1183,14 +1177,48 @@ directories if your program contains sources from more than one directory."
 ;;; History of argument lists passed to perldb.
 (defvar gud-perldb-history nil)
 
+;; Convert a command line as would be typed normally to run a script
+;; into one that invokes an Emacs-enabled debugging session.
+;; "-d" in inserted as the first switch, and "-emacs" is inserted where
+;; it will be $ARGV[0] (see perl5db.pl).
 (defun gud-perldb-massage-args (file args)
-  (cond ((equal (car args) "-e")
-        (cons "-d"
-              (cons (car args)
-                    (cons (nth 1 args)
-                          (cons "--" (cons "-emacs" (cdr (cdr args))))))))
-       (t
-        (cons "-d" (cons (car args) (cons "-emacs" (cdr args)))))))
+  (let* ((new-args (list "-d"))
+        (seen-e nil)
+        (shift (lambda ()
+                 (setq new-args (cons (car args) new-args))
+                 (setq args (cdr args)))))
+
+    ;; Pass all switches and -e scripts through.
+    (while (and args
+               (string-match "^-" (car args))
+               (not (equal "-" (car args)))
+               (not (equal "--" (car args))))
+      (when (equal "-e" (car args))
+       ;; -e goes with the next arg, so shift one extra.
+       (or (funcall shift)
+           ;; -e as the last arg is an error in Perl.
+           (error "No code specified for -e"))
+       (setq seen-e t))
+      (funcall shift))
+
+    (unless seen-e
+      (if (or (not args)
+             (string-match "^-" (car args)))
+         (error "Can't use stdin as the script to debug"))
+      ;; This is the program name.
+      (funcall shift))
+
+    ;; If -e specified, make sure there is a -- so -emacs is not taken
+    ;; as -e macs.
+    (if (and args (equal "--" (car args)))
+       (funcall shift)
+      (and seen-e (push "--" new-args)))
+
+    (push "-emacs" new-args)
+    (while args
+      (funcall shift))
+
+    (nreverse new-args)))
 
 ;; There's no guarantee that Emacs will hand the filter the entire
 ;; marker at once; it could be broken up across several strings.  We
@@ -1243,11 +1271,7 @@ directories if your program contains sources from more than one directory."
     output))
 
 (defun gud-perldb-find-file (f)
-  (save-excursion
-    (let ((buf (find-file-noselect f)))
-      (set-buffer buf)
-      (gud-make-debug-menu)
-      buf)))
+  (find-file-noselect f))
 
 (defcustom gud-perldb-command-name "perl"
   "File name for executing Perl."
@@ -1260,19 +1284,12 @@ directories if your program contains sources from more than one directory."
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger."
   (interactive
-   (list (read-from-minibuffer "Run perldb (like this): "
-                              (if (consp gud-perldb-history)
-                                  (car gud-perldb-history)
-                                (concat gud-perldb-command-name
-                                        " "
-                                        (or (buffer-file-name)
-                                            "-e 0")
-                                        " "))
-                              nil nil
-                              '(gud-perldb-history . 1))))
+   (list (gud-query-cmdline 'perldb
+                           (concat (or (buffer-file-name) "-e 0") " "))))
 
   (gud-common-init command-line 'gud-perldb-massage-args
                   'gud-perldb-marker-filter 'gud-perldb-find-file)
+  (set (make-local-variable 'gud-minor-mode) 'perldb)
 
   (gud-def gud-break  "b %l"         "\C-b" "Set breakpoint at current line.")
   (gud-def gud-remove "d %l"         "\C-d" "Remove breakpoint at current line")
@@ -1286,8 +1303,7 @@ and source-file directory for your debugger."
 
   (setq comint-prompt-regexp "^  DB<+[0-9]+>+ ")
   (setq paragraph-start comint-prompt-regexp)
-  (run-hooks 'perldb-mode-hook)
-  )
+  (run-hooks 'perldb-mode-hook))
 \f
 ;; ======================================================================
 ;; pdb (Python debugger) functions
@@ -1364,22 +1380,7 @@ and source-file directory for your debugger."
     output))
 
 (defun gud-pdb-find-file (f)
-  (save-excursion
-    (let ((buf (find-file-noselect f)))
-      (set-buffer buf)
-      (gud-make-debug-menu)
-      ;; (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish))
-      ;; (local-set-key [menu-bar debug up] '("Up Stack" . gud-up))
-      ;; (local-set-key [menu-bar debug down] '("Down Stack" . gud-down))
-      buf)))
-
-(defvar pdb-minibuffer-local-map nil
-  "Keymap for minibuffer prompting of pdb startup command.")
-(if pdb-minibuffer-local-map
-    ()
-  (setq pdb-minibuffer-local-map (copy-keymap minibuffer-local-map))
-  (define-key
-    pdb-minibuffer-local-map "\C-i" 'comint-dynamic-complete-filename))
+  (find-file-noselect f))
 
 (defcustom gud-pdb-command-name "pdb"
   "File name for executing the Python debugger.
@@ -1393,15 +1394,11 @@ This should be an executable on your path, or an absolute file name."
 The directory containing FILE becomes the initial working directory
 and source-file directory for your debugger."
   (interactive
-   (list (read-from-minibuffer "Run pdb (like this): "
-                              (if (consp gud-pdb-history)
-                                  (car gud-pdb-history)
-                                (concat gud-pdb-command-name " "))
-                              pdb-minibuffer-local-map nil
-                              '(gud-pdb-history . 1))))
+   (list (gud-query-cmdline 'pdb)))
 
   (gud-common-init command-line 'gud-pdb-massage-args
                   'gud-pdb-marker-filter 'gud-pdb-find-file)
+  (set (make-local-variable 'gud-minor-mode) 'pdb)
 
   (gud-def gud-break  "break %l"     "\C-b" "Set breakpoint at current line.")
   (gud-def gud-remove "clear %l"     "\C-d" "Remove breakpoint at current line")
@@ -1510,7 +1507,15 @@ and source-file directory for your debugger."
 ;; List of Java source file directories.
 (defvar gud-jdb-directories (list ".")
   "*A list of directories that gud jdb should search for source code.
-The file names should be absolute, or relative to the current directory.")
+The file names should be absolute, or relative to the current
+directory.
+
+The set of .java files residing in the directories listed are
+syntactically analyzed to determine the classes they define and the
+packages in which these classes belong.  In this way gud jdb maps the
+package-qualified class names output by the jdb debugger to the source
+file from which the class originated.  This allows gud mode to keep
+the source code display in sync with the debugging session.")
 
 ;; List of the java source files for this debugging session.
 (defvar gud-jdb-source-files nil)
@@ -1526,7 +1531,10 @@ The file names should be absolute, or relative to the current directory.")
 ;; which to search for files with extension EXTN.  Normally EXTN is
 ;; given as the regular expression "\\.java$" .
 (defun gud-jdb-build-source-files-list (path extn)
-  (apply 'nconc (mapcar (lambda (d) (directory-files d t extn nil)) path)))
+  (apply 'nconc (mapcar (lambda (d)
+                         (when (file-directory-p d)
+                           (directory-files d t extn nil)))
+                       path)))
 
 ;; Move point past whitespace.
 (defun gud-jdb-skip-whitespace ()
@@ -1574,11 +1582,10 @@ The file names should be absolute, or relative to the current directory.")
 ;; Move point past a string literal.
 (defun gud-jdb-skip-string-literal ()
   (forward-char)
-  (while
-      (progn
-       (if (eq (following-char) ?\\)
-           (forward-char 2))
-       (not (eq (following-char) ?\042)))
+  (while (not (cond
+              ((eq (following-char) ?\\)
+               (forward-char))
+              ((eq (following-char) ?\042))))
     (forward-char))
   (forward-char))
 
@@ -1727,7 +1734,7 @@ The file names should be absolute, or relative to the current directory.")
 ;; holding their definitions.  SOURCES holds a list of all the source
 ;; files to examine.
 (defun gud-jdb-build-class-source-alist (sources)
-  (setq gud-jdb-analysis-buffer (get-buffer-create "*gud-jdb-scratch*"))
+  (setq gud-jdb-analysis-buffer (get-buffer-create " *gud-jdb-scratch*"))
   (prog1
       (apply
        'nconc
@@ -1766,7 +1773,7 @@ The file names should be absolute, or relative to the current directory.")
        (if user-error
            (progn
              (kill-buffer (current-buffer))
-             (error "Error: Omit whitespace between '-classpath' and it's value")))
+             (error "Error: Omit whitespace between '-classpath' and its value")))
 
        (if args
            (setq massaged-args
@@ -1871,23 +1878,19 @@ The file names should be absolute, or relative to the current directory.")
 if there is.  If the \"-classpath\" switch is given, omit all whitespace
 between it and it's value."
   (interactive
-   (list (read-from-minibuffer "Run jdb (like this): "
-                              (if (consp gud-jdb-history)
-                                  (car gud-jdb-history)
-                                (concat gud-jdb-command-name " "))
-                              nil nil
-                              '(gud-jdb-history . 1))))
+   (list (gud-query-cmdline 'jdb)))
 
   (gud-common-init command-line 'gud-jdb-massage-args
           'gud-jdb-marker-filter 'gud-jdb-find-file)
+  (set (make-local-variable 'gud-minor-mode) 'jdb)
 
-  (gud-def gud-break  "stop at %l" "\C-b" "Set breakpoint at current line.")
+  (gud-def gud-break  "stop at %F:%l" "\C-b" "Set breakpoint at current line.")
   (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line")
   (gud-def gud-step   "step"    "\C-s" "Step one source line with display.")
   (gud-def gud-next   "next"    "\C-n" "Step one line (skip functions).")
   (gud-def gud-cont   "cont"    "\C-r" "Continue with display.")
 
-  (setq comint-prompt-regexp "^> \|^.+\[[0-9]+\] ")
+  (setq comint-prompt-regexp "^> \\|^.+\\[[0-9]+\\] ")
   (setq paragraph-start comint-prompt-regexp)
   (run-hooks 'jdb-mode-hook)
 
@@ -1951,7 +1954,7 @@ between it and it's value."
 \f
 (put 'gud-mode 'mode-class 'special)
 
-(defun gud-mode ()
+(define-derived-mode gud-mode comint-mode "Debugger"
   "Major mode for interacting with an inferior debugger process.
 
    You start it up with one of the commands M-x gdb, M-x sdb, M-x dbx,
@@ -2005,50 +2008,31 @@ commands.
 
 Other commands for interacting with the debugger process are inherited from
 comint mode, which see."
-  (interactive)
-  (comint-mode)
-  (setq major-mode 'gud-mode)
-  (setq mode-name "Debugger")
   (setq mode-line-process '(":%s"))
-  (use-local-map comint-mode-map)
-  (gud-make-debug-menu)
   (define-key (current-local-map) "\C-c\C-l" 'gud-refresh)
-  (make-local-variable 'gud-last-frame)
-  (setq gud-last-frame nil)
+  (set (make-local-variable 'gud-last-frame) nil)
   (make-local-variable 'comint-prompt-regexp)
   ;; Don't put repeated commands in command history many times.
-  (make-local-variable 'comint-input-ignoredups)
-  (setq comint-input-ignoredups t)
+  (set (make-local-variable 'comint-input-ignoredups) t)
   (make-local-variable 'paragraph-start)
-  (make-local-variable 'gud-delete-prompt-marker)
-  (setq gud-delete-prompt-marker (make-marker))
-  (run-hooks 'gud-mode-hook))
-
-;; Chop STRING into words separated by SPC or TAB and return a list of them.
-(defun gud-chop-words (string)
-  (let ((i 0) (beg 0)
-       (len (length string))
-       (words nil))
-    (while (< i len)
-      (if (memq (aref string i) '(?\t ? ))
-         (progn
-           (setq words (cons (substring string beg i) words)
-                 beg (1+ i))
-           (while (and (< beg len) (memq (aref string beg) '(?\t ? )))
-             (setq beg (1+ beg)))
-           (setq i (1+ beg)))
-       (setq i (1+ i))))
-    (if (< beg len)
-       (setq words (cons (substring string beg) words)))
-    (nreverse words)))
+  (set (make-local-variable 'gud-delete-prompt-marker) (make-marker)))
+
+;; Cause our buffers to be displayed, by default,
+;; in the selected window.
+;;;###autoload (add-hook 'same-window-regexps "\\*gud-.*\\*\\(\\|<[0-9]+>\\)")
+
+(defcustom gud-chdir-before-run t
+  "Non-nil if GUD should `cd' to the debugged executable."
+  :group 'gud
+  :type 'boolean)
 
 ;; Perform initializations common to all debuggers.
 ;; The first arg is the specified command line,
 ;; which starts with the program to debug.
 ;; The other three args specify the values to use
 ;; for local variables in the debugger buffer.
-(defun gud-common-init (command-line massage-args marker-filter find-file)
-  (let* ((words (gud-chop-words command-line))
+(defun gud-common-init (command-line massage-args marker-filter &optional find-file)
+  (let* ((words (split-string command-line))
         (program (car words))
         ;; Extract the file name from WORDS
         ;; and put t in its place.
@@ -2072,9 +2056,10 @@ comint mode, which see."
                        (expand-file-name file-subst)
                      file-subst)))
         (filepart (and file-word (concat "-" (file-name-nondirectory file)))))
-    (switch-to-buffer (concat "*gud" filepart "*"))
+    (pop-to-buffer (concat "*gud" filepart "*"))
     ;; Set default-directory to the file's directory.
     (and file-word
+        gud-chdir-before-run
         ;; Don't set default-directory if no directory was specified.
         ;; In that case, either the file is found in the current directory,
         ;; in which case this setq is a no-op,
@@ -2096,17 +2081,15 @@ comint mode, which see."
   (gud-mode)
   (make-local-variable 'gud-marker-filter)
   (setq gud-marker-filter marker-filter)
-  (make-local-variable 'gud-find-file)
-  (setq gud-find-file find-file)
+  (if find-file (set (make-local-variable 'gud-find-file) find-file))
 
   (set-process-filter (get-buffer-process (current-buffer)) 'gud-filter)
   (set-process-sentinel (get-buffer-process (current-buffer)) 'gud-sentinel)
-  (gud-set-buffer)
-  )
+  (gud-set-buffer))
 
 (defun gud-set-buffer ()
-  (cond ((eq major-mode 'gud-mode)
-       (setq gud-comint-buffer (current-buffer)))))
+  (when (eq major-mode 'gud-mode)
+    (setq gud-comint-buffer (current-buffer))))
 
 (defvar gud-filter-defer-flag nil
   "Non-nil means don't process anything from the debugger right now.
@@ -2137,23 +2120,26 @@ It is saved for when this flag is not set.")
            (if gud-filter-pending-text
                (setq string (concat gud-filter-pending-text string)
                      gud-filter-pending-text nil))
-           (save-excursion
-             (set-buffer (process-buffer proc))
+
+           (with-current-buffer (process-buffer proc)
              ;; If we have been so requested, delete the debugger prompt.
-             (if (marker-buffer gud-delete-prompt-marker)
-                 (progn
-                   (delete-region (process-mark proc) gud-delete-prompt-marker)
-                   (set-marker gud-delete-prompt-marker nil)))
-             ;; Save the process output, checking for source file markers.
-             (setq output (gud-marker-filter string))
-             ;; Check for a filename-and-line number.
-             ;; Don't display the specified file
-             ;; unless (1) point is at or after the position where output appears
-             ;; and (2) this buffer is on the screen.
-             (setq process-window
-                   (and gud-last-frame
-                        (>= (point) (process-mark proc))
-                        (get-buffer-window (current-buffer))))
+             (save-restriction
+               (widen)
+               (if (marker-buffer gud-delete-prompt-marker)
+                   (progn
+                     (delete-region (process-mark proc)
+                                    gud-delete-prompt-marker)
+                     (set-marker gud-delete-prompt-marker nil)))
+               ;; Save the process output, checking for source file markers.
+               (setq output (gud-marker-filter string))
+               ;; Check for a filename-and-line number.
+               ;; Don't display the specified file
+               ;; unless (1) point is at or after the position where output appears
+               ;; and (2) this buffer is on the screen.
+               (setq process-window
+                     (and gud-last-frame
+                          (>= (point) (process-mark proc))
+                          (get-buffer-window (current-buffer)))))
 
              ;; Let the comint filter do the actual insertion.
              ;; That lets us inherit various comint features.
@@ -2275,6 +2261,11 @@ Obeying it means displaying in another window the specified file and line."
          (setq subst (file-name-nondirectory (if insource
                                                  (buffer-file-name)
                                                (car frame)))))
+        ((eq key ?F)
+         (setq subst (file-name-sans-extension
+                      (file-name-nondirectory (if insource
+                                                  (buffer-file-name)
+                                                (car frame))))))
         ((eq key ?d)
          (setq subst (file-name-directory (if insource
                                               (buffer-file-name)
@@ -2283,18 +2274,17 @@ Obeying it means displaying in another window the specified file and line."
          (setq subst (if insource
                          (save-excursion
                            (beginning-of-line)
-                           (save-restriction (widen)
-                                             (1+ (count-lines 1 (point)))))
+                           (save-restriction
+                             (widen)
+                             (int-to-string (1+ (count-lines 1 (point))))))
                        (cdr frame))))
         ((eq key ?e)
          (setq subst (gud-find-c-expr)))
         ((eq key ?a)
          (setq subst (gud-read-address)))
         ((eq key ?p)
-         (setq subst (if arg (int-to-string arg) ""))))
-       (setq result (concat result
-                            (substring str (match-beginning 1) (match-end 1))
-                            subst)))
+         (setq subst (if arg (int-to-string arg)))))
+       (setq result (concat result (match-string 1 str) subst)))
       (setq str (substring str (match-end 2))))
     ;; There might be text left in STR when the loop ends.
     (concat result str)))
@@ -2334,10 +2324,12 @@ Obeying it means displaying in another window the specified file and line."
     ;; Arrange for the current prompt to get deleted.
     (save-excursion
       (set-buffer gud-comint-buffer)
-      (goto-char (process-mark proc))
-      (beginning-of-line)
-      (if (looking-at comint-prompt-regexp)
-         (set-marker gud-delete-prompt-marker (point))))
+      (save-restriction
+       (widen)
+       (goto-char (process-mark proc))
+       (forward-line 0)
+       (if (looking-at comint-prompt-regexp)
+           (set-marker gud-delete-prompt-marker (point)))))
     (process-send-string proc command)))
 
 (defun gud-refresh (&optional arg)
@@ -2347,22 +2339,6 @@ Obeying it means displaying in another window the specified file and line."
   (or gud-last-frame (setq gud-last-frame gud-last-last-frame))
   (gud-display-frame))
 \f
-
-(defun gud-new-keymap (map)
-  "Return a new keymap which inherits from MAP and has name `Gud'."
-  (nconc (make-sparse-keymap "Gud") map))
-
-(defun gud-make-debug-menu ()
-  "Make sure the current local map has a [menu-bar debug] submap.
-If it doesn't, replace it with a new map that inherits it,
-and create such a submap in that new map."
-  (if (and (current-local-map)
-          (lookup-key (current-local-map) [menu-bar debug]))
-      nil
-    (use-local-map (gud-new-keymap (current-local-map)))
-    (define-key (current-local-map) [menu-bar debug]
-      (cons "Gud" (gud-new-keymap gud-menu-map)))))
-\f
 ;;; Code for parsing expressions out of C code.  The single entry point is
 ;;; find-c-expr, which tries to return an lvalue expression from around point.
 ;;;
@@ -2393,8 +2369,7 @@ and create such a submap in that new map."
       (setq test-expr (gud-next-expr))
       (while (gud-expr-compound expr test-expr)
        (setq expr (cons (car expr) (cdr test-expr)))
-       (setq test-expr (gud-next-expr))
-       )
+       (setq test-expr (gud-next-expr)))
       (buffer-substring (car expr) (cdr expr)))))
 
 (defun gud-innermost-expr ()