Use `called-interactively-p' instead of `interactive-p'.
[bpt/emacs.git] / lisp / progmodes / fortran.el
index 97f4c1c..02346c1 100644 (file)
@@ -1,8 +1,8 @@
 ;;; fortran.el --- Fortran mode for GNU Emacs
 
 ;; Copyright (C) 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
-;;               2002, 2003, 2004, 2005, 2006, 2007
-;;               Free Software Foundation, Inc.
+;;   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+;;   Free Software Foundation, Inc.
 
 ;; Author: Michael D. Prange <prange@erl.mit.edu>
 ;; Maintainer: Glenn Morris <rgm@gnu.org>
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs 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 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -21,9 +21,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 
 ;; silence compiler
 (defvar dabbrev-case-fold-search)
-(defvar font-lock-syntactic-keywords)
 (defvar gud-find-expr-function)
 (defvar imenu-case-fold-search)
 (defvar imenu-syntax-alist)
-
+(defvar comment-region-function)
+(defvar uncomment-region-function)
 
 (defgroup fortran nil
   "Major mode for editing fixed format Fortran code."
@@ -85,6 +83,7 @@ A non-nil value specifies tab-digit style of continuation control.
 A value of nil specifies that continuation lines are marked
 with a character in column 6."
   :type  'boolean
+  :safe  'booleanp
   :group 'fortran-indent)
 
 ;; TODO add more detail of what tab mode is to doc string.
@@ -97,30 +96,34 @@ with a character in column 6."
                                           (interactive)
                                           (describe-variable
                                            'fortran-tab-mode-string))))
-  "String to appear in mode line in TAB format buffers."
+  "String to appear in mode line in TAB format buffers.
+See Info node `(emacs)ForIndent Cont'."
   :type  'string
+  :risky t
   :group 'fortran-indent)
 
-(put 'fortran-tab-mode-string 'risky-local-variable t)
-
 (defcustom fortran-do-indent 3
   "Extra indentation applied to DO blocks."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
 
 (defcustom fortran-if-indent 3
   "Extra indentation applied to IF, SELECT CASE and WHERE blocks."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
 
 (defcustom fortran-structure-indent 3
   "Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
 
 (defcustom fortran-continuation-indent 5
   "Extra indentation applied to continuation lines."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
 
 (defcustom fortran-comment-indent-style 'fixed
@@ -132,28 +135,33 @@ nil forces comment lines not to be touched;
 `relative' indents to current Fortran indentation plus
   `fortran-comment-line-extra-indent'."
   :type  '(radio (const :tag "Untouched" nil) (const fixed) (const relative))
+  :safe  (lambda (value) (memq value '(nil fixed relative)))
   :group 'fortran-indent)
 
 (defcustom fortran-comment-line-extra-indent 0
   "Amount of extra indentation for text within full-line comments."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent
   :group 'fortran-comment)
 
 (defcustom fortran-comment-line-start "C"
   "Delimiter inserted to start new full-line comment.
-You might want to change this to \"*\", for instance."
+You might want to change this to \"*\", for instance; or \"!\" to
+allow trailing comments on a line."
   :version "21.1"
   :type    'string
+  :safe    'stringp
   :group   'fortran-comment)
 
 ;; This used to match preprocessor lines too, but that messes up
 ;; filling and doesn't seem to be necessary.
 (defcustom fortran-comment-line-start-skip
   "^[CcDd*!]\\(\\([^ \t\n]\\)\\2+\\)?[ \t]*"
-  "*Regexp to match the start of a full-line comment."
+  "Regexp to match the start of a full-line comment."
   :version "21.1"
   :type    'regexp
+  :safe    'stringp
   :group   'fortran-comment)
 
 (defcustom fortran-directive-re
@@ -163,16 +171,19 @@ The matching text will be fontified with `font-lock-keyword-face'.
 The matching line will be given zero indentation."
   :version "22.1"
   :type    'regexp
+  :safe    'stringp
   :group   'fortran-indent)
 
 (defcustom fortran-minimum-statement-indent-fixed 6
   "Minimum statement indentation for fixed format continuation style."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
 
 (defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
   "Minimum statement indentation for TAB format continuation style."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
 
 ;; Note that this is documented in the v18 manuals as being a string
@@ -182,23 +193,28 @@ The matching line will be given zero indentation."
   "Single-character string inserted for Fortran comment indentation.
 Normally a space."
   :type  'string
+  :safe  (lambda (value) (or (characterp value)
+                             (and (stringp value) (= (length value) 1))))
   :group 'fortran-comment)
 
 (defcustom fortran-line-number-indent 1
   "Maximum indentation for Fortran line numbers.
 5 means right-justify them within their five-column field."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
 
 (defcustom fortran-check-all-num-for-matching-do nil
   "Non-nil causes all numbered lines to be treated as possible DO loop ends."
   :type  'boolean
+  :safe  'booleanp
   :group 'fortran)
 
 (defcustom fortran-blink-matching-if nil
   "Non-nil causes \\[fortran-indent-line] on ENDIF to blink on matching IF.
 Also, from an ENDDO statement blink on matching DO [WHILE] statement."
   :type  'boolean
+  :safe  'booleanp
   :group 'fortran)
 
 (defcustom fortran-continuation-string "$"
@@ -207,19 +223,22 @@ In fixed format continuation style, this character is inserted in
 column 6 by \\[fortran-split-line] to begin a continuation line.
 Also, if \\[fortran-indent-line] finds this at the beginning of a
 line, it will convert the line into a continuation line of the
-appropriate style. Normally $."
+appropriate style.  Normally \"$\"."
   :type  'string
+  :safe  (lambda (value) (and (stringp value) (= (length value) 1)))
   :group 'fortran)
 
 (defcustom fortran-comment-region "c$$$"
   "String inserted by \\[fortran-comment-region] at start of each \
 line in region."
   :type  'string
+  :safe  'stringp
   :group 'fortran-comment)
 
 (defcustom fortran-electric-line-number t
   "Non-nil causes line numbers to be moved to the correct column as typed."
   :type  'boolean
+  :safe  'booleanp
   :group 'fortran)
 
 ;; TODO use fortran-line-length, somehow.
@@ -232,6 +251,7 @@ line in region."
 This variable is used in fixed format mode.
 See the variable `fortran-column-ruler-tab' for TAB format mode."
   :type  'string
+  :safe  'stringp
   :group 'fortran)
 
 ;; TODO use fortran-line-length, somehow.
@@ -244,17 +264,20 @@ See the variable `fortran-column-ruler-tab' for TAB format mode."
 This variable is used in TAB format mode.
 See the variable `fortran-column-ruler-fixed' for fixed format mode."
   :type  'string
+  :safe  'stringp
   :group 'fortran)
 
 (defcustom fortran-analyze-depth 100
   "Number of lines to scan to identify fixed or TAB format style."
   :type  'integer
+  :safe  'integerp
   :group 'fortran)
 
 (defcustom fortran-break-before-delimiters t
   "Non-nil causes filling to break lines before delimiters.
 Delimiters are characters matching the regexp `fortran-break-delimiters-re'."
   :type  'boolean
+  :safe  'booleanp
   :group 'fortran)
 
 ;; TODO 0 as no-limit, as per g77.
@@ -268,6 +291,7 @@ buffers and the default) or the function
 buffer).  This corresponds to the g77 compiler option
 `-ffixed-line-length-N'."
   :type 'integer
+  :safe 'integerp
   :initialize 'custom-initialize-default
   :set (lambda (symbol value)
          ;; Do all fortran buffers, and the default.
@@ -275,7 +299,6 @@ buffer).  This corresponds to the g77 compiler option
   :version "23.1"
   :group 'fortran)
 
-(put 'fortran-line-length 'safe-local-variable 'integerp)
 (make-variable-buffer-local 'fortran-line-length)
 
 (defcustom fortran-mode-hook nil
@@ -302,6 +325,13 @@ characters long.")
 (defconst fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*("
   "Regexp matching the start of an IF statement.")
 
+;; Note fortran-current-defun uses the subgroups.
+(defconst fortran-start-prog-re
+  "^[ \t]*\\(program\\|subroutine\\|function\
+\\|[ \ta-z0-9*()]*[ \t]+function\\|\
+\\(block[ \t]*data\\)\\)"
+  "Regexp matching the start of a subprogram, from the line start.")
+
 (defconst fortran-end-prog-re1
   "end\
 \\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\
@@ -363,8 +393,8 @@ program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
                           'paren) "\\>")
            ;; Builtin operators.
            (concat "\\." (regexp-opt
-                          '("and" "or" "not" "lt" "le" "eq" "ge"
-                            "gt" "ne" "true" "false")
+                          '("and" "eq" "eqv" "false" "ge" "gt" "le" "lt" "ne"
+                            "neqv" "not" "or" "true")
                           'paren) "\\.")
            ;; do/goto keywords and targets, and goto tags.
            '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?"
@@ -526,15 +556,15 @@ tries to strike a compromise between complexity and flexibility.
 Used in the Fortran entry in `hs-special-modes-alist'.")
 
 (add-to-list 'hs-special-modes-alist
-            `(fortran-mode ,fortran-start-block-re ,fortran-end-block-re
+             `(fortran-mode ,fortran-start-block-re ,fortran-end-block-re
                             "^[cC*!]" fortran-end-of-block nil))
 
 \f
 (defvar fortran-mode-syntax-table
   (let ((table (make-syntax-table)))
-    ;; We might like `;' to be punctuation (g77 multi-statement
-    ;; lines), but that screws abbrevs.
-    (modify-syntax-entry ?\; "w"  table)
+    ;; Was a word-constituent (for abbrevs), now punctuation (g77
+    ;; multi-statement lines).
+    (modify-syntax-entry ?\; "."  table)
     (modify-syntax-entry ?\r " "  table)
     (modify-syntax-entry ?+  "."  table)
     (modify-syntax-entry ?-  "."  table)
@@ -566,7 +596,8 @@ Used in the Fortran entry in `hs-special-modes-alist'.")
   (let ((map (make-sparse-keymap)))
     (define-key map ";"        'fortran-abbrev-start)
     (define-key map "\C-c;"    'fortran-comment-region)
-    (define-key map "\M-;"     'fortran-indent-comment)
+    ;; The default comment-dwim does at least as much as this.
+;;;    (define-key map "\M-;"     'fortran-indent-comment)
     (define-key map "\M-\n"    'fortran-split-line)
     (define-key map "\M-\C-n"  'fortran-end-of-block)
     (define-key map "\M-\C-p"  'fortran-beginning-of-block)
@@ -590,14 +621,21 @@ Used in the Fortran entry in `hs-special-modes-alist'.")
 
     (easy-menu-define fortran-menu map "Menu for Fortran mode."
       `("Fortran"
-        ["Manual" (info "(emacs)Fortran")]
+        ["Manual" (info "(emacs)Fortran") :active t
+         :help "Read the Emacs manual chapter on Fortran mode"]
         ("Customization"
          ,(custom-menu-create 'fortran)
-         ["Set"  Custom-set t]
-         ["Save" Custom-save t]
-         ["Reset to Current" Custom-reset-current t]
-         ["Reset to Saved"   Custom-reset-saved t]
-         ["Reset to Standard Settings" Custom-reset-standard t]
+         ;; FIXME useless?
+         ["Set"  Custom-set :active t
+          :help "Set current value of all edited settings in the buffer"]
+         ["Save" Custom-save :active t
+          :help "Set and save all edited settings"]
+         ["Reset to Current" Custom-reset-current :active t
+          :help "Reset all edited settings to current"]
+         ["Reset to Saved" Custom-reset-saved :active t
+          :help "Reset all edited or set settings to saved"]
+         ["Reset to Standard Settings" Custom-reset-standard :active t
+          :help "Erase all cusomizations in buffer"]
          )
         "--"
         ["Comment Region" fortran-comment-region mark-active]
@@ -607,9 +645,12 @@ Used in the Fortran entry in `hs-special-modes-alist'.")
         ["Indent Region"     indent-region mark-active]
         ["Indent Subprogram" fortran-indent-subprogram t]
         "--"
-        ["Beginning of Subprogram" fortran-beginning-of-subprogram t]
-        ["End of Subprogram"       fortran-end-of-subprogram       t]
+        ["Beginning of Subprogram" fortran-beginning-of-subprogram :active t
+         :help "Move point to the start of the current subprogram"]
+        ["End of Subprogram" fortran-end-of-subprogram :active t
+         :help "Move point to the end of the current subprogram"]
         ("Mark"
+         :help "Mark a region of code"
          ["Subprogram" mark-defun      t]
          ["IF Block"   fortran-mark-if t]
          ["DO Block"   fortran-mark-do t]
@@ -617,105 +658,101 @@ Used in the Fortran entry in `hs-special-modes-alist'.")
         ["Narrow to Subprogram" narrow-to-defun t]
         ["Widen" widen t]
         "--"
-        ["Temporary column ruler" fortran-column-ruler  t]
+        ["Temporary Column Ruler" fortran-column-ruler :active t
+         :help "Briefly display Fortran column numbers"]
         ;; May not be '72', depending on fortran-line-length, but this
         ;; seems ok for a menu item.
-        ["72-column window"       fortran-window-create t]
+        ["72-column Window" fortran-window-create :active t
+         :help "Set window width to Fortran line length"]
         ["Full Width Window"
          (enlarge-window-horizontally (- (frame-width) (window-width)))
-         (< (window-width) (frame-width))]
-        ["Momentary 72-column window" fortran-window-create-momentarily t]
+         :active (not (window-full-width-p))
+         :help "Make window full width"]
+        ["Momentary 72-Column Window" fortran-window-create-momentarily
+         :active t :help "Briefly set window width to Fortran line length"]
         "--"
-        ["Break Line at Point"    fortran-split-line t]
-        ["Join Line"              fortran-join-line  t]
-        ["Fill Statement/Comment" fill-paragraph     t]
+        ["Break Line at Point" fortran-split-line :active t
+         :help "Break the current line at point"]
+        ["Join Line" fortran-join-line :active t
+         :help "Join the current line to the previous one"]
+        ["Fill Statement/Comment" fill-paragraph t]
         "--"
-        ["Toggle auto-fill"   auto-fill-mode :selected auto-fill-function
-         :style toggle]
-        ["Toggle abbrev-mode" abbrev-mode    :selected abbrev-mode
-         :style toggle]
-        ["Add imenu Menu" imenu-add-menubar-index
+        ["Toggle Auto Fill" auto-fill-mode :selected auto-fill-function
+         :style toggle
+         :help "Automatically fill text while typing in this buffer"]
+        ["Toggle Abbrev Mode" abbrev-mode :selected abbrev-mode
+         :style toggle :help "Expand abbreviations while typing in this buffer"]
+        ["Add Imenu Menu" imenu-add-menubar-index
          :active   (not (lookup-key (current-local-map) [menu-bar index]))
-         :included (fboundp 'imenu-add-to-menubar)]))
+         :included (fboundp 'imenu-add-to-menubar)
+         :help "Add an index menu to the menu-bar"]))
     map)
   "Keymap used in Fortran mode.")
 
 \f
-(defvar fortran-mode-abbrev-table
-  (progn
-    (define-abbrev-table 'fortran-mode-abbrev-table nil)
-    fortran-mode-abbrev-table)
-  "Abbrev table for Fortran mode.")
-
-(let (abbrevs-changed)
-  ;; Use the 6th arg (SYSTEM-FLAG) of define-abbrev if possible.
-  ;; Only use `apply' to quieten the byte-compiler.
-  (mapcar
-   (function (lambda (element)
-               (condition-case nil
-                   (apply 'define-abbrev fortran-mode-abbrev-table
-                          (append element '(nil 0 t)))
-                 (wrong-number-of-arguments
-                  (apply 'define-abbrev fortran-mode-abbrev-table
-                         (append element '(nil 0)))))))
-   '((";au"   "automatic"         )
-     (";b"    "byte"              )
-     (";bd"   "block data"        )
-     (";ch"   "character"         )
-     (";cl"   "close"             )
-     (";c"    "continue"          )
-     (";cm"   "common"            )
-     (";cx"   "complex"           )
-     (";df"   "define"            )
-     (";di"   "dimension"         )
-     (";do"   "double"            )
-     (";dc"   "double complex"    )
-     (";dp"   "double precision"  )
-     (";dw"   "do while"          )
-     (";e"    "else"              )
-     (";ed"   "enddo"             )
-     (";el"   "elseif"            )
-     (";en"   "endif"             )
-     (";eq"   "equivalence"       )
-     (";ew"   "endwhere"          )
-     (";ex"   "external"          )
-     (";ey"   "entry"             )
-     (";f"    "format"            )
-     (";fa"   ".false."           )
-     (";fu"   "function"          )
-     (";g"    "goto"              )
-     (";im"   "implicit"          )
-     (";ib"   "implicit byte"     )
-     (";ic"   "implicit complex"  )
-     (";ich"  "implicit character")
-     (";ii"   "implicit integer"  )
-     (";il"   "implicit logical"  )
-     (";ir"   "implicit real"     )
-     (";inc"  "include"           )
-     (";in"   "integer"           )
-     (";intr" "intrinsic"         )
-     (";l"    "logical"           )
-     (";n"    "namelist"          )
-     (";o"    "open"              )     ; was ;op
-     (";pa"   "parameter"         )
-     (";pr"   "program"           )
-     (";ps"   "pause"             )
-     (";p"    "print"             )
-     (";rc"   "record"            )
-     (";re"   "real"              )
-     (";r"    "read"              )
-     (";rt"   "return"            )
-     (";rw"   "rewind"            )
-     (";s"    "stop"              )
-     (";sa"   "save"              )
-     (";st"   "structure"         )
-     (";sc"   "static"            )
-     (";su"   "subroutine"        )
-     (";tr"   ".true."            )
-     (";ty"   "type"              )
-     (";vo"   "volatile"          )
-     (";w"    "write"             )
-     (";wh"   "where"             ))))
+(define-abbrev-table 'fortran-mode-abbrev-table
+  (mapcar (lambda (e) (list (car e) (cdr e) nil :system t))
+          '((";au"   . "automatic"         )
+            (";b"    . "byte"              )
+            (";bd"   . "block data"        )
+            (";ch"   . "character"         )
+            (";cl"   . "close"             )
+            (";c"    . "continue"          )
+            (";cm"   . "common"            )
+            (";cx"   . "complex"           )
+            (";df"   . "define"            )
+            (";di"   . "dimension"         )
+            (";do"   . "double"            )
+            (";dc"   . "double complex"    )
+            (";dp"   . "double precision"  )
+            (";dw"   . "do while"          )
+            (";e"    . "else"              )
+            (";ed"   . "enddo"             )
+            (";el"   . "elseif"            )
+            (";en"   . "endif"             )
+            (";eq"   . "equivalence"       )
+            (";ew"   . "endwhere"          )
+            (";ex"   . "external"          )
+            (";ey"   . "entry"             )
+            (";f"    . "format"            )
+            (";fa"   . ".false."           )
+            (";fu"   . "function"          )
+            (";g"    . "goto"              )
+            (";im"   . "implicit"          )
+            (";ib"   . "implicit byte"     )
+            (";ic"   . "implicit complex"  )
+            (";ich"  . "implicit character")
+            (";ii"   . "implicit integer"  )
+            (";il"   . "implicit logical"  )
+            (";ir"   . "implicit real"     )
+            (";inc"  . "include"           )
+            (";in"   . "integer"           )
+            (";intr" . "intrinsic"         )
+            (";l"    . "logical"           )
+            (";n"    . "namelist"          )
+            (";o"    . "open"              ) ; was ;op
+            (";pa"   . "parameter"         )
+            (";pr"   . "program"           )
+            (";ps"   . "pause"             )
+            (";p"    . "print"             )
+            (";rc"   . "record"            )
+            (";re"   . "real"              )
+            (";r"    . "read"              )
+            (";rt"   . "return"            )
+            (";rw"   . "rewind"            )
+            (";s"    . "stop"              )
+            (";sa"   . "save"              )
+            (";st"   . "structure"         )
+            (";sc"   . "static"            )
+            (";su"   . "subroutine"        )
+            (";tr"   . ".true."            )
+            (";ty"   . "type"              )
+            (";vo"   . "volatile"          )
+            (";w"    . "write"             )
+            (";wh"   . "where"             )))
+  "Abbrev table for Fortran mode."
+  ;; Accept ; as the first char of an abbrev.  Also allow _ in abbrevs.
+  :regexp "\\(?:[^[:word:]_;]\\|^\\)\\(;?[[:word:]_]+\\)[^[:word:]_]*")
 
 \f
 ;;;###autoload
@@ -756,7 +793,7 @@ Variables controlling indentation style and extra features:
                 `fortran-minimum-statement-indent-tab' (TAB format),
               depending on the continuation format in use.
   relative  indent to `fortran-comment-line-extra-indent' beyond the
-             indentation for a line of code.
+              indentation for a line of code.
   (default 'fixed)
 `fortran-comment-indent-char'
   Single-character string to be inserted instead of space for
@@ -814,6 +851,11 @@ with no args, if that value is non-nil."
        ;; (concat "\\(\\)\\(![ \t]*\\|" fortran-comment-line-start-skip "\\)")
        "\\(\\)\\(?:^[CcDd*]\\|!\\)\\(?:\\([^ \t\n]\\)\\2+\\)?[ \t]*")
   (set (make-local-variable 'comment-indent-function) 'fortran-comment-indent)
+  (set (make-local-variable 'comment-region-function) 'fortran-comment-region)
+  (set (make-local-variable 'uncomment-region-function)
+       'fortran-uncomment-region)
+  (set (make-local-variable 'comment-insert-comment-function)
+       'fortran-indent-comment)
   (set (make-local-variable 'abbrev-all-caps) t)
   (set (make-local-variable 'normal-auto-fill-function) 'fortran-auto-fill)
   (set (make-local-variable 'indent-tabs-mode) (fortran-analyze-file-format))
@@ -827,9 +869,9 @@ with no args, if that value is non-nil."
           fortran-font-lock-keywords-3
           fortran-font-lock-keywords-4)
          nil t ((?/ . "$/") ("_$" . "w"))
-         fortran-beginning-of-subprogram))
-  (set (make-local-variable 'font-lock-syntactic-keywords)
-       (fortran-font-lock-syntactic-keywords))
+         fortran-beginning-of-subprogram
+         (font-lock-syntactic-keywords
+          . fortran-font-lock-syntactic-keywords)))
   (set (make-local-variable 'imenu-case-fold-search) t)
   (set (make-local-variable 'imenu-generic-expression)
        fortran-imenu-generic-expression)
@@ -853,20 +895,20 @@ Fortran mode.  If the optional argument GLOBAL is non-nil, it
 affects all Fortran buffers, and also the default."
   (interactive "p")
   (let (new)
-    (mapcar (lambda (buff)
-              (with-current-buffer buff
-                (when (eq major-mode 'fortran-mode)
-                  (setq fortran-line-length nchars
-                        fill-column fortran-line-length
-                        new (fortran-font-lock-syntactic-keywords))
-                  ;; Refontify only if necessary.
-                  (unless (equal new font-lock-syntactic-keywords)
-                    (setq font-lock-syntactic-keywords
-                          (fortran-font-lock-syntactic-keywords))
-                    (if font-lock-mode (font-lock-mode 1))))))
-            (if global
-                (buffer-list)
-              (list (current-buffer))))
+    (mapc (lambda (buff)
+            (with-current-buffer buff
+              (when (eq major-mode 'fortran-mode)
+                (setq fortran-line-length nchars
+                      fill-column fortran-line-length
+                      new (fortran-font-lock-syntactic-keywords))
+                ;; Refontify only if necessary.
+                (unless (equal new font-lock-syntactic-keywords)
+                  (setq font-lock-syntactic-keywords
+                        (fortran-font-lock-syntactic-keywords))
+                  (if font-lock-mode (font-lock-mode 1))))))
+          (if global
+              (buffer-list)
+            (list (current-buffer))))
     (if global
         (setq-default fortran-line-length nchars))))
 
@@ -874,6 +916,8 @@ affects all Fortran buffers, and also the default."
   "Fortran mode adds this to `hack-local-variables-hook'."
   (fortran-line-length fortran-line-length))
 
+(declare-function gud-find-c-expr "gud.el" nil)
+
 (defun fortran-gud-find-expr ()
   ;; Consider \n as punctuation (end of expression).
   (with-syntax-table fortran-gud-syntax-table
@@ -899,33 +943,33 @@ or on a new line inserted before this line if this line is not blank."
   (beginning-of-line)
   ;; Recognize existing comments of either kind.
   (cond ((fortran-find-comment-start-skip 'all)
-        (goto-char (match-beginning 0))
-        (if (bolp)
-            (fortran-indent-line)
-          (unless (= (current-column) (fortran-comment-indent))
+         (goto-char (match-beginning 0))
+         (if (bolp)
+             (fortran-indent-line)
+           (unless (= (current-column) (fortran-comment-indent))
              (delete-horizontal-space)
              (indent-to (fortran-comment-indent)))))
-       ;; No existing comment.
-       ;; If side-by-side comments are defined, insert one,
-       ;; unless line is now blank.
-       ((and comment-start (not (looking-at "[ \t]*$"))
-             (string-match comment-start-skip (concat " " comment-start)))
-        (end-of-line)
-        (delete-horizontal-space)
-        (indent-to (fortran-comment-indent))
-        (insert comment-start))
-       ;; Else insert separate-line comment, making a new line if nec.
-       (t
-        (if (looking-at "^[ \t]*$")
-            (delete-horizontal-space)
-          (beginning-of-line)
-          (insert ?\n)
-          (forward-char -1))
-        (insert fortran-comment-line-start)
-        (insert-char (if (stringp fortran-comment-indent-char)
-                         (aref fortran-comment-indent-char 0)
-                       fortran-comment-indent-char)
-                     (- (fortran-calculate-indent) (current-column))))))
+        ;; No existing comment.
+        ;; If side-by-side comments are defined, insert one,
+        ;; unless line is now blank.
+        ((and comment-start (not (looking-at "[ \t]*$"))
+              (string-match comment-start-skip (concat " " comment-start)))
+         (end-of-line)
+         (delete-horizontal-space)
+         (indent-to (fortran-comment-indent))
+         (insert comment-start))
+        ;; Else insert separate-line comment, making a new line if nec.
+        (t
+         (if (looking-at "^[ \t]*$")
+             (delete-horizontal-space)
+           (beginning-of-line)
+           (insert ?\n)
+           (forward-char -1))
+         (insert fortran-comment-line-start)
+         (insert-char (if (stringp fortran-comment-indent-char)
+                          (aref fortran-comment-indent-char 0)
+                        fortran-comment-indent-char)
+                      (- (fortran-calculate-indent) (current-column))))))
 
 (defun fortran-comment-region (beg-region end-region arg)
   "Comment every line in the region.
@@ -935,7 +979,7 @@ BEG-REGION and END-REGION specify the region boundaries.
 With non-nil ARG, uncomments the region."
   (interactive "*r\nP")
   (let ((end-region-mark (copy-marker end-region))
-       (save-point (point-marker)))
+        (save-point (point-marker)))
     (goto-char beg-region)
     (beginning-of-line)
     (if arg
@@ -954,12 +998,17 @@ With non-nil ARG, uncomments the region."
     (set-marker end-region-mark nil)
     (set-marker save-point nil)))
 
+;; uncomment-region calls this with 3 args.
+(defun fortran-uncomment-region (start end &optional ignored)
+  "Uncomment every line in the region."
+  (fortran-comment-region start end t))
+
 \f
 (defun fortran-abbrev-start ()
   "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs.
 Any other key combination is executed normally."
   (interactive "*")
-  (insert last-command-char)
+  (insert last-command-event)
   (let* ((event (if (fboundp 'next-command-event) ; XEmacs
                     (next-command-event)
                   (read-event)))
@@ -968,7 +1017,7 @@ Any other key combination is executed normally."
     ;; Insert char if not equal to `?', or if abbrev-mode is off.
     (if (and abbrev-mode (or (eq char ??) (eq char help-char)
                              (memq event help-event-list)))
-       (fortran-abbrev-help)
+        (fortran-abbrev-help)
       (push event unread-command-events))))
 
 (defun fortran-abbrev-help ()
@@ -1001,8 +1050,8 @@ The next key typed is executed unless it is SPC."
    (save-excursion
      (beginning-of-line)
      (if (eq (window-start (selected-window))
-            (window-point (selected-window)))
-        (line-beginning-position 2)
+             (window-point (selected-window)))
+         (line-beginning-position 2)
        (point)))
    nil "Type SPC or any command to erase ruler."))
 
@@ -1011,13 +1060,13 @@ The next key typed is executed unless it is SPC."
 See also `fortran-window-create-momentarily'."
   (interactive)
   (let ((window-min-width 2))
-    (if (< (window-width) (frame-width))
-       (enlarge-window-horizontally (- (frame-width)
-                                       (window-width) 1)))
+    (unless (window-full-width-p)
+        (enlarge-window-horizontally (- (frame-width)
+                                        (window-width) 1)))
     (let* ((window-edges (window-edges))
-          (scroll-bar-width (- (nth 2 window-edges)
-                               (car window-edges)
-                               (window-width))))
+           (scroll-bar-width (- (nth 2 window-edges)
+                                (car window-edges)
+                                (window-width))))
       (split-window-horizontally (+ fortran-line-length scroll-bar-width)))
     (other-window 1)
     (switch-to-buffer " fortran-window-extra" t)
@@ -1029,16 +1078,16 @@ Optional ARG non-nil and non-unity disables the momentary feature.
 See also `fortran-window-create'."
   (interactive "p")
   (if (or (not arg)
-         (= arg 1))
+          (= arg 1))
       (save-window-excursion
-       (progn
-         (condition-case nil
-             (fortran-window-create)
-           (error (error "No room for Fortran window")))
-         (message "Type SPC to continue editing.")
-         (let ((char (read-event)))
-           (or (equal char ?\s)
-               (setq unread-command-events (list char))))))
+        (progn
+          (condition-case nil
+              (fortran-window-create)
+            (error (error "No room for Fortran window")))
+          (message "Type SPC to continue editing.")
+          (let ((char (read-event)))
+            (or (equal char ?\s)
+                (setq unread-command-events (list char))))))
     (fortran-window-create)))
 
 (defun fortran-split-line ()
@@ -1046,13 +1095,13 @@ See also `fortran-window-create'."
   (interactive "*")
   (delete-horizontal-space)
   (if (save-excursion
-       (let ((pos (point)))
-         (beginning-of-line)
-         (and (fortran-find-comment-start-skip 'all)
-              (< (match-beginning 0) pos))))
+        (let ((pos (point)))
+          (beginning-of-line)
+          (and (fortran-find-comment-start-skip 'all)
+               (< (match-beginning 0) pos))))
       (insert ?\n (match-string 0))
     (if indent-tabs-mode
-       (insert ?\n ?\t (fortran-numerical-continuation-char))
+        (insert ?\n ?\t (fortran-numerical-continuation-char))
       (insert "\n " fortran-continuation-string))) ; space after \n important
   (fortran-indent-line))               ; when cont string is C, c or *
 
@@ -1088,7 +1137,7 @@ plus one, otherwise return 1.  Zero not allowed."
   (save-excursion
     (forward-line -1)
     (if (looking-at "\t[1-9]")
-       (+ ?1 (% (- (char-after (1+ (point))) ?0) 9))
+        (+ ?1 (% (- (char-after (1+ (point))) ?0) 9))
       ?1)))
 
 (put 'fortran-electric-line-number 'delete-selection t)
@@ -1098,29 +1147,29 @@ Auto-indent does not happen if a numeric ARG is used."
   (interactive "*P")
   (if (or arg (not fortran-electric-line-number))
       (if arg
-         (self-insert-command (prefix-numeric-value arg))
-       (self-insert-command 1))
+          (self-insert-command (prefix-numeric-value arg))
+        (self-insert-command 1))
     (if (or (and (= 5 (current-column))
-                (save-excursion
-                  (beginning-of-line)
+                 (save-excursion
+                   (beginning-of-line)
                     ;; In col 5 with only spaces to the left.
-                  (looking-at " \\{5\\}")))
-           (and (= (if indent-tabs-mode
-                       fortran-minimum-statement-indent-tab
-                     fortran-minimum-statement-indent-fixed) (current-column))
+                   (looking-at " \\{5\\}")))
+            (and (= (if indent-tabs-mode
+                        fortran-minimum-statement-indent-tab
+                      fortran-minimum-statement-indent-fixed) (current-column))
                  ;; In col 8 with a single tab to the left.
-                (eq ?\t (char-after (line-beginning-position)))
-                (not (or (eq last-command 'fortran-indent-line)
-                         (eq last-command
-                             'fortran-indent-new-line))))
-           (save-excursion
-             (re-search-backward "[^ \t0-9]"
-                                 (line-beginning-position)
-                                 t))   ; not a line number
-           (looking-at "[0-9]"))       ; within a line number
-       (self-insert-command (prefix-numeric-value arg))
+                 (eq ?\t (char-after (line-beginning-position)))
+                 (not (or (eq last-command 'fortran-indent-line)
+                          (eq last-command
+                              'fortran-indent-new-line))))
+            (save-excursion
+              (re-search-backward "[^ \t0-9]"
+                                  (line-beginning-position)
+                                  t))   ; not a line number
+            (looking-at "[0-9]"))       ; within a line number
+        (self-insert-command (prefix-numeric-value arg))
       (skip-chars-backward " \t")
-      (insert last-command-char)
+      (insert last-command-event)
       (fortran-indent-line))))
 
 \f
@@ -1130,42 +1179,52 @@ Auto-indent does not happen if a numeric ARG is used."
   ;; match of whitespace, avoiding possible column 73+ stuff.
   (save-match-data
     (string-match "^\\s-*\\(\\'\\|\\s<\\)"
-                 (buffer-substring (match-end 0)
-                                   (min (line-end-position)
-                                        (+ fortran-line-length
+                  (buffer-substring (match-end 0)
+                                    (min (line-end-position)
+                                         (+ fortran-line-length
                                             (line-beginning-position)))))))
 
-;; Note that you can't just check backwards for `subroutine' &c in
-;; case of un-marked main programs not at the start of the file.
+;; This is more complex than first expected because the beginning of a
+;; main program may be implicit (ie not marked by a PROGRAM statement).
+;; This would be fine (we could just go to bob in the absence of a match),
+;; except it need not even be the first subprogram in the file (eg it
+;; could follow a subroutine).  Hence we have to search for END
+;; statements instead.
+;; cf fortran-beginning-of-block, f90-beginning-of-subprogram
+;; Note that unlike the latter, we don't have to worry about nested
+;; subprograms (?).
+;; FIXME push-mark?
 (defun fortran-beginning-of-subprogram ()
   "Move point to the beginning of the current Fortran subprogram."
   (interactive)
-  (save-match-data
-    (let ((case-fold-search t))
-      (beginning-of-line -1)
-      (if (catch 'ok
-           (while (re-search-backward fortran-end-prog-re nil 'move)
-             (if (fortran-check-end-prog-re)
-                 (throw 'ok t))))
-         (forward-line)))))
-
+  (let ((case-fold-search t))
+    ;; If called already at the start of subprogram, go to the previous.
+    (beginning-of-line (if (bolp) 0 1))
+    (save-match-data
+      (or (looking-at fortran-start-prog-re)
+          ;; This leaves us at bob if before the first subprogram.
+          (eq (fortran-previous-statement) 'first-statement)
+          (if (or (catch 'ok
+                    (while (re-search-backward fortran-end-prog-re nil 'move)
+                      (if (fortran-check-end-prog-re) (throw 'ok t))))
+                  ;; If the search failed, must be at bob.
+                  ;; First code line is the start of the subprogram.
+                  ;; FIXME use a more rigorous test, cf fortran-next-statement?
+                  ;; Though that needs to handle continuations too.
+                  (not (looking-at "^\\([ \t]*[0-9]\\|[ \t]+[^!#]\\)")))
+              (fortran-next-statement))))))
+
+;; This is simpler than f-beginning-of-s because the end of a
+;; subprogram is never implicit.
 (defun fortran-end-of-subprogram ()
   "Move point to the end of the current Fortran subprogram."
   (interactive)
-  (save-match-data
-    (let ((case-fold-search t))
-      (if (save-excursion              ; on END
-           (beginning-of-line)
-           (and (looking-at fortran-end-prog-re)
-                (fortran-check-end-prog-re)))
-         (forward-line)
-       (beginning-of-line 2)
-       (catch 'ok
-         (while (re-search-forward fortran-end-prog-re nil 'move)
-           (if (fortran-check-end-prog-re)
-               (throw 'ok t))))
-       (goto-char (match-beginning 0))
-       (forward-line)))))
+  (let ((case-fold-search t))
+    (beginning-of-line)
+    (save-match-data
+      (while (and (re-search-forward fortran-end-prog-re nil 'move)
+                  (not (fortran-check-end-prog-re))))
+      (forward-line))))
 
 (defun fortran-previous-statement ()
   "Move point to beginning of the previous Fortran statement.
@@ -1176,28 +1235,28 @@ Directive lines are treated as comments."
   (let (not-first-statement continue-test)
     (beginning-of-line)
     (setq continue-test
-         (and
-          (not (looking-at fortran-comment-line-start-skip))
+          (and
+           (not (looking-at fortran-comment-line-start-skip))
            (not (looking-at fortran-directive-re))
-          (or (looking-at
-               (concat "[ \t]*"
-                       (regexp-quote fortran-continuation-string)))
-              (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))))
+           (or (looking-at
+                (concat "[ \t]*"
+                        (regexp-quote fortran-continuation-string)))
+               (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))))
     (while (and (setq not-first-statement (zerop (forward-line -1)))
-               (or (looking-at fortran-comment-line-start-skip)
+                (or (looking-at fortran-comment-line-start-skip)
                     (looking-at fortran-directive-re)
                     (looking-at
                      (concat "[ \t]*"
                              (regexp-quote fortran-continuation-string)))
-                   (looking-at "[ \t]*$\\| \\{5\\}[^ 0\n]\\|\t[1-9]")
-                   (looking-at (concat "[ \t]*" comment-start-skip)))))
+                    (looking-at "[ \t]*$\\| \\{5\\}[^ 0\n]\\|\t[1-9]")
+                    (looking-at (concat "[ \t]*" comment-start-skip)))))
     (cond ((and continue-test
-               (not not-first-statement))
-          (message "Incomplete continuation statement."))
-         (continue-test
-          (fortran-previous-statement))
-         ((not not-first-statement)
-          'first-statement))))
+                (not not-first-statement))
+           (message "Incomplete continuation statement."))
+          (continue-test
+           (fortran-previous-statement))
+          ((not not-first-statement)
+           'first-statement))))
 
 (defun fortran-next-statement ()
   "Move point to beginning of the next Fortran statement.
@@ -1208,14 +1267,14 @@ Directive lines are treated as comments."
   (let (not-last-statement)
     (beginning-of-line)
     (while (and (setq not-last-statement
-                     (and (zerop (forward-line 1))
-                          (not (eobp))))
-               (or (looking-at fortran-comment-line-start-skip)
+                      (and (zerop (forward-line 1))
+                           (not (eobp))))
+                (or (looking-at fortran-comment-line-start-skip)
                     (looking-at fortran-directive-re)
-                   (looking-at "[ \t]*$\\|     [^ 0\n]\\|\t[1-9]")
-                   (looking-at (concat "[ \t]*" comment-start-skip)))))
+                    (looking-at "[ \t]*$\\|     [^ 0\n]\\|\t[1-9]")
+                    (looking-at (concat "[ \t]*" comment-start-skip)))))
     (if (not not-last-statement)
-       'last-statement)))
+        'last-statement)))
 
 (defun fortran-looking-at-if-then ()
   "Return non-nil if at the start of a line with an IF ... THEN statement."
@@ -1236,7 +1295,7 @@ If NUM is negative, go backward to the start of a block.  Does
 not check for consistency of block types.  Interactively, pushes
 mark before moving point."
   (interactive "p")
-  (if (interactive-p) (push-mark (point) t))
+  (if (called-interactively-p 'interactive) (push-mark (point) t))
   (and num (< num 0) (fortran-beginning-of-block (- num)))
   (let ((case-fold-search t)
         (count (or num 1)))
@@ -1269,7 +1328,7 @@ blocks.  If NUM is negative, go forward to the end of a block.
 Does not check for consistency of block types.  Interactively,
 pushes mark before moving point."
   (interactive "p")
-  (if (interactive-p) (push-mark (point) t))
+  (if (called-interactively-p 'interactive) (push-mark (point) t))
   (and num (< num 0) (fortran-end-of-block (- num)))
   (let ((case-fold-search t)
         (count (or num 1)))
@@ -1300,10 +1359,10 @@ pushes mark before moving point."
   "From a line matching REGEX, blink matching KEYWORD statement line.
 Use function FIND-BEGIN to match it."
   (let ((top-of-window (window-start))
-       (end-point (point))
-       (case-fold-search t)
-       matching
-       message)
+        (end-point (point))
+        (case-fold-search t)
+        matching
+        message)
     (when (save-excursion
             (beginning-of-line)
             (skip-chars-forward " \t0-9")
@@ -1327,7 +1386,7 @@ Use function FIND-BEGIN to match it."
 (defun fortran-blink-matching-if ()
   "From an ENDIF or ELSE statement, blink the matching IF statement."
   (fortran-blink-match "e\\(nd[ \t]*if\\|lse\\([ \t]*if\\)?\\)\\b"
-                      "if" #'fortran-beginning-if))
+                       "if" #'fortran-beginning-if))
 
 (defun fortran-blink-matching-do ()
   "From an ENDDO statement, blink the matching DO or DO WHILE statement."
@@ -1350,27 +1409,27 @@ The marks are pushed."
 Return point or nil."
   (let ((case-fold-search t))
     (if (save-excursion (beginning-of-line)
-                       (skip-chars-forward " \t0-9")
-                       (looking-at "end[ \t]*do\\b"))
-       ;; Sitting on one.
-       (match-beginning 0)
+                        (skip-chars-forward " \t0-9")
+                        (looking-at "end[ \t]*do\\b"))
+        ;; Sitting on one.
+        (match-beginning 0)
       ;; Search for one.
       (save-excursion
-       (let ((count 1))
-         (while (and (not (zerop count))
-                     (not (eq (fortran-next-statement) 'last-statement))
-                     ;; Keep local to subprogram.
-                     (not (and (looking-at fortran-end-prog-re)
-                               (fortran-check-end-prog-re))))
-           (skip-chars-forward " \t0-9")
-           (cond ((looking-at "end[ \t]*do\\b")
-                  (setq count (1- count)))
-                 ((looking-at
-                   "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]")
-                  (setq count (1+ count)))))
-         (and (zerop count)
-              ;; All pairs accounted for.
-              (point)))))))
+        (let ((count 1))
+          (while (and (not (zerop count))
+                      (not (eq (fortran-next-statement) 'last-statement))
+                      ;; Keep local to subprogram.
+                      (not (and (looking-at fortran-end-prog-re)
+                                (fortran-check-end-prog-re))))
+            (skip-chars-forward " \t0-9")
+            (cond ((looking-at "end[ \t]*do\\b")
+                   (setq count (1- count)))
+                  ((looking-at
+                    "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]")
+                   (setq count (1+ count)))))
+          (and (zerop count)
+               ;; All pairs accounted for.
+               (point)))))))
 
 (defun fortran-beginning-do ()
   "Search backwards for first unmatched DO [WHILE].
@@ -1378,28 +1437,28 @@ Return point or nil.  Ignores labelled DO loops (ie DO 10 ... 10 CONTINUE)."
   (let ((case-fold-search t)
         (dostart-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]"))
     (if (save-excursion
-         (beginning-of-line)
-         (skip-chars-forward " \t0-9")
-         (looking-at dostart-re))
-       ;; Sitting on one.
-       (match-beginning 0)
+          (beginning-of-line)
+          (skip-chars-forward " \t0-9")
+          (looking-at dostart-re))
+        ;; Sitting on one.
+        (match-beginning 0)
       ;; Search for one.
       (save-excursion
-       (let ((count 1))
-         (while (and (not (zerop count))
-                     (not (eq (fortran-previous-statement) 'first-statement))
-                     ;; Keep local to subprogram.
-                     (not (and (looking-at fortran-end-prog-re)
-                               (fortran-check-end-prog-re))))
-           (skip-chars-forward " \t0-9")
-           (cond ((looking-at dostart-re)
-                  (setq count (1- count)))
+        (let ((count 1))
+          (while (and (not (zerop count))
+                      (not (eq (fortran-previous-statement) 'first-statement))
+                      ;; Keep local to subprogram.
+                      (not (and (looking-at fortran-end-prog-re)
+                                (fortran-check-end-prog-re))))
+            (skip-chars-forward " \t0-9")
+            (cond ((looking-at dostart-re)
+                   (setq count (1- count)))
                   ;; Note labelled loop ends not considered.
-                 ((looking-at "end[ \t]*do\\b")
-                  (setq count (1+ count)))))
-         (and (zerop count)
-              ;; All pairs accounted for.
-              (point)))))))
+                  ((looking-at "end[ \t]*do\\b")
+                   (setq count (1+ count)))))
+          (and (zerop count)
+               ;; All pairs accounted for.
+               (point)))))))
 
 (defun fortran-mark-if ()
   "Put mark at end of Fortran IF-ENDIF construct, point at beginning.
@@ -1419,103 +1478,103 @@ The marks are pushed."
 Return point or nil."
   (let ((case-fold-search t))
     (if (save-excursion (beginning-of-line)
-                       (skip-chars-forward " \t0-9")
-                       (looking-at "end[ \t]*if\\b"))
-       ;; Sitting on one.
-       (match-beginning 0)
+                        (skip-chars-forward " \t0-9")
+                        (looking-at "end[ \t]*if\\b"))
+        ;; Sitting on one.
+        (match-beginning 0)
       ;; Search for one.  The point has been already been moved to first
       ;; letter on line but this should not cause troubles.
       (save-excursion
-       (let ((count 1))
-         (while (and (not (zerop count))
-                     (not (eq (fortran-next-statement) 'last-statement))
-                     ;; Keep local to subprogram.
-                     (not (and (looking-at fortran-end-prog-re)
-                               (fortran-check-end-prog-re))))
-           (skip-chars-forward " \t0-9")
-           (cond ((looking-at "end[ \t]*if\\b")
-                  (setq count (1- count)))
-                 ((looking-at fortran-if-start-re)
-                  (save-excursion
-                    (if (or
-                         (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
-                         (let (then-test) ; multi-line if-then
-                           (while
-                               (and
-                                (zerop (forward-line 1))
-                                ;; Search forward for then.
-                                (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
-                                (not
-                                 (setq then-test
-                                       (looking-at
-                                        ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
-                           then-test))
-                        (setq count (1+ count)))))))
-         (and (zerop count)
-              ;; All pairs accounted for.
-              (point)))))))
+        (let ((count 1))
+          (while (and (not (zerop count))
+                      (not (eq (fortran-next-statement) 'last-statement))
+                      ;; Keep local to subprogram.
+                      (not (and (looking-at fortran-end-prog-re)
+                                (fortran-check-end-prog-re))))
+            (skip-chars-forward " \t0-9")
+            (cond ((looking-at "end[ \t]*if\\b")
+                   (setq count (1- count)))
+                  ((looking-at fortran-if-start-re)
+                   (save-excursion
+                     (if (or
+                          (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
+                          (let (then-test) ; multi-line if-then
+                            (while
+                                (and
+                                 (zerop (forward-line 1))
+                                 ;; Search forward for then.
+                                 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
+                                 (not
+                                  (setq then-test
+                                        (looking-at
+                                         ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
+                            then-test))
+                         (setq count (1+ count)))))))
+          (and (zerop count)
+               ;; All pairs accounted for.
+               (point)))))))
 
 (defun fortran-beginning-if ()
   "Search backwards for first unmatched IF-THEN.
 Return point or nil."
   (let ((case-fold-search t))
     (if (save-excursion
-         ;; May be sitting on multi-line if-then statement, first
-         ;; move to beginning of current statement.  Note:
-         ;; `fortran-previous-statement' moves to previous statement
-         ;; *unless* current statement is first one.  Only move
-         ;; forward if not first-statement.
-         (if (not (eq (fortran-previous-statement) 'first-statement))
-             (fortran-next-statement))
-         (skip-chars-forward " \t0-9")
-         (and
-          (looking-at fortran-if-start-re)
-          (save-match-data
-            (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
-                ;; Multi-line if-then.
-                (let (then-test)
-                  (while
+          ;; May be sitting on multi-line if-then statement, first
+          ;; move to beginning of current statement.  Note:
+          ;; `fortran-previous-statement' moves to previous statement
+          ;; *unless* current statement is first one.  Only move
+          ;; forward if not first-statement.
+          (if (not (eq (fortran-previous-statement) 'first-statement))
+              (fortran-next-statement))
+          (skip-chars-forward " \t0-9")
+          (and
+           (looking-at fortran-if-start-re)
+           (save-match-data
+             (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
+                 ;; Multi-line if-then.
+                 (let (then-test)
+                   (while
                        (and (zerop (forward-line 1))
-                           ;; Search forward for then.
-                           (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
-                           (not
-                            (setq then-test
-                                  (looking-at
-                                   ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
-                  then-test)))))
-       ;; Sitting on one.
-       (match-beginning 0)
+                            ;; Search forward for then.
+                            (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
+                            (not
+                             (setq then-test
+                                   (looking-at
+                                    ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
+                   then-test)))))
+        ;; Sitting on one.
+        (match-beginning 0)
       ;; Search for one.
       (save-excursion
-       (let ((count 1))
-         (while (and (not (zerop count))
-                     (not (eq (fortran-previous-statement) 'first-statement))
-                     ;; Keep local to subprogram.
-                     (not (and (looking-at fortran-end-prog-re)
-                               (fortran-check-end-prog-re))))
-           (skip-chars-forward " \t0-9")
-           (cond ((looking-at fortran-if-start-re)
-                  (save-excursion
-                    (if (or
-                         (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
-                         (let (then-test) ; multi-line if-then
-                           (while
-                               (and
-                                (zerop (forward-line 1))
-                                ;; Search forward for then.
-                                (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
-                                (not
-                                 (setq then-test
-                                       (looking-at
-                                        (concat ".*then\\b[ \t]*"
-                                                "[^ \t(=a-z0-9]"))))))
-                           then-test))
-                        (setq count (1- count)))))
-                 ((looking-at "end[ \t]*if\\b")
-                  (setq count (1+ count)))))
-         (and (zerop count)
-              ;; All pairs accounted for.
-              (point)))))))
+        (let ((count 1))
+          (while (and (not (zerop count))
+                      (not (eq (fortran-previous-statement) 'first-statement))
+                      ;; Keep local to subprogram.
+                      (not (and (looking-at fortran-end-prog-re)
+                                (fortran-check-end-prog-re))))
+            (skip-chars-forward " \t0-9")
+            (cond ((looking-at fortran-if-start-re)
+                   (save-excursion
+                     (if (or
+                          (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
+                          (let (then-test) ; multi-line if-then
+                            (while
+                                (and
+                                 (zerop (forward-line 1))
+                                 ;; Search forward for then.
+                                 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
+                                 (not
+                                  (setq then-test
+                                        (looking-at
+                                         (concat ".*then\\b[ \t]*"
+                                                 "[^ \t(=a-z0-9]"))))))
+                            then-test))
+                         (setq count (1- count)))))
+                  ((looking-at "end[ \t]*if\\b")
+                   (setq count (1+ count)))))
+          (and (zerop count)
+               ;; All pairs accounted for.
+               (point)))))))
 
 \f
 (defun fortran-indent-line ()
@@ -1525,15 +1584,15 @@ Return point or nil."
     (save-excursion
       (beginning-of-line)
       (if (or (not (= cfi (fortran-current-line-indentation)))
-             (and (re-search-forward "^[ \t]*[0-9]+" (+ (point) 4) t)
-                  (not (fortran-line-number-indented-correctly-p))))
-         (fortran-indent-to-column cfi)
-       (beginning-of-line)
-       (if (fortran-find-comment-start-skip)
-           (fortran-indent-comment))))
+              (and (re-search-forward "^[ \t]*[0-9]+" (+ (point) 4) t)
+                   (not (fortran-line-number-indented-correctly-p))))
+          (fortran-indent-to-column cfi)
+        (beginning-of-line)
+        (if (fortran-find-comment-start-skip)
+            (fortran-indent-comment))))
     ;; Never leave point in left margin.
     (if (< (current-column) cfi)
-       (move-to-column cfi))
+        (move-to-column cfi))
     (and auto-fill-function
          (> (save-excursion (end-of-line) (current-column))
             fill-column)
@@ -1548,20 +1607,20 @@ Return point or nil."
   "Function to use for `normal-auto-fill-function' in Fortran mode."
   (if (> (current-column) (current-fill-column))
       (let ((cfi (fortran-calculate-indent)))
-       (save-excursion
-         (beginning-of-line)
-         (if (or (not (= cfi (fortran-current-line-indentation)))
-                 (and (re-search-forward "^[ \t]*[0-9]+"
-                                         (+ (point) 4) t)
-                      (not (fortran-line-number-indented-correctly-p))))
-             (fortran-indent-to-column cfi)
-           (beginning-of-line)
-           (if (fortran-find-comment-start-skip)
-               (fortran-indent-comment))))
-       (fortran-fill)
-       ;; Never leave point in left margin.
-       (if (< (current-column) cfi)
-           (move-to-column cfi)))))
+        (save-excursion
+          (beginning-of-line)
+          (if (or (not (= cfi (fortran-current-line-indentation)))
+                  (and (re-search-forward "^[ \t]*[0-9]+"
+                                          (+ (point) 4) t)
+                       (not (fortran-line-number-indented-correctly-p))))
+              (fortran-indent-to-column cfi)
+            (beginning-of-line)
+            (if (fortran-find-comment-start-skip)
+                (fortran-indent-comment))))
+        (fortran-fill)
+        ;; Never leave point in left margin.
+        (if (< (current-column) cfi)
+            (move-to-column cfi)))))
 
 ;; Historically this was a separate function which advertised itself
 ;; as reindenting but only did so where `most likely to be necessary'.
@@ -1579,21 +1638,21 @@ Return point or nil."
 (defun fortran-calculate-indent ()
   "Calculates the Fortran indent column based on previous lines."
   (let (icol first-statement (case-fold-search t)
-            (fortran-minimum-statement-indent
-             (if indent-tabs-mode
-                 fortran-minimum-statement-indent-tab
-               fortran-minimum-statement-indent-fixed)))
+             (fortran-minimum-statement-indent
+              (if indent-tabs-mode
+                  fortran-minimum-statement-indent-tab
+                fortran-minimum-statement-indent-fixed)))
     (save-excursion
       (setq first-statement (fortran-previous-statement))
       (if first-statement
-         (setq icol fortran-minimum-statement-indent)
+          (setq icol fortran-minimum-statement-indent)
         (if (= (point) (point-min))
             (setq icol fortran-minimum-statement-indent)
           (setq icol (fortran-current-line-indentation)))
         (skip-chars-forward " \t0-9")
         (cond ((looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(")
                (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t_$(=a-z0-9]")
-                       (let (then-test)        ; multi-line if-then
+                       (let (then-test) ; multi-line if-then
                          (while (and (zerop (forward-line 1))
                                      ;; Search forward for then.
                                      (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
@@ -1624,57 +1683,71 @@ Return point or nil."
               ((and (looking-at fortran-end-prog-re1)
                     (fortran-check-end-prog-re))
                ;; Previous END resets indent to minimum.
-               (setq icol fortran-minimum-statement-indent)))))
+               (setq icol fortran-minimum-statement-indent))
+              ;; Previous statement was a numbered DO loop without a
+              ;; closing CONTINUE or END DO, so we indented the
+              ;; terminator like the loop body.
+              ((and fortran-check-all-num-for-matching-do
+                    (not (looking-at "\\(continue\\|end[ \t]*do\\)\\>"))
+                    (progn
+                      (beginning-of-line)
+                      (and (looking-at "[ \t]*[0-9]+")
+                           (fortran-check-for-matching-do))))
+               (setq icol (- icol fortran-do-indent))))))
     (save-excursion
       (beginning-of-line)
       (cond ((looking-at "[ \t]*$"))
             ;; Check for directive before comment, so as not to indent.
-           ((looking-at fortran-directive-re)
-            (setq fortran-minimum-statement-indent 0 icol 0))
-           ((looking-at fortran-comment-line-start-skip)
-            (cond ((eq fortran-comment-indent-style 'relative)
-                   (setq icol (+ icol fortran-comment-line-extra-indent)))
-                  ((eq fortran-comment-indent-style 'fixed)
-                   (setq icol (+ fortran-minimum-statement-indent
-                                 fortran-comment-line-extra-indent))))
-            (setq fortran-minimum-statement-indent 0))
-           ((or (looking-at (concat "[ \t]*"
-                                    (regexp-quote
-                                     fortran-continuation-string)))
-                (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
+            ((looking-at fortran-directive-re)
+             (setq fortran-minimum-statement-indent 0 icol 0))
+            ((looking-at fortran-comment-line-start-skip)
+             (cond ((eq fortran-comment-indent-style 'relative)
+                    (setq icol (+ icol fortran-comment-line-extra-indent)))
+                   ((eq fortran-comment-indent-style 'fixed)
+                    (setq icol (+ fortran-minimum-statement-indent
+                                  fortran-comment-line-extra-indent))))
+             (setq fortran-minimum-statement-indent 0))
+            ((or (looking-at (concat "[ \t]*"
+                                     (regexp-quote
+                                      fortran-continuation-string)))
+                 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
              (skip-chars-forward " \t")
              ;; Do not introduce extra whitespace into a broken string.
              (setq icol
                    (if (fortran-is-in-string-p (point))
                        6
                      (+ icol fortran-continuation-indent))))
-           (first-statement)
-           ((and fortran-check-all-num-for-matching-do
-                 (looking-at "[ \t]*[0-9]+")
-                 (fortran-check-for-matching-do))
-            (setq icol (- icol fortran-do-indent)))
-           (t
-            (skip-chars-forward " \t0-9")
-            (cond ((looking-at "end[ \t]*\\(if\\|select\\|where\\)\\b")
-                   (setq icol (- icol fortran-if-indent)))
-                  ((looking-at "else\\(if\\)?\\b")
-                   (setq icol (- icol fortran-if-indent)))
+            (first-statement)
+            ;; The terminating statement is actually part of the
+            ;; loop body, so unless it is a CONTINUE or END DO, we
+            ;; indent it like the loop body (see above).
+            ((and fortran-check-all-num-for-matching-do
+                  (looking-at "[ \t]*[0-9]+[ \t]*\
+\\(continue\\|end[ \t]*do\\)\\>")
+                  (fortran-check-for-matching-do))
+             (setq icol (- icol fortran-do-indent)))
+            (t
+             (skip-chars-forward " \t0-9")
+             (cond ((looking-at "end[ \t]*\\(if\\|select\\|where\\)\\b")
+                    (setq icol (- icol fortran-if-indent)))
+                   ((looking-at "else\\(if\\)?\\b")
+                    (setq icol (- icol fortran-if-indent)))
                    ((looking-at "case[ \t]*\\((.*)\\|default\\>\\)")
-                   (setq icol (- icol fortran-if-indent)))
-                  ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
-                   (setq icol (- icol fortran-if-indent)))
-                  ((and (looking-at "continue\\b")
-                        (fortran-check-for-matching-do))
-                   (setq icol (- icol fortran-do-indent)))
-                  ((looking-at "end[ \t]*do\\b")
-                   (setq icol (- icol fortran-do-indent)))
-                  ((looking-at "end[ \t]*\
+                    (setq icol (- icol fortran-if-indent)))
+                   ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
+                    (setq icol (- icol fortran-if-indent)))
+                   ((and (looking-at "continue\\b")
+                         (fortran-check-for-matching-do))
+                    (setq icol (- icol fortran-do-indent)))
+                   ((looking-at "end[ \t]*do\\b")
+                    (setq icol (- icol fortran-do-indent)))
+                   ((looking-at "end[ \t]*\
 \\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]")
-                   (setq icol (- icol fortran-structure-indent)))
-                  ((and (looking-at fortran-end-prog-re1)
-                        (fortran-check-end-prog-re)
-                        (not (= icol fortran-minimum-statement-indent)))
-                   (message "Warning: `end' not in column %d.  Probably\
+                    (setq icol (- icol fortran-structure-indent)))
+                   ((and (looking-at fortran-end-prog-re1)
+                         (fortran-check-end-prog-re)
+                         (not (= icol fortran-minimum-statement-indent)))
+                    (message "Warning: `end' not in column %d.  Probably\
  an unclosed block." fortran-minimum-statement-indent))))))
     (max fortran-minimum-statement-indent icol)))
 
@@ -1688,16 +1761,16 @@ non-indentation text within the comment."
   (save-excursion
     (beginning-of-line)
     (cond ((looking-at fortran-comment-line-start-skip)
-          (goto-char (match-end 0))
-          (skip-chars-forward
-           (if (stringp fortran-comment-indent-char)
-               fortran-comment-indent-char
-             (char-to-string fortran-comment-indent-char))))
-         ((or (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
-          (goto-char (match-end 0)))
-         (t
-          ;; Move past line number.
-          (skip-chars-forward "[ \t0-9]")))
+           (goto-char (match-end 0))
+           (skip-chars-forward
+            (if (stringp fortran-comment-indent-char)
+                fortran-comment-indent-char
+              (char-to-string fortran-comment-indent-char))))
+          ((or (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
+           (goto-char (match-end 0)))
+          (t
+           ;; Move past line number.
+           (skip-chars-forward "[ \t0-9]")))
     ;; Move past whitespace.
     (skip-chars-forward " \t")
     (current-column)))
@@ -1714,48 +1787,48 @@ notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
   (save-excursion
     (beginning-of-line)
     (if (looking-at fortran-comment-line-start-skip)
-       (if fortran-comment-indent-style
-           (let* ((char (if (stringp fortran-comment-indent-char)
-                            (aref fortran-comment-indent-char 0)
-                          fortran-comment-indent-char))
-                  (chars (string ?\s ?\t char)))
-             (goto-char (match-end 0))
-             (skip-chars-backward chars)
-             (delete-region (point) (progn (skip-chars-forward chars)
-                                           (point)))
-             (insert-char char (- col (current-column)))))
+        (if fortran-comment-indent-style
+            (let* ((char (if (stringp fortran-comment-indent-char)
+                             (aref fortran-comment-indent-char 0)
+                           fortran-comment-indent-char))
+                   (chars (string ?\s ?\t char)))
+              (goto-char (match-end 0))
+              (skip-chars-backward chars)
+              (delete-region (point) (progn (skip-chars-forward chars)
+                                            (point)))
+              (insert-char char (- col (current-column)))))
       (if (looking-at "\t[1-9]")
-         (if indent-tabs-mode
-             (goto-char (match-end 0))
-           (delete-char 2)
-           (insert-char ?\s 5)
-           (insert fortran-continuation-string))
-       (if (looking-at " \\{5\\}[^ 0\n]")
-           (if indent-tabs-mode
-               (progn (delete-char 6)
-                      (insert ?\t (fortran-numerical-continuation-char) 1))
-             (forward-char 6))
-         (delete-horizontal-space)
-         ;; Put line number in columns 0-4, or
+          (if indent-tabs-mode
+              (goto-char (match-end 0))
+            (delete-char 2)
+            (insert-char ?\s 5)
+            (insert fortran-continuation-string))
+        (if (looking-at " \\{5\\}[^ 0\n]")
+            (if indent-tabs-mode
+                (progn (delete-char 6)
+                       (insert ?\t (fortran-numerical-continuation-char) 1))
+              (forward-char 6))
+          (delete-horizontal-space)
+          ;; Put line number in columns 0-4, or
           ;; continuation character in column 5.
-         (cond ((eobp))
-               ((looking-at (regexp-quote fortran-continuation-string))
-                (if indent-tabs-mode
-                    (progn
-                      (indent-to
-                       (if indent-tabs-mode
-                           fortran-minimum-statement-indent-tab
-                         fortran-minimum-statement-indent-fixed))
-                      (delete-char 1)
-                      (insert-char (fortran-numerical-continuation-char) 1))
-                  (indent-to 5)
-                  (forward-char 1)))
-               ((looking-at "[0-9]+")
-                (let ((extra-space (- 5 (- (match-end 0) (point)))))
-                  (if (< extra-space 0)
-                      (message "Warning: line number exceeds 5-digit limit.")
-                    (indent-to (min fortran-line-number-indent extra-space))))
-                (skip-chars-forward "0-9")))))
+          (cond ((eobp))
+                ((looking-at (regexp-quote fortran-continuation-string))
+                 (if indent-tabs-mode
+                     (progn
+                       (indent-to
+                        (if indent-tabs-mode
+                            fortran-minimum-statement-indent-tab
+                          fortran-minimum-statement-indent-fixed))
+                       (delete-char 1)
+                       (insert-char (fortran-numerical-continuation-char) 1))
+                   (indent-to 5)
+                   (forward-char 1)))
+                ((looking-at "[0-9]+")
+                 (let ((extra-space (- 5 (- (match-end 0) (point)))))
+                   (if (< extra-space 0)
+                       (message "Warning: line number exceeds 5-digit limit.")
+                     (indent-to (min fortran-line-number-indent extra-space))))
+                 (skip-chars-forward "0-9")))))
       ;; Point is now after any continuation character or line number.
       ;; Put body of statement where specified.
       (delete-horizontal-space)
@@ -1774,20 +1847,20 @@ Do not call if there is no line number."
     (beginning-of-line)
     (skip-chars-forward " \t")
     (and (<= (current-column) fortran-line-number-indent)
-        (or (= (current-column) fortran-line-number-indent)
-            (progn (skip-chars-forward "0-9")
-                   (= (current-column) 5))))))
+         (or (= (current-column) fortran-line-number-indent)
+             (progn (skip-chars-forward "0-9")
+                    (= (current-column) 5))))))
 
 (defun fortran-check-for-matching-do ()
   "When called from a numbered statement, return t if matching DO is found.
 Otherwise return nil."
   (let ((case-fold-search t)
-       charnum)
+        charnum)
     (save-excursion
       (beginning-of-line)
       (when (looking-at "[ \t]*[0-9]+")
         (skip-chars-forward " \t")
-        (skip-chars-forward "0")       ; skip past leading zeros
+        (skip-chars-forward "0")        ; skip past leading zeros
         (setq charnum
               (buffer-substring (point) (progn
                                           (skip-chars-forward "0-9")
@@ -1814,78 +1887,78 @@ If ALL is nil, only match comments that start in column > 0."
   ;; (comment-search-forward (line-end-position) t))
   (when (or all comment-start-skip)
     (let ((pos (point))
-         (css (if comment-start-skip
-                  (concat fortran-comment-line-start-skip
-                          "\\|" comment-start-skip)
-                fortran-comment-line-start-skip)))
+          (css (if comment-start-skip
+                   (concat fortran-comment-line-start-skip
+                           "\\|" comment-start-skip)
+                 fortran-comment-line-start-skip)))
       (when (re-search-forward css (line-end-position) t)
-       (if (and (or all (> (match-beginning 0) (line-beginning-position)))
-                (or (save-match-data
-                      (not (fortran-is-in-string-p (match-beginning 0))))
-                    ;; Recurse for rest of line.
-                    (fortran-find-comment-start-skip all)))
-           (point)
-         (goto-char pos)
-         nil)))))
+        (if (and (or all (> (match-beginning 0) (line-beginning-position)))
+                 (or (save-match-data
+                       (not (fortran-is-in-string-p (match-beginning 0))))
+                     ;; Recurse for rest of line.
+                     (fortran-find-comment-start-skip all)))
+            (point)
+          (goto-char pos)
+          nil)))))
 
 ;; From: ralf@up3aud1.gwdg.de (Ralf Fassel)
 ;; Test if TAB format continuation lines work.
 (defun fortran-is-in-string-p (where)
-  "Return non-nil iff WHERE (a buffer position) is inside a Fortran string."
+  "Return non-nil if WHERE (a buffer position) is inside a Fortran string."
   (save-excursion
     (goto-char where)
     (cond
-     ((bolp) nil)                      ; bol is never inside a string
-     ((save-excursion                  ; comment lines too
-       (beginning-of-line)
-       (looking-at fortran-comment-line-start-skip)) nil)
+     ((bolp) nil)                       ; bol is never inside a string
+     ((save-excursion                   ; comment lines too
+        (beginning-of-line)
+        (looking-at fortran-comment-line-start-skip)) nil)
      (t (let ((parse-state '(0 nil nil nil nil nil 0))
-             (quoted-comment-start (if comment-start
-                                       (regexp-quote comment-start)))
-             (not-done t)
-             parse-limit end-of-line)
-         ;; Move to start of current statement.
-         (fortran-next-statement)
-         (fortran-previous-statement)
-         ;; Now parse up to WHERE.
-         (while not-done
-           (if (or ;; Skip to next line if:
-                ;; - comment line?
-                (looking-at fortran-comment-line-start-skip)
-                ;; - at end of line?
-                (eolp)
-                ;; - not in a string and after comment-start?
-                (and (not (nth 3 parse-state))
-                     comment-start
-                     (equal comment-start
-                            (char-to-string (preceding-char)))))
-               (if (> (forward-line) 0)
-                   (setq not-done nil))
-             ;; else:
-             ;; If we are at beginning of code line, skip any
-             ;; whitespace, labels and tab continuation markers.
-             (if (bolp) (skip-chars-forward " \t0-9"))
-             ;; If we are in column <= 5 now, check for continuation char.
-             (cond ((= 5 (current-column)) (forward-char 1))
-                   ((and (< (current-column) 5)
-                         (equal fortran-continuation-string
-                                (char-to-string (following-char)))
-                         (forward-char 1))))
-             ;; Find out parse-limit from here.
-             (setq end-of-line (line-end-position))
-             (setq parse-limit (min where end-of-line))
-             ;; Parse max up to comment-start, if non-nil and in current line.
-             (if comment-start
-                 (save-excursion
-                   (if (re-search-forward quoted-comment-start end-of-line t)
-                       (setq parse-limit (min (point) parse-limit)))))
-             ;; Now parse if still in limits.
-             (if (< (point) where)
-                 (setq parse-state (parse-partial-sexp
-                                    (point) parse-limit nil nil parse-state))
-               (setq not-done nil))))
-         ;; Result.
-         (nth 3 parse-state))))))
+              (quoted-comment-start (if comment-start
+                                        (regexp-quote comment-start)))
+              (not-done t)
+              parse-limit end-of-line)
+          ;; Move to start of current statement.
+          (fortran-next-statement)
+          (fortran-previous-statement)
+          ;; Now parse up to WHERE.
+          (while not-done
+            (if (or ;; Skip to next line if:
+                 ;; - comment line?
+                 (looking-at fortran-comment-line-start-skip)
+                 ;; - at end of line?
+                 (eolp)
+                 ;; - not in a string and after comment-start?
+                 (and (not (nth 3 parse-state))
+                      comment-start
+                      (equal comment-start
+                             (char-to-string (preceding-char)))))
+                (if (> (forward-line) 0)
+                    (setq not-done nil))
+              ;; else:
+              ;; If we are at beginning of code line, skip any
+              ;; whitespace, labels and tab continuation markers.
+              (if (bolp) (skip-chars-forward " \t0-9"))
+              ;; If we are in column <= 5 now, check for continuation char.
+              (cond ((= 5 (current-column)) (forward-char 1))
+                    ((and (< (current-column) 5)
+                          (equal fortran-continuation-string
+                                 (char-to-string (following-char)))
+                          (forward-char 1))))
+              ;; Find out parse-limit from here.
+              (setq end-of-line (line-end-position))
+              (setq parse-limit (min where end-of-line))
+              ;; Parse max up to comment-start, if non-nil and in current line.
+              (if comment-start
+                  (save-excursion
+                    (if (re-search-forward quoted-comment-start end-of-line t)
+                        (setq parse-limit (min (point) parse-limit)))))
+              ;; Now parse if still in limits.
+              (if (< (point) where)
+                  (setq parse-state (parse-partial-sexp
+                                     (point) parse-limit nil nil parse-state))
+                (setq not-done nil))))
+          ;; Result.
+          (nth 3 parse-state))))))
 
 ;; From old version.
 (defalias 'fortran-auto-fill-mode 'auto-fill-mode)
@@ -1893,17 +1966,17 @@ If ALL is nil, only match comments that start in column > 0."
 (defun fortran-fill ()
   "Fill the current line at an appropriate point(s)."
   (let* ((auto-fill-function #'fortran-auto-fill)
-        (opoint (point))
-        (bol (line-beginning-position))
-        (eol (line-end-position))
-        (bos (min eol (+ bol (fortran-current-line-indentation))))
+         (opoint (point))
+         (bol (line-beginning-position))
+         (eol (line-end-position))
+         (bos (min eol (+ bol (fortran-current-line-indentation))))
          ;; If in a string at fill-column, break it either before the
          ;; initial quote, or at fill-col (if string is too long).
-        (quote
-         (save-excursion
-           (goto-char bol)
-           ;; OK to break quotes on comment lines.
-           (unless (looking-at fortran-comment-line-start-skip)
+         (quote
+          (save-excursion
+            (goto-char bol)
+            ;; OK to break quotes on comment lines.
+            (unless (looking-at fortran-comment-line-start-skip)
               (let (fcpoint start)
                 (move-to-column fill-column)
                 (when (fortran-is-in-string-p (setq fcpoint (point)))
@@ -1922,12 +1995,12 @@ If ALL is nil, only match comments that start in column > 0."
                          (- fill-column 6 fortran-continuation-indent))
                       fcpoint
                     start))))))
-        ;; Decide where to split the line. If a position for a quoted
-        ;; string was found above then use that, else break the line
-        ;; before/after the last delimiter.
-        (fill-point
-         (or quote
-             (save-excursion
+         ;; Decide where to split the line. If a position for a quoted
+         ;; string was found above then use that, else break the line
+         ;; before/after the last delimiter.
+         (fill-point
+          (or quote
+              (save-excursion
                 ;; If f-b-b-d is t, have an extra column to play with,
                 ;; since delimiter gets shifted to new line.
                 (move-to-column (if fortran-break-before-delimiters
@@ -1951,13 +2024,13 @@ If ALL is nil, only match comments that start in column > 0."
                       (or (looking-at fortran-no-break-re)
                           (forward-char)))))
                 ;; Line indented beyond fill-column?
-               (when (<= (point) bos)
+                (when (<= (point) bos)
                   (move-to-column (1+ fill-column))
                   ;; What is this doing???
                   (or (re-search-forward "[\t\n,'+-/*)=]" eol t)
                       (goto-char bol)))
-               (if (bolp)
-                   (re-search-forward "[ \t]" opoint t))
+                (if (bolp)
+                    (re-search-forward "[ \t]" opoint t))
                 (point)))))
     ;; If we are in an in-line comment, don't break unless the
     ;; line of code is longer than it should be. Otherwise
@@ -1966,20 +2039,20 @@ If ALL is nil, only match comments that start in column > 0."
     ;; Need to use fortran-find-comment-start-skip to make sure that
     ;; quoted !'s don't prevent a break.
     (when (and (save-excursion
-                (beginning-of-line)
-                (if (not (fortran-find-comment-start-skip))
+                 (beginning-of-line)
+                 (if (not (fortran-find-comment-start-skip))
                      t
-                  (goto-char (match-beginning 0))
-                  (>= (point) fill-point)))
-              (save-excursion
-                (goto-char fill-point)
-                (not (bolp)))
-              (> (save-excursion
-                   (goto-char opoint)
-                   (current-column))
-                 (min (1+ fill-column)
-                      (+ (fortran-calculate-indent)
-                         fortran-continuation-indent))))
+                   (goto-char (match-beginning 0))
+                   (>= (point) fill-point)))
+               (save-excursion
+                 (goto-char fill-point)
+                 (not (bolp)))
+               (> (save-excursion
+                    (goto-char opoint)
+                    (current-column))
+                  (min (1+ fill-column)
+                       (+ (fortran-calculate-indent)
+                          fortran-continuation-indent))))
       (goto-char fill-point)
       (fortran-break-line)
       (end-of-line))))
@@ -1987,27 +2060,27 @@ If ALL is nil, only match comments that start in column > 0."
 (defun fortran-break-line ()
   "Call `fortran-split-line'.  Joins continuation lines first, then refills."
   (let ((bol (line-beginning-position))
-       (comment-string
-        (save-excursion
-          (if (fortran-find-comment-start-skip)
-              (delete-and-extract-region
-               (match-beginning 0) (line-end-position))))))
+        (comment-string
+         (save-excursion
+           (if (fortran-find-comment-start-skip)
+               (delete-and-extract-region
+                (match-beginning 0) (line-end-position))))))
     ;; Forward line 1 really needs to go to next non white line.
     (if (save-excursion (forward-line)
-                       (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
-       (progn
-         (end-of-line)
-         (delete-region (point) (match-end 0))
-         (delete-horizontal-space)
-         (fortran-fill))
+                        (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
+        (progn
+          (end-of-line)
+          (delete-region (point) (match-end 0))
+          (delete-horizontal-space)
+          (fortran-fill))
       (fortran-split-line))
     (if comment-string
-       (save-excursion
-         (goto-char bol)
-         (end-of-line)
-         (delete-horizontal-space)
-         (indent-to (fortran-comment-indent))
-         (insert comment-string)))))
+        (save-excursion
+          (goto-char bol)
+          (end-of-line)
+          (delete-horizontal-space)
+          (indent-to (fortran-comment-indent))
+          (insert comment-string)))))
 
 (defun fortran-analyze-file-format ()
   "Return nil if fixed format is used, t if TAB formatting is used.
@@ -2017,12 +2090,12 @@ before the end or in the first `fortran-analyze-depth' lines."
     (save-excursion
       (goto-char (point-min))
       (while (not (or
-                  (eobp)
-                  (eq (char-after) ?\t)
-                  (looking-at " \\{6\\}")
-                  (> i fortran-analyze-depth)))
-       (forward-line)
-       (setq i (1+ i)))
+                   (eobp)
+                   (eq (char-after) ?\t)
+                   (looking-at " \\{6\\}")
+                   (> i fortran-analyze-depth)))
+        (forward-line)
+        (setq i (1+ i)))
       (cond
        ((eq (char-after) ?\t) t)
        ((looking-at " \\{6\\}") nil)
@@ -2076,19 +2149,16 @@ arg DO-SPACE prevents stripping the whitespace."
       (replace-match "" nil nil nil 1)
       (unless do-space (delete-horizontal-space)))))
 
-;; This code used to live in add-log.el, but this is a better place
-;; for it.
+;; This code used to live in add-log.el, but this is a better place for it.
 (defun fortran-current-defun ()
   "Function to use for `add-log-current-defun-function' in Fortran mode."
   (save-excursion
     ;; We must be inside function body for this to work.
     (fortran-beginning-of-subprogram)
-    (let ((case-fold-search t))                ; case-insensitive
+    (let ((case-fold-search t))
       ;; Search for fortran subprogram start.
       (if (re-search-forward
-           (concat "^[ \t]*\\(program\\|subroutine\\|function"
-                   "\\|[ \ta-z0-9*()]*[ \t]+function\\|"
-                   "\\(block[ \t]*data\\)\\)")
+           fortran-start-prog-re
            (save-excursion (fortran-end-of-subprogram)
                            (point))
            t)