]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/fortran.el
Close bug#3992.
[gnu-emacs] / lisp / progmodes / fortran.el
index 0e7fd0ee051546f527ac7ef9127e6a654b462997..3784ba787c4fbae998fe6f8db5e51170256f7466 100644 (file)
@@ -1,7 +1,8 @@
 ;;; fortran.el --- Fortran mode for GNU Emacs
 
 ;; Copyright (C) 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
 ;;; fortran.el --- Fortran mode for GNU Emacs
 
 ;; Copyright (C) 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
-;;               2002, 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+;;   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
 ;; Author: Michael D. Prange <prange@erl.mit.edu>
 ;; Maintainer: Glenn Morris <rgm@gnu.org>
 
 ;; Author: Michael D. Prange <prange@erl.mit.edu>
 ;; Maintainer: Glenn Morris <rgm@gnu.org>
 
 ;; This file is part of GNU Emacs.
 
 
 ;; 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
 ;; 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
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +21,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
 ;; 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:
 
 
 ;;; Commentary:
 
 
 ;; silence compiler
 (defvar dabbrev-case-fold-search)
 
 ;; 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 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."
 
 (defgroup fortran nil
   "Major mode for editing fixed format Fortran code."
   :group  'fortran)
 
 
   :group  'fortran)
 
 
-;;;###autoload
 (defcustom fortran-tab-mode-default nil
 (defcustom fortran-tab-mode-default nil
-  "*Default tabbing/carriage control style for empty files in Fortran mode.
+  "Default tabbing/carriage control style for empty files in Fortran mode.
 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
 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)
   :group 'fortran-indent)
-(put 'fortran-tab-mode-default 'safe-local-variable 'booleanp)
 
 
-(defcustom fortran-tab-mode-string "/t"
-  "*String to appear in mode line in TAB format buffers."
+;; TODO add more detail of what tab mode is to doc string.
+(defcustom fortran-tab-mode-string
+  (propertize "/t" 'help-echo "This buffer is in Fortran TAB mode"
+              'mouse-face 'mode-line-highlight
+              'local-map
+              (make-mode-line-mouse-map 'mouse-1
+                                        (lambda ()
+                                          (interactive)
+                                          (describe-variable
+                                           'fortran-tab-mode-string))))
+  "String to appear in mode line in TAB format buffers.
+See Info node `(emacs)ForIndent Cont'."
   :type  'string
   :type  'string
+  :risky t
   :group 'fortran-indent)
   :group 'fortran-indent)
-(put 'fortran-tab-mode-string 'safe-local-variable 'stringp)
 
 (defcustom fortran-do-indent 3
 
 (defcustom fortran-do-indent 3
-  "*Extra indentation applied to DO blocks."
+  "Extra indentation applied to DO blocks."
   :type  'integer
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
   :group 'fortran-indent)
-(put 'fortran-do-indent 'safe-local-variable 'integerp)
 
 (defcustom fortran-if-indent 3
 
 (defcustom fortran-if-indent 3
-  "*Extra indentation applied to IF, SELECT CASE and WHERE blocks."
+  "Extra indentation applied to IF, SELECT CASE and WHERE blocks."
   :type  'integer
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
   :group 'fortran-indent)
-(put 'fortran-if-indent 'safe-local-variable 'integerp)
 
 (defcustom fortran-structure-indent 3
 
 (defcustom fortran-structure-indent 3
-  "*Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks."
+  "Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks."
   :type  'integer
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
   :group 'fortran-indent)
-(put 'fortran-structure-indent 'safe-local-variable 'integerp)
 
 (defcustom fortran-continuation-indent 5
 
 (defcustom fortran-continuation-indent 5
-  "*Extra indentation applied to continuation lines."
+  "Extra indentation applied to continuation lines."
   :type  'integer
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
   :group 'fortran-indent)
-(put 'fortran-continuation-indent 'safe-local-variable 'integerp)
 
 (defcustom fortran-comment-indent-style 'fixed
 
 (defcustom fortran-comment-indent-style 'fixed
-  "*How to indent comments.
+  "How to indent comments.
 nil forces comment lines not to be touched;
 `fixed' indents to `fortran-comment-line-extra-indent' columns beyond
   `fortran-minimum-statement-indent-fixed' (if `indent-tabs-mode' nil), or
 nil forces comment lines not to be touched;
 `fixed' indents to `fortran-comment-line-extra-indent' columns beyond
   `fortran-minimum-statement-indent-fixed' (if `indent-tabs-mode' nil), or
@@ -127,116 +135,113 @@ 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))
 `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)
   :group 'fortran-indent)
-(put 'fortran-comment-indent 'safe-local-variable
-     (lambda (value) (memq value '(nil fixed relative))))
 
 (defcustom fortran-comment-line-extra-indent 0
 
 (defcustom fortran-comment-line-extra-indent 0
-  "*Amount of extra indentation for text within full-line comments."
+  "Amount of extra indentation for text within full-line comments."
   :type  'integer
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent
   :group 'fortran-comment)
   :group 'fortran-indent
   :group 'fortran-comment)
-(put 'fortran-comment-line-extra-indent 'safe-local-variable 'integerp)
 
 (defcustom fortran-comment-line-start "C"
 
 (defcustom fortran-comment-line-start "C"
-  "*Delimiter inserted to start new full-line comment.
-You might want to change this to \"*\", for instance."
+  "Delimiter inserted to start new full-line comment.
+You might want to change this to \"*\", for instance; or \"!\" to
+allow trailing comments on a line."
   :version "21.1"
   :type    'string
   :version "21.1"
   :type    'string
+  :safe    'stringp
   :group   'fortran-comment)
   :group   'fortran-comment)
-(put 'fortran-comment-line-start 'safe-local-variable 'stringp)
 
 ;; 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]*"
 
 ;; 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
   :version "21.1"
   :type    'regexp
+  :safe    'stringp
   :group   'fortran-comment)
   :group   'fortran-comment)
-(put 'fortran-comment-line-start-skip 'safe-local-variable 'stringp)
 
 (defcustom fortran-directive-re
   "^[ \t]*#.*"
 
 (defcustom fortran-directive-re
   "^[ \t]*#.*"
-  "*Regexp to match a directive line.
+  "Regexp to match a directive line.
 The matching text will be fontified with `font-lock-keyword-face'.
 The matching line will be given zero indentation."
   :version "22.1"
   :type    'regexp
 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)
   :group   'fortran-indent)
-(put 'fortran-directive-re 'safe-local-variable 'stringp)
 
 (defcustom fortran-minimum-statement-indent-fixed 6
 
 (defcustom fortran-minimum-statement-indent-fixed 6
-  "*Minimum statement indentation for fixed format continuation style."
+  "Minimum statement indentation for fixed format continuation style."
   :type  'integer
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
   :group 'fortran-indent)
-(put 'fortran-minimum-statement-indent-fixed 'safe-local-variable 'integerp)
 
 (defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
 
 (defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
-  "*Minimum statement indentation for TAB format continuation style."
+  "Minimum statement indentation for TAB format continuation style."
   :type  'integer
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
   :group 'fortran-indent)
-(put 'fortran-minimum-statement-indent-tab 'safe-local-variable 'integerp)
 
 ;; Note that this is documented in the v18 manuals as being a string
 ;; of length one rather than a single character.
 ;; The code in this file accepts either format for compatibility.
 (defcustom fortran-comment-indent-char " "
 
 ;; Note that this is documented in the v18 manuals as being a string
 ;; of length one rather than a single character.
 ;; The code in this file accepts either format for compatibility.
 (defcustom fortran-comment-indent-char " "
-  "*Single-character string inserted for Fortran comment indentation.
+  "Single-character string inserted for Fortran comment indentation.
 Normally a space."
   :type  'string
 Normally a space."
   :type  'string
+  :safe  (lambda (value) (or (characterp value)
+                             (and (stringp value) (= (length value) 1))))
   :group 'fortran-comment)
   :group 'fortran-comment)
-(put 'fortran-comment-indent-char 'safe-local-variable
-     (lambda (value) (or (char-valid-p value)
-                         (and (stringp value)
-                              (= (length value) 1)))))
 
 (defcustom fortran-line-number-indent 1
 
 (defcustom fortran-line-number-indent 1
-  "*Maximum indentation for Fortran line numbers.
+  "Maximum indentation for Fortran line numbers.
 5 means right-justify them within their five-column field."
   :type  'integer
 5 means right-justify them within their five-column field."
   :type  'integer
+  :safe  'integerp
   :group 'fortran-indent)
   :group 'fortran-indent)
-(put 'fortran-line-number-indent 'safe-local-variable 'integerp)
 
 (defcustom fortran-check-all-num-for-matching-do nil
 
 (defcustom fortran-check-all-num-for-matching-do nil
-  "*Non-nil causes all numbered lines to be treated as possible DO loop ends."
+  "Non-nil causes all numbered lines to be treated as possible DO loop ends."
   :type  'boolean
   :type  'boolean
+  :safe  'booleanp
   :group 'fortran)
   :group 'fortran)
-(put 'fortran-check-all-num-for-matching-do 'safe-local-variable 'booleanp)
 
 (defcustom fortran-blink-matching-if nil
 
 (defcustom fortran-blink-matching-if nil
-  "*Non-nil causes \\[fortran-indent-line] on ENDIF to blink on matching IF.
+  "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
 Also, from an ENDDO statement blink on matching DO [WHILE] statement."
   :type  'boolean
+  :safe  'booleanp
   :group 'fortran)
   :group 'fortran)
-(put 'fortran-blink-matching-if 'safe-local-variable 'booleanp)
 
 (defcustom fortran-continuation-string "$"
 
 (defcustom fortran-continuation-string "$"
-  "*Single-character string used for Fortran continuation lines.
+  "Single-character string used for Fortran continuation lines.
 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
 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
   :type  'string
+  :safe  (lambda (value) (and (stringp value) (= (length value) 1)))
   :group 'fortran)
   :group 'fortran)
-(put 'fortran-continuation-string 'safe-local-variable
-     (lambda (value) (and (stringp value)
-                          (= (length value) 1))))
 
 (defcustom fortran-comment-region "c$$$"
 
 (defcustom fortran-comment-region "c$$$"
-  "*String inserted by \\[fortran-comment-region] at start of each \
+  "String inserted by \\[fortran-comment-region] at start of each \
 line in region."
   :type  'string
 line in region."
   :type  'string
+  :safe  'stringp
   :group 'fortran-comment)
   :group 'fortran-comment)
-(put 'fortran-comment-region 'safe-local-variable 'stringp)
 
 (defcustom fortran-electric-line-number t
 
 (defcustom fortran-electric-line-number t
-  "*Non-nil causes line numbers to be moved to the correct column as typed."
+  "Non-nil causes line numbers to be moved to the correct column as typed."
   :type  'boolean
   :type  'boolean
+  :safe  'booleanp
   :group 'fortran)
   :group 'fortran)
-(put 'fortran-electric-line-number 'safe-local-variable 'booleanp)
 
 
+;; TODO use fortran-line-length, somehow.
 (defcustom fortran-column-ruler-fixed
   "0   4 6  10        20        30        40        5\
 0        60        70\n\
 (defcustom fortran-column-ruler-fixed
   "0   4 6  10        20        30        40        5\
 0        60        70\n\
@@ -246,9 +251,10 @@ line in region."
 This variable is used in fixed format mode.
 See the variable `fortran-column-ruler-tab' for TAB format mode."
   :type  'string
 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)
   :group 'fortran)
-(put 'fortran-column-ruler-fixed 'safe-local-variable 'stringp)
 
 
+;; TODO use fortran-line-length, somehow.
 (defcustom fortran-column-ruler-tab
   "0       810        20        30        40        5\
 0        60        70\n\
 (defcustom fortran-column-ruler-tab
   "0       810        20        30        40        5\
 0        60        70\n\
@@ -258,22 +264,49 @@ 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
 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)
   :group 'fortran)
-(put 'fortran-column-ruler-tab 'safe-local-variable 'stringp)
 
 (defcustom fortran-analyze-depth 100
   "Number of lines to scan to identify fixed or TAB format style."
   :type  'integer
 
 (defcustom fortran-analyze-depth 100
   "Number of lines to scan to identify fixed or TAB format style."
   :type  'integer
+  :safe  'integerp
   :group 'fortran)
   :group 'fortran)
-(put 'fortran-analyze-depth 'safe-local-variable 'integerp)
 
 (defcustom fortran-break-before-delimiters t
 
 (defcustom fortran-break-before-delimiters t
-  "*Non-nil causes filling to break lines before delimiters.
+  "Non-nil causes filling to break lines before delimiters.
 Delimiters are characters matching the regexp `fortran-break-delimiters-re'."
   :type  'boolean
 Delimiters are characters matching the regexp `fortran-break-delimiters-re'."
   :type  'boolean
+  :safe  'booleanp
+  :group 'fortran)
+
+;; TODO 0 as no-limit, as per g77.
+(defcustom fortran-line-length 72
+  "Maximum number of characters in a line of fixed-form Fortran code.
+Characters beyond this point are treated as comments.  Setting
+this variable directly (after fortran mode is loaded) does not
+take effect.  Use either \\[customize] (which affects all Fortran
+buffers and the default) or the function
+`fortran-line-length' (which can also operate on just the current
+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.
+         (fortran-line-length value t))
+  :version "23.1"
+  :group 'fortran)
+
+(make-variable-buffer-local 'fortran-line-length)
+
+(defcustom fortran-mode-hook nil
+  "Hook run when entering Fortran mode."
+  :type  'hook
   :group 'fortran)
   :group 'fortran)
-(put 'fortran-break-before-delimiters 'safe-local-variable 'booleanp)
 
 
+\f
 (defconst fortran-break-delimiters-re "[-+*/><=, \t]"
   "Regexp matching delimiter characters at which lines may be broken.
 There are certain tokens comprised entirely of characters
 (defconst fortran-break-delimiters-re "[-+*/><=, \t]"
   "Regexp matching delimiter characters at which lines may be broken.
 There are certain tokens comprised entirely of characters
@@ -289,22 +322,23 @@ characters matching the regexp `fortran-break-delimiters-re' that should
 not be split by filling.  Each element is assumed to be two
 characters long.")
 
 not be split by filling.  Each element is assumed to be two
 characters long.")
 
-(defcustom fortran-mode-hook nil
-  "Hook run when entering Fortran mode."
-  :type  'hook
-  :group 'fortran)
-
-\f
-(defvar fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*("
+(defconst fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*("
   "Regexp matching the start of an IF statement.")
 
   "Regexp matching the start of an IF statement.")
 
-(defvar fortran-end-prog-re1
+;; 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\\)\\>\
 \\([ \t]*\\(\\sw\\|\\s_\\)+\\)?\\)?"
   "Regexp possibly matching the end of a subprogram.")
 
   "end\
 \\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\
 \\([ \t]*\\(\\sw\\|\\s_\\)+\\)?\\)?"
   "Regexp possibly matching the end of a subprogram.")
 
-(defvar fortran-end-prog-re
+(defconst fortran-end-prog-re
   (concat "^[ \t0-9]*" fortran-end-prog-re1)
   "Regexp possibly matching the end of a subprogram, from the line start.
 See also `fortran-end-prog-re1'.")
   (concat "^[ \t0-9]*" fortran-end-prog-re1)
   "Regexp possibly matching the end of a subprogram, from the line start.
 See also `fortran-end-prog-re1'.")
@@ -359,8 +393,8 @@ program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
                           'paren) "\\>")
            ;; Builtin operators.
            (concat "\\." (regexp-opt
                           'paren) "\\>")
            ;; Builtin operators.
            (concat "\\." (regexp-opt
-                          '("and" "or" "not" "lt" "le" "eq" "ge"
-                            "gt" "ne" "eqv" "neqv" "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]+\\)?"
                           'paren) "\\.")
            ;; do/goto keywords and targets, and goto tags.
            '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?"
@@ -369,6 +403,28 @@ program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
            '("^ *\\([0-9]+\\)" . font-lock-constant-face)))
   "Medium level highlighting for Fortran mode.")
 
            '("^ *\\([0-9]+\\)" . font-lock-constant-face)))
   "Medium level highlighting for Fortran mode.")
 
+;; See bug#1385. Never really looked into _why_ this matters...
+(defun fortran-match-and-skip-declaration (limit)
+  "Like `font-lock-match-c-style-declaration-item-and-skip-to-next'.
+The only difference is, it returns t in a case when the default returns nil."
+  (when (looking-at "[ \n\t*]*\\(\\sw+\\)[ \t\n]*\\(((?\\)?")
+    (when (and (match-end 2) (> (- (match-end 2) (match-beginning 2)) 1))
+      (let ((pos (point)))
+       (skip-chars-backward " \t\n")
+       (skip-syntax-backward "w")
+       (unless (looking-at "\\(\\sw+\\)[ \t\n]*\\sw+[ \t\n]*\\(((?\\)?")
+         (goto-char pos)
+         (looking-at "[ \n\t*]*\\(\\sw+\\)[ \t\n]*\\(((?\\)?"))))
+    (save-match-data
+      (condition-case nil
+         (save-restriction
+           (narrow-to-region (point-min) limit)
+           (goto-char (match-end 1))
+           (while (not (looking-at "[ \t\n]*\\(\\(,\\)\\|;\\|\\'\\)"))
+             (goto-char (or (scan-sexps (point) 1) (point-max))))
+            (goto-char (match-end 2)))
+       (error t)))))
+
 (defvar fortran-font-lock-keywords-3
   (append
    fortran-font-lock-keywords-1
 (defvar fortran-font-lock-keywords-3
   (append
    fortran-font-lock-keywords-1
@@ -378,7 +434,7 @@ program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
           ;; Type specifier.
           '(1 font-lock-type-face)
           ;; Declaration item (or just /.../ block name).
           ;; Type specifier.
           '(1 font-lock-type-face)
           ;; Declaration item (or just /.../ block name).
-          `(font-lock-match-c-style-declaration-item-and-skip-to-next
+          `(fortran-match-and-skip-declaration
             ;; Start after any *(...) expression.
             (condition-case nil
                 (and (match-beginning ,(1+ (regexp-opt-depth
             ;; Start after any *(...) expression.
             (condition-case nil
                 (and (match-beginning ,(1+ (regexp-opt-depth
@@ -432,11 +488,13 @@ Consists of level 3 plus all other intrinsics not already highlighted.")
 ;; (We can do so for F90-style).  Therefore an unmatched quote in a
 ;; standard comment will throw fontification off on the wrong track.
 ;; So we do syntactic fontification with regexps.
 ;; (We can do so for F90-style).  Therefore an unmatched quote in a
 ;; standard comment will throw fontification off on the wrong track.
 ;; So we do syntactic fontification with regexps.
-(defvar fortran-font-lock-syntactic-keywords
-  '(("^[cd\\*]" 0 (11))
-    ("^[^cd\\*\t\n].\\{71\\}\\([^\n]+\\)" 1 (11)))
-  "`font-lock-syntactic-keywords' for Fortran.
-These get fixed-format comments fontified.")
+(defun fortran-font-lock-syntactic-keywords ()
+  "Return a value for `font-lock-syntactic-keywords' in Fortran mode.
+This varies according to the value of `fortran-line-length'.
+This is used to fontify fixed-format Fortran comments."
+  `(("^[cd\\*]" 0 (11))
+    (,(format "^[^cd\\*\t\n].\\{%d\\}\\([^\n]+\\)" (1- fortran-line-length))
+     1 (11))))
 
 (defvar fortran-font-lock-keywords fortran-font-lock-keywords-1
   "Default expressions to highlight in Fortran mode.")
 
 (defvar fortran-font-lock-keywords fortran-font-lock-keywords-1
   "Default expressions to highlight in Fortran mode.")
@@ -520,15 +578,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
 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)))
                             "^[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)
     (modify-syntax-entry ?\r " "  table)
     (modify-syntax-entry ?+  "."  table)
     (modify-syntax-entry ?-  "."  table)
@@ -560,7 +618,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)
   (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)
     (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)
@@ -584,14 +643,21 @@ Used in the Fortran entry in `hs-special-modes-alist'.")
 
     (easy-menu-define fortran-menu map "Menu for Fortran mode."
       `("Fortran"
 
     (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)
         ("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]
          )
         "--"
         ["Comment Region" fortran-comment-region mark-active]
@@ -601,9 +667,12 @@ Used in the Fortran entry in `hs-special-modes-alist'.")
         ["Indent Region"     indent-region mark-active]
         ["Indent Subprogram" fortran-indent-subprogram t]
         "--"
         ["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"
         ("Mark"
+         :help "Mark a region of code"
          ["Subprogram" mark-defun      t]
          ["IF Block"   fortran-mark-if t]
          ["DO Block"   fortran-mark-do t]
          ["Subprogram" mark-defun      t]
          ["IF Block"   fortran-mark-if t]
          ["DO Block"   fortran-mark-do t]
@@ -611,103 +680,101 @@ Used in the Fortran entry in `hs-special-modes-alist'.")
         ["Narrow to Subprogram" narrow-to-defun t]
         ["Widen" widen t]
         "--"
         ["Narrow to Subprogram" narrow-to-defun t]
         ["Widen" widen t]
         "--"
-        ["Temporary column ruler" fortran-column-ruler  t]
-        ["72-column window"       fortran-window-create 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 :active t
+         :help "Set window width to Fortran line length"]
         ["Full Width Window"
          (enlarge-window-horizontally (- (frame-width) (window-width)))
         ["Full Width Window"
          (enlarge-window-horizontally (- (frame-width) (window-width)))
-         (not (window-full-width-p))]
-        ["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]))
          :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
     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
 
 \f
 ;;;###autoload
@@ -748,7 +815,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
                 `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
   (default 'fixed)
 `fortran-comment-indent-char'
   Single-character string to be inserted instead of space for
@@ -806,11 +873,16 @@ 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)
        ;; (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))
   (setq mode-line-process '(indent-tabs-mode fortran-tab-mode-string))
   (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))
   (setq mode-line-process '(indent-tabs-mode fortran-tab-mode-string))
-  (set (make-local-variable 'fill-column) 72)
+  (set (make-local-variable 'fill-column) fortran-line-length)
   (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
   (set (make-local-variable 'font-lock-defaults)
        '((fortran-font-lock-keywords
   (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
   (set (make-local-variable 'font-lock-defaults)
        '((fortran-font-lock-keywords
@@ -819,9 +891,9 @@ with no args, if that value is non-nil."
           fortran-font-lock-keywords-3
           fortran-font-lock-keywords-4)
          nil t ((?/ . "$/") ("_$" . "w"))
           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)
   (set (make-local-variable 'imenu-case-fold-search) t)
   (set (make-local-variable 'imenu-generic-expression)
        fortran-imenu-generic-expression)
@@ -834,9 +906,40 @@ with no args, if that value is non-nil."
        #'fortran-current-defun)
   (set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search)
   (set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr)
        #'fortran-current-defun)
   (set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search)
   (set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr)
+  (add-hook 'hack-local-variables-hook 'fortran-hack-local-variables nil t)
   (run-mode-hooks 'fortran-mode-hook))
 
 \f
   (run-mode-hooks 'fortran-mode-hook))
 
 \f
+(defun fortran-line-length (nchars &optional global)
+  "Set the length of fixed-form Fortran lines to NCHARS.
+This normally only affects the current buffer, which must be in
+Fortran mode.  If the optional argument GLOBAL is non-nil, it
+affects all Fortran buffers, and also the default."
+  (interactive "p")
+  (let (new)
+    (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))))
+
+(defun fortran-hack-local-variables ()
+  "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
 (defun fortran-gud-find-expr ()
   ;; Consider \n as punctuation (end of expression).
   (with-syntax-table fortran-gud-syntax-table
@@ -862,33 +965,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)
   (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)))))
              (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.
 
 (defun fortran-comment-region (beg-region end-region arg)
   "Comment every line in the region.
@@ -898,7 +1001,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))
 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
     (goto-char beg-region)
     (beginning-of-line)
     (if arg
@@ -917,12 +1020,17 @@ With non-nil ARG, uncomments the region."
     (set-marker end-region-mark nil)
     (set-marker save-point nil)))
 
     (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 "*")
 \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)))
   (let* ((event (if (fboundp 'next-command-event) ; XEmacs
                     (next-command-event)
                   (read-event)))
@@ -931,7 +1039,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)))
     ;; 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 ()
       (push event unread-command-events))))
 
 (defun fortran-abbrev-help ()
@@ -964,44 +1072,44 @@ The next key typed is executed unless it is SPC."
    (save-excursion
      (beginning-of-line)
      (if (eq (window-start (selected-window))
    (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."))
 
 (defun fortran-window-create ()
        (point)))
    nil "Type SPC or any command to erase ruler."))
 
 (defun fortran-window-create ()
-  "Make the window 72 columns wide.
+  "Make the window `fortran-line-length' (default 72) columns wide.
 See also `fortran-window-create-momentarily'."
   (interactive)
   (let ((window-min-width 2))
     (unless (window-full-width-p)
 See also `fortran-window-create-momentarily'."
   (interactive)
   (let ((window-min-width 2))
     (unless (window-full-width-p)
-      (enlarge-window-horizontally (- (frame-width)
-                                      (window-width) 1)))
+        (enlarge-window-horizontally (- (frame-width)
+                                        (window-width) 1)))
     (let* ((window-edges (window-edges))
     (let* ((window-edges (window-edges))
-          (scroll-bar-width (- (nth 2 window-edges)
-                               (car window-edges)
-                               (window-width))))
-      (split-window-horizontally (+ 72 scroll-bar-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)
     (select-window (previous-window))))
 
 (defun fortran-window-create-momentarily (&optional arg)
     (other-window 1)
     (switch-to-buffer " fortran-window-extra" t)
     (select-window (previous-window))))
 
 (defun fortran-window-create-momentarily (&optional arg)
-  "Momentarily make the window 72 columns wide.
+  "Momentarily make the window `fortran-line-length' (default 72) columns wide.
 Optional ARG non-nil and non-unity disables the momentary feature.
 See also `fortran-window-create'."
   (interactive "p")
   (if (or (not arg)
 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
       (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 ()
     (fortran-window-create)))
 
 (defun fortran-split-line ()
@@ -1009,13 +1117,13 @@ See also `fortran-window-create'."
   (interactive "*")
   (delete-horizontal-space)
   (if (save-excursion
   (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 (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 *
 
       (insert "\n " fortran-continuation-string))) ; space after \n important
   (fortran-indent-line))               ; when cont string is C, c or *
 
@@ -1051,7 +1159,7 @@ plus one, otherwise return 1.  Zero not allowed."
   (save-excursion
     (forward-line -1)
     (if (looking-at "\t[1-9]")
   (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)
       ?1)))
 
 (put 'fortran-electric-line-number 'delete-selection t)
@@ -1061,29 +1169,29 @@ Auto-indent does not happen if a numeric ARG is used."
   (interactive "*P")
   (if (or arg (not fortran-electric-line-number))
       (if arg
   (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))
     (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.
                     ;; 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.
                  ;; 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")
       (skip-chars-backward " \t")
-      (insert last-command-char)
+      (insert last-command-event)
       (fortran-indent-line))))
 
 \f
       (fortran-indent-line))))
 
 \f
@@ -1093,41 +1201,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<\\)"
   ;; match of whitespace, avoiding possible column 73+ stuff.
   (save-match-data
     (string-match "^\\s-*\\(\\'\\|\\s<\\)"
-                 (buffer-substring (match-end 0)
-                                   (min (line-end-position)
-                                        (+ 72 (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.
+                  (buffer-substring (match-end 0)
+                                    (min (line-end-position)
+                                         (+ fortran-line-length
+                                            (line-beginning-position)))))))
+
+;; 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)
 (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)
 (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.
 
 (defun fortran-previous-statement ()
   "Move point to beginning of the previous Fortran statement.
@@ -1138,28 +1257,28 @@ Directive lines are treated as comments."
   (let (not-first-statement continue-test)
     (beginning-of-line)
     (setq continue-test
   (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))
            (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)))
     (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 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
     (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.
 
 (defun fortran-next-statement ()
   "Move point to beginning of the next Fortran statement.
@@ -1170,14 +1289,14 @@ Directive lines are treated as comments."
   (let (not-last-statement)
     (beginning-of-line)
     (while (and (setq not-last-statement
   (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 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)
     (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."
 
 (defun fortran-looking-at-if-then ()
   "Return non-nil if at the start of a line with an IF ... THEN statement."
@@ -1198,7 +1317,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")
 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 'any) (push-mark (point) t))
   (and num (< num 0) (fortran-beginning-of-block (- num)))
   (let ((case-fold-search t)
         (count (or num 1)))
   (and num (< num 0) (fortran-beginning-of-block (- num)))
   (let ((case-fold-search t)
         (count (or num 1)))
@@ -1231,7 +1350,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")
 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 'any) (push-mark (point) t))
   (and num (< num 0) (fortran-end-of-block (- num)))
   (let ((case-fold-search t)
         (count (or num 1)))
   (and num (< num 0) (fortran-end-of-block (- num)))
   (let ((case-fold-search t)
         (count (or num 1)))
@@ -1262,10 +1381,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))
   "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")
     (when (save-excursion
             (beginning-of-line)
             (skip-chars-forward " \t0-9")
@@ -1289,7 +1408,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"
 (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."
 
 (defun fortran-blink-matching-do ()
   "From an ENDDO statement, blink the matching DO or DO WHILE statement."
@@ -1312,27 +1431,27 @@ The marks are pushed."
 Return point or nil."
   (let ((case-fold-search t))
     (if (save-excursion (beginning-of-line)
 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
       ;; 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].
 
 (defun fortran-beginning-do ()
   "Search backwards for first unmatched DO [WHILE].
@@ -1340,28 +1459,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
   (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
       ;; 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.
                   ;; 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.
 
 (defun fortran-mark-if ()
   "Put mark at end of Fortran IF-ENDIF construct, point at beginning.
@@ -1381,103 +1500,103 @@ The marks are pushed."
 Return point or nil."
   (let ((case-fold-search t))
     (if (save-excursion (beginning-of-line)
 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
       ;; 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
 
 (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))
                        (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
       ;; 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 ()
 
 \f
 (defun fortran-indent-line ()
@@ -1487,15 +1606,15 @@ Return point or nil."
     (save-excursion
       (beginning-of-line)
       (if (or (not (= cfi (fortran-current-line-indentation)))
     (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)
     ;; 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)
     (and auto-fill-function
          (> (save-excursion (end-of-line) (current-column))
             fill-column)
@@ -1510,20 +1629,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)))
   "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'.
 
 ;; Historically this was a separate function which advertised itself
 ;; as reindenting but only did so where `most likely to be necessary'.
@@ -1541,21 +1660,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)
 (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
     (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]")
         (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]")
                          (while (and (zerop (forward-line 1))
                                      ;; Search forward for then.
                                      (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
@@ -1586,57 +1705,71 @@ Return point or nil."
               ((and (looking-at fortran-end-prog-re1)
                     (fortran-check-end-prog-re))
                ;; Previous END resets indent to minimum.
               ((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.
     (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))))
              (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\\>\\)")
                    ((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]")
 \\(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)))
 
  an unclosed block." fortran-minimum-statement-indent))))))
     (max fortran-minimum-statement-indent icol)))
 
@@ -1650,16 +1783,16 @@ non-indentation text within the comment."
   (save-excursion
     (beginning-of-line)
     (cond ((looking-at fortran-comment-line-start-skip)
   (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)))
     ;; Move past whitespace.
     (skip-chars-forward " \t")
     (current-column)))
@@ -1676,48 +1809,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)
   (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 (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.
           ;; 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)
       ;; Point is now after any continuation character or line number.
       ;; Put body of statement where specified.
       (delete-horizontal-space)
@@ -1736,20 +1869,20 @@ Do not call if there is no line number."
     (beginning-of-line)
     (skip-chars-forward " \t")
     (and (<= (current-column) fortran-line-number-indent)
     (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)
 
 (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")
     (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")
         (setq charnum
               (buffer-substring (point) (progn
                                           (skip-chars-forward "0-9")
@@ -1776,19 +1909,19 @@ 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))
   ;; (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)
       (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.
 
 ;; From: ralf@up3aud1.gwdg.de (Ralf Fassel)
 ;; Test if TAB format continuation lines work.
@@ -1797,57 +1930,57 @@ If ALL is nil, only match comments that start in column > 0."
   (save-excursion
     (goto-char where)
     (cond
   (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))
      (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)
 
 ;; From old version.
 (defalias 'fortran-auto-fill-mode 'auto-fill-mode)
@@ -1855,17 +1988,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)
 (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).
          ;; 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)))
               (let (fcpoint start)
                 (move-to-column fill-column)
                 (when (fortran-is-in-string-p (setq fcpoint (point)))
@@ -1884,12 +2017,12 @@ If ALL is nil, only match comments that start in column > 0."
                          (- fill-column 6 fortran-continuation-indent))
                       fcpoint
                     start))))))
                          (- 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
                 ;; 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
@@ -1913,13 +2046,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?
                       (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)))
                   (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
                 (point)))))
     ;; If we are in an in-line comment, don't break unless the
     ;; line of code is longer than it should be. Otherwise
@@ -1928,20 +2061,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
     ;; 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
                      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))))
       (goto-char fill-point)
       (fortran-break-line)
       (end-of-line))))
@@ -1949,27 +2082,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))
 (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)
     ;; 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
       (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.
 
 (defun fortran-analyze-file-format ()
   "Return nil if fixed format is used, t if TAB formatting is used.
@@ -1979,12 +2112,12 @@ before the end or in the first `fortran-analyze-depth' lines."
     (save-excursion
       (goto-char (point-min))
       (while (not (or
     (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)
       (cond
        ((eq (char-after) ?\t) t)
        ((looking-at " \\{6\\}") nil)
@@ -2026,29 +2159,28 @@ Always returns non-nil (to prevent `fill-paragraph' being called)."
     (fortran-indent-line)))
 
 (defun fortran-strip-sequence-nos (&optional do-space)
     (fortran-indent-line)))
 
 (defun fortran-strip-sequence-nos (&optional do-space)
-  "Delete all text in column 72 and up (assumed to be sequence numbers).
-Normally also deletes trailing whitespace after stripping such text.
-Supplying prefix arg DO-SPACE prevents stripping the whitespace."
+  "Delete all text in column `fortran-line-length' (default 72) and up.
+This is assumed to be sequence numbers.  Normally also deletes
+trailing whitespace after stripping such text.  Supplying prefix
+arg DO-SPACE prevents stripping the whitespace."
   (interactive "*p")
   (save-excursion
     (goto-char (point-min))
   (interactive "*p")
   (save-excursion
     (goto-char (point-min))
-    (while (re-search-forward "^.\\{72\\}\\(.*\\)" nil t)
+    (while (re-search-forward (format "^.\\{%d\\}\\(.*\\)" fortran-line-length)
+                              nil t)
       (replace-match "" nil nil nil 1)
       (unless do-space (delete-horizontal-space)))))
 
       (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)
 (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
       ;; 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)
            (save-excursion (fortran-end-of-subprogram)
                            (point))
            t)