]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/fortran.el
(fortran-mode-syntax-table): Change `\' to `\'
[gnu-emacs] / lisp / progmodes / fortran.el
index aad14d232c2381270f189544ae550c27fe6946b7..bd0d0aad0046fba318f3649e0d93bb3f8e1b1f8c 100644 (file)
@@ -1,80 +1,16 @@
-;;; fortran.el --- Fortran mode for GNU Emacs  (version 1.28.3, July 15, 1991)
-
-;;; Copyright (c) 1991 Free Software Foundation, Inc.
-;;; Written by Michael D. Prange (prange@erl.mit.edu)
-;;; Maintained (as of version 1.28) by Stephen A. Wood (saw@hallc1.cebaf.gov)
-;;; This version is an update of version 1.21 (Oct 1, 1985).
-;;;  Updated by Stephen A. Wood (saw@hallc1.cebaf.gov) to use tab format
-;;;  continuation control and indentation.  (Digit after TAB to signify 
-;;;  continuation line.  This version also incorporates suggestions from
-;;;  Richard Stallman, and the ideas in two previous unpublished versions of
-;;;  fortran .el (version 1.21.1 (from gildea@expo.lcs.mit.edu) and 1.27 
-;;;  (prange@erl.mit.edu).)
-
-;;; Notes to fortran-mode version 1.28
-;;;  1. Fortran mode can support either fixed format or tab format.  Fixed
-;;;     format is where statements start in column 6 (first column is 0)
-;;;     and continuation lines are denoted by a character in column 5.
-;;;     In tab mode, statements follow a tab character.  Continuation lines
-;;;     are where the first character on a line is a tab and the second is
-;;;     a digit from 1 to 9.
-;;;  2. When fortran mode is called, the buffer is analyzed to determine what
-;;;     kind of formating is used.  Starting at the top of the file, lines
-;;;     are scanned until a line is found that begins with a tab or 6 spaces.
-;;;     The mode for that buffer is then set to either tab or fixed format
-;;;     based on that line.  If no line starting with a tab or 6 spaces is
-;;;     found before the end  of the buffer or in the first 100 lines, the
-;;;     mode is set from the variable `fortran-tab-mode-default'.  t is tab
-;;;     mode, nil is fixed format mode.  By default, fixed format mode is used.
-;;;     To use tabbing mode as the default, put the following line in .emacs
-;;;           (setq fortran-tab-mode-default t)
-;;;     This line should not be in the hook since the hook is called only
-;;;     after the file is analyzed.
-;;;     To force a particular mode independent of the analysis, attach
-;;;           (fortran-tab-mode t) or (fortran-tab-mode nil)
-;;;     to fortran-mode-hook.
-;;;  3. The command `fortran-tab-mode' will toggle between fixed and tab
-;;;     formatting modes.  The file will not automatically be reformatted,
-;;;     but either `indent-region' or `fortran-indent-subprogram' can be
-;;;     used to reformat portions of the file.
-;;;  4. Several abbreviations have been added.  Abbreviation mode is turned
-;;;     on by default.
-;;;  5. The routine fortran-blink-matching if has been incorporated (from
-;;;     experimental version 1.27).  If the variable of the same name is set
-;;;     to t, the the matching if statement is blinked whenever an endif
-;;;     line is indented.
-;;;  6. C-c C-w is now bound to fortran-window-create-momentarily (from
-;;;     experimental version 1.27.)
-;;;  7. LFD is now bound to fortran-reindent-then-newline-and-indent.
-;;;  8. fortran-continuation-string (was fortran-continuation-char) is now
-;;;     a string rather than a character.
-;;;  9. Fixed a bug from 1.21 that gave max-lisp-eval-depth exceeded when
-;;;     Comments lines had !'s in them.
-;;; 10. DEC fortran recognizes a & in the first column as a continuation.
-;;;     character.  This mode does not recognize the & as a continuation
-;;;     character.
-;;; 11. fortran-blink-matching-if still is in effect when indenting a region.
-;;;     Is this a desirable effect?  (It looks kind of neat)
-;;; 12. If you strike a digit and there are exactly 5 characters, all spaces
-;;;     to the left of the point, the digit will be inserted in place to
-;;;     serve as a continuation line marker.  Similarly, if the only thing to
-;;;     the left of the point is a single tab, and the last command issued
-;;;     was neither fortran-indent-line (TAB) or fortran-reindent-then-newline-
-;;;     and-indent (LFD), the digit is inserted as a tab format style
-;;;     continuation character.
-;;; 13. Both modes should usually work with tab-width set to other than 8.
-;;;     However, in tab-mode, if tab-width is less than 6, the column number
-;;;     for the minimum indentation is set to 6 so that all line numbers will
-;;;     have have a tab after them.  This may be a bit ugly, but why would
-;;;     you want to use a tab-width other than 8 anyway?
-;;; 14. When in tab mode, the fortran column ruler will not be correct if
-;;;     tab-width is not 8.
+;;; fortran.el --- Fortran mode for GNU Emacs
+
+;; Copyright (c) 1986, 93, 94, 95, 97, 98, 1999 Free Software Foundation, Inc.
+
+;; Author: Michael D. Prange <prange@erl.mit.edu>
+;; Maintainer: Dave Love <fx@gnu.org>
+;; Keywords: languages
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 1, or (at your option)
+;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This mode is documented in the Emacs manual.
+;;
+;; Note that it is for editing Fortran77 or Fortran90 fixed source
+;; form.  For editing Fortran 90 free format source, use `f90-mode'
+;; (f90.el).
+
+;;; History:
+
+;; Fortran mode was upgraded by Stephen A. Wood (saw@cebaf.gov).
+
+;; We acknowledge many contributions and valuable suggestions by
+;; Lawrence R. Dodd, Ralf Fassel, Ralph Finch, Stephen Gildea,
+;; Dr. Anil Gokhale, Ulrich Mueller, Mark Neale, Eric Prestemon,
+;; Gary Sabot and Richard Stallman.
+
+;;; Code:
+
+;; Todo:
 
-;;; Author acknowledges help from Stephen Gildea <gildea@erl.mit.edu>
+;; * Tidy it all up!  (including renaming non-`fortran' prefixed
+;;   functions).
+;; * Implement insertion and removal of statement continuations in
+;;   mixed f77/f90 style, with the first `&' past column 72 and the
+;;   second in column 6.
+;; * Support any other extensions to f77 grokked by GNU Fortran.
+;; * Change fontification to use font-lock-syntactic-keywords for
+;;   fixed-form comments.  (Done, but doesn't work properly with
+;;   lazy-lock in pre-20.4.)
+
+(require 'easymenu)
+
+(defgroup fortran nil
+  "Fortran mode for Emacs"
+  :link '(custom-manual "(emacs)Fortran")
+  :group 'languages)
+
+(defgroup fortran-indent nil
+  "Indentation variables in Fortran mode"
+  :prefix "fortran-"
+  :group 'fortran)
+
+(defgroup fortran-comment nil
+  "Comment-handling variables in Fortran mode"
+  :prefix "fortran-"
+  :group 'fortran)
 
-;;; Bugs to bug-fortran-mode@erl.mit.edu
 
 ;;;###autoload
-(defvar fortran-tab-mode-default nil
-  "*Default tabbing/carriage control style for empty files in fortran mode.
-t indicates that tab-digit style of continuation control will be used.
-nil indicates that continuation lines are marked with a character in
-column 6.")
+(defcustom fortran-tab-mode-default nil
+  "*Default tabbing/carriage control style for empty files in Fortran mode.
+A value of t 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
+  :group 'fortran-indent)
 
-(defvar fortran-do-indent 3
-  "*Extra indentation applied to `do' blocks.")
+;; Buffer local, used to display mode line.
+(defcustom fortran-tab-mode-string nil
+  "String to appear in mode line when TAB format mode is on."
+  :type '(choice (const nil) string)
+  :group 'fortran-indent)
+(make-variable-buffer-local 'fortran-tab-mode-string)
 
-(defvar fortran-if-indent 3
-  "*Extra indentation applied to `if' blocks.")
+(defcustom fortran-do-indent 3
+  "*Extra indentation applied to DO blocks."
+  :type 'integer
+  :group 'fortran-indent)
 
-(defvar fortran-continuation-indent 5
-  "*Extra indentation applied to `continuation' lines.")
+(defcustom fortran-if-indent 3
+  "*Extra indentation applied to IF blocks."
+  :type 'integer
+  :group 'fortran-indent)
 
-(defvar fortran-comment-indent-style 'fixed
-  "*nil forces comment lines not to be touched,
-'fixed produces fixed comment indentation to comment-column,
-and 'relative indents to current fortran indentation plus comment-column.")
+(defcustom fortran-structure-indent 3
+  "*Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks."
+  :type 'integer
+  :group 'fortran-indent)
 
-(defvar fortran-comment-line-column 6
-  "*Indentation for text in comment lines.")
+(defcustom fortran-continuation-indent 5
+  "*Extra indentation applied to Fortran continuation lines."
+  :type 'integer
+  :group 'fortran-indent)
 
-(defvar comment-line-start nil
-  "*Delimiter inserted to start new full-line comment.")
+(defcustom fortran-comment-indent-style 'fixed
+  "*How to indent comments.
+nil forces comment lines not to be touched,
+'fixed makes fixed comment indentation to `fortran-comment-line-extra-indent'
+columns beyond `fortran-minimum-statement-indent-fixed' (for
+`indent-tabs-mode' of nil) or `fortran-minimum-statement-indent-tab' (for
+`indent-tabs-mode' of t), and 'relative indents to current
+Fortran indentation plus `fortran-comment-line-extra-indent'."
+  :type '(radio (const :tag "Untouched" nil) (const fixed) (const relative))
+  :group 'fortran-indent)
 
-(defvar comment-line-start-skip nil
-  "*Regexp to match the start of a full-line comment.")
+(defcustom fortran-comment-line-extra-indent 0
+  "*Amount of extra indentation for text within full-line comments."
+  :type 'integer
+  :group 'fortran-indent
+  :group 'fortran-comment)
 
-(defvar fortran-minimum-statement-indent 6
-  "*Minimum indentation for fortran statements.")
+(defcustom comment-line-start nil
+  "*Delimiter inserted to start new full-line comment."
+  :type '(choice string (const nil))
+  :group 'fortran-comment)
+
+(defcustom comment-line-start-skip nil
+  "*Regexp to match the start of a full-line comment."
+  :type '(choice string (const nil))
+  :group 'fortran-comment)
+
+(defcustom fortran-minimum-statement-indent-fixed 6
+  "*Minimum statement indentation for fixed format continuation style."
+  :type 'integer
+  :group 'fortran-indent)
+
+(defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
+  "*Minimum statement indentation for TAB format continuation style."
+  :type 'integer
+  :group 'fortran-indent)
 
 ;; 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.
-(defvar fortran-comment-indent-char " "
+(defcustom fortran-comment-indent-char " "
   "*Single-character string inserted for Fortran comment indentation.
-Normally a space.")
+Normally a space."
+  :type 'string
+  :group 'fortran-comment)
 
-(defvar fortran-line-number-indent 1
+(defcustom fortran-line-number-indent 1
   "*Maximum indentation for Fortran line numbers.
-5 means right-justify them within their five-column field.")
+5 means right-justify them within their five-column field."
+  :type 'integer
+  :group 'fortran-indent)
 
-(defvar fortran-check-all-num-for-matching-do nil
-  "*Non-nil causes all numbered lines to be treated as possible do-loop ends.")
+(defcustom fortran-check-all-num-for-matching-do nil
+  "*Non-nil causes all numbered lines to be treated as possible DO loop ends."
+  :type 'boolean
+  :group 'fortran)
 
-(defvar fortran-blink-matching-if nil
-  "*From a fortran `endif' statement, blink the matching `if' statement.")
+(defcustom fortran-blink-matching-if nil
+  "*Non-nil causes \\[fortran-indent-line] on ENDIF statement to blink on matching IF.
+Also, from an ENDDO statement blink on matching DO [WHILE] statement."
+  :type 'boolean
+  :group 'fortran)
 
-(defvar fortran-continuation-string "$"
-  "*Single-character string used for fortran continuation lines.
+(defcustom fortran-continuation-string "$"
+  "*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 appropriate style.
-Normally $.")
-
-(defvar fortran-comment-region "c$$$"
-  "*String inserted by \\[fortran-comment-region]\
- at start of each line in region.")
+Normally $."
+  :type 'string
+  :group 'fortran)
 
-(defvar fortran-electric-line-number t
-  "*Non-nil causes line number digits to be moved to the correct column as\
- typed.")
+(defcustom fortran-comment-region "c$$$"
+  "*String inserted by \\[fortran-comment-region] at start of each \
+line in region."
+  :type 'string
+  :group 'fortran-comment)
 
-(defvar fortran-startup-message t
-  "*Non-nil displays a startup message when Fortran mode is first called.")
+(defcustom fortran-electric-line-number t
+  "*Non-nil causes line number digits to be moved to the correct \
+column as typed."
+  :type 'boolean
+  :group 'fortran)
 
-(defvar fortran-column-ruler " "
-  "*String displayed above current line by \\[fortran-column-ruler].")
+(defvar fortran-column-ruler-fixed
+  "0   4 6  10        20        30        40        5\
+0        60        70\n\
+\[   ]|{   |    |    |    |    |    |    |    |    \
+\|    |    |    |    |}\n"
+  "String displayed above current line by \\[fortran-column-ruler].
+This variable used in fixed format mode.")
 
-(defconst bug-fortran-mode "bug-fortran-mode@erl.mit.edu"
-  "Address of mailing list for Fortran mode bugs.")
-
-(defconst fortran-mode-version "1.28.3")
+(defvar fortran-column-ruler-tab
+  "0       810        20        30        40        5\
+0        60        70\n\
+\[   ]|  { |    |    |    |    |    |    |    |    \
+\|    |    |    |    |}\n"
+  "String displayed above current line by \\[fortran-column-ruler].
+This variable used in TAB format mode.")
 
 (defvar fortran-mode-syntax-table nil
   "Syntax table in use in Fortran mode buffers.")
 
 (defvar fortran-analyze-depth 100
-  "Number of lines to scan to determine whether to use fixed or tab format\
- style.")
+  "Number of lines to scan to determine whether to use fixed or TAB \
+format style.")
+
+(defcustom fortran-break-before-delimiters t
+  "*Non-nil causes filling to break lines before delimiters."
+  :type 'boolean
+  :group 'fortran)
 
 (if fortran-mode-syntax-table
     ()
   (setq fortran-mode-syntax-table (make-syntax-table))
+  ;; We might like `;' to be punctuation (g77 multi-statement lines),
+  ;; but that screws abbrevs.
   (modify-syntax-entry ?\; "w" fortran-mode-syntax-table)
   (modify-syntax-entry ?\r " " fortran-mode-syntax-table)
   (modify-syntax-entry ?+ "." fortran-mode-syntax-table)
@@ -186,29 +235,203 @@ Normally $.")
   (modify-syntax-entry ?/ "." fortran-mode-syntax-table)
   (modify-syntax-entry ?\' "\"" fortran-mode-syntax-table)
   (modify-syntax-entry ?\" "\"" fortran-mode-syntax-table)
-  (modify-syntax-entry ?\\ "/" fortran-mode-syntax-table)
-  (modify-syntax-entry ?. "w" fortran-mode-syntax-table)
+  (modify-syntax-entry ?\\ "\\" fortran-mode-syntax-table)
+  ;; This might be better as punctuation, as for C, but this way you
+  ;; can treat floating-point numbers as symbols.
+  (modify-syntax-entry ?. "_" fortran-mode-syntax-table) ; e.g. `a.ne.b'
+  (modify-syntax-entry ?_ "_" fortran-mode-syntax-table)
+  (modify-syntax-entry ?$ "_" fortran-mode-syntax-table) ; esp. VMSisms
+  (modify-syntax-entry ?\! "<" fortran-mode-syntax-table)
   (modify-syntax-entry ?\n ">" fortran-mode-syntax-table))
 
-(defvar fortran-mode-map () 
-  "Keymap used in fortran mode.")
+;; Comments are real pain in Fortran because there is no way to
+;; represent the standard comment syntax in an Emacs syntax table.
+;; (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.
+\f
+;; Regexps done by simon@gnu with help from Ulrik Dickow <dickow@nbi.dk> and
+;; probably others Si's forgotten about (sorry).
+
+(defconst fortran-font-lock-keywords-1 nil
+  "Subdued level highlighting for Fortran mode.")
+
+(defconst fortran-font-lock-keywords-2 nil
+  "Medium level highlighting for Fortran mode.")
+
+(defconst fortran-font-lock-keywords-3 nil
+  "Gaudy level highlighting for Fortran mode.")
+
+(defconst fortran-font-lock-syntactic-keywords nil
+  "`font-lock-syntactic-keywords' for Fortran.
+These get fixed-format comments fontified.")
+
+(let ((comment-chars "cd")             ; `d' for `debugging' comments
+      (fortran-type-types
+       (eval-when-compile
+        (let ((re (regexp-opt
+                   (let ((simple-types
+                          '("character" "byte" "integer" "logical"
+                            "none" "real" "complex"
+                            "double precision" "double complex"))
+                         (structured-types '("structure" "union" "map"))
+                         (other-types '("record" "dimension"
+                                        "parameter" "common" "save"
+                                        "external" "intrinsic" "data"
+                                        "equivalence")))
+                     (append
+                      (mapcar (lambda (x) (concat "implicit " x))
+                              simple-types)
+                      simple-types
+                      (mapcar (lambda (x) (concat "end " x))
+                              structured-types)
+                      structured-types
+                      other-types)))))
+          ;; In the optimized regexp above, replace spaces by regexp
+          ;; for optional whitespace, which regexp-opt would have
+          ;; escaped.
+          (mapconcat #'identity (split-string re) "[ \t]*"))))
+      (fortran-keywords
+       (eval-when-compile
+         (regexp-opt '("continue" "format" "end" "enddo" "if" "then"
+                       "else" "endif" "elseif" "while" "inquire" "stop"
+                       "return" "include" "open" "close" "read" "write"
+                       "format" "print" "select" "case" "cycle" "exit"))))
+      (fortran-logicals
+       (eval-when-compile
+         (regexp-opt '("and" "or" "not" "lt" "le" "eq" "ge" "gt" "ne"
+                       "true" "false")))))
+
+  (setq fortran-font-lock-syntactic-keywords
+       ;; Fixed format comments.  (!-style handled normally.)
+       (list
+        (list (concat "^[" comment-chars "]") 0 '(11))
+        (list (concat "^[^" comment-chars "\t\n]" (make-string 71 ?.)
+                      "\\([^\n]+\\)")
+              1 '(11))))
+
+  (setq fortran-font-lock-keywords-1
+        (list
+         ;;
+         ;; Program, subroutine and function declarations, plus calls.
+         (list (concat "\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|"
+                       "program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?")
+               '(1 font-lock-keyword-face)
+               '(2 font-lock-function-name-face nil t))))
+
+  (setq fortran-font-lock-keywords-2
+        (append fortran-font-lock-keywords-1
+                (list
+                 ;;
+                 ;; Fontify all type specifiers (must be first; see below).
+                 (cons (concat "\\<\\(" fortran-type-types "\\)\\>")
+                       'font-lock-type-face)
+                 ;;
+                 ;; Fontify all builtin keywords (except logical, do
+                 ;; and goto; see below).
+                 (concat "\\<\\(" fortran-keywords "\\)\\>")
+                 ;;
+                 ;; Fontify all builtin operators.
+                 (concat "\\.\\(" fortran-logicals "\\)\\.")
+                 ;;
+                 ;; Fontify do/goto keywords and targets, and goto tags.
+                 (list "\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?"
+                       '(1 font-lock-keyword-face)
+                       '(2 font-lock-constant-face nil t))
+                 (cons "^ *\\([0-9]+\\)" 'font-lock-constant-face))))
+
+  (setq fortran-font-lock-keywords-3
+        (append
+         ;;
+         ;; The list `fortran-font-lock-keywords-1'.
+         fortran-font-lock-keywords-1
+         ;;
+         ;; Fontify all type specifiers plus their declared items.
+         (list
+          (list (concat "\\<\\(" fortran-type-types "\\)\\>[ \t(/]*\\(*\\)?")
+                ;; Fontify the type specifier.
+                '(1 font-lock-type-face)
+                ;; Fontify each declaration item (or just the /.../ block name).
+                `(font-lock-match-c-style-declaration-item-and-skip-to-next
+                  ;; Start after any *(...) expression.
+                  (condition-case nil
+                     (and (and (match-beginning ,(+ 2 (regexp-opt-depth
+                                                       fortran-type-types)))
+                               (forward-sexp))
+                          (forward-sexp))
+                   (error nil))
+                  ;; No need to clean up.
+                  nil
+                  ;; Fontify as a variable name, functions are
+                  ;; fontified elsewhere.
+                  (1 font-lock-variable-name-face nil t))))
+         ;;
+         ;; Things extra to `fortran-font-lock-keywords-3'
+         ;; (must be done first).
+         (list
+          ;;
+          ;; Fontify goto-like `err=label'/`end=label' in read/write
+          ;; statements.
+          '(", *\\(e\\(nd\\|rr\\)\\)\\> *\\(= *\\([0-9]+\\)\\)?"
+            (1 font-lock-keyword-face) (4 font-lock-constant-face nil t))
+          ;;
+          ;; Highlight standard continuation character and in a
+          ;; TAB-formatted line.
+          '("^     \\([^ 0]\\)" 1 font-lock-string-face)
+          '("^\t\\([1-9]\\)" 1 font-lock-string-face))
+         ;;
+         ;; The list `fortran-font-lock-keywords-2' less that for types
+         ;; (see above).
+         (cdr (nthcdr (length fortran-font-lock-keywords-1)
+                      fortran-font-lock-keywords-2)))))
+
+(defvar fortran-font-lock-keywords fortran-font-lock-keywords-1
+  "Default expressions to highlight in Fortran mode.")
+\f
+(defvar fortran-imenu-generic-expression
+  ;; These patterns could be confused by sequence nos. in cols 72+ and
+  ;; don't allow continuations everywhere.
+  (list
+   (list
+    nil
+    ;; Lines below are: 1. leading whitespace; 2. function
+    ;; declaration with optional type, e.g. `real', `real*4',
+    ;; character(*), `double precision' and possible statement
+    ;; continuation; 3. untyped declarations; 4. the variable to
+    ;; index.  [This will be fooled by `end function' allowed by G77.
+    ;; Also, it assumes sensible whitespace is employed.]
+    (concat "^\\s-+\\(\
+\\(\\sw\\|\\s-\\|[*()+]\\)*\
+\\<function\\|subroutine\\|entry\\|block\\s-*data\\|program\\)\
+[ \t" fortran-continuation-string "]+\
+\\(\\sw+\\)")
+    3)
+   ;; Un-named block data
+   (list nil "^\\s-+\\(block\\s-*data\\)\\s-*$" 1))
+  "Imenu generic expression for `imenu-default-create-index-function'.")
+
+(defvar fortran-mode-map ()
+  "Keymap used in Fortran mode.")
 (if fortran-mode-map
     ()
   (setq fortran-mode-map (make-sparse-keymap))
   (define-key fortran-mode-map ";" 'fortran-abbrev-start)
   (define-key fortran-mode-map "\C-c;" 'fortran-comment-region)
-  (define-key fortran-mode-map "\e\C-a" 'beginning-of-fortran-subprogram)
-  (define-key fortran-mode-map "\e\C-e" 'end-of-fortran-subprogram)
-  (define-key fortran-mode-map "\e;" 'fortran-indent-comment)
-  (define-key fortran-mode-map "\e\C-h" 'mark-fortran-subprogram)
-  (define-key fortran-mode-map "\e\n" 'fortran-split-line)
-  (define-key fortran-mode-map "\n" 'fortran-reindent-then-newline-and-indent)
-  (define-key fortran-mode-map "\e\C-q" 'fortran-indent-subprogram)
+  (define-key fortran-mode-map "\M-\C-a" 'beginning-of-fortran-subprogram)
+  (define-key fortran-mode-map "\M-\C-e" 'end-of-fortran-subprogram)
+  (define-key fortran-mode-map "\M-;" 'fortran-indent-comment)
+  (define-key fortran-mode-map "\M-\C-h" 'mark-fortran-subprogram)
+  (define-key fortran-mode-map "\M-\n" 'fortran-split-line)
+  (define-key fortran-mode-map "\n" 'fortran-indent-new-line)
+  (define-key fortran-mode-map "\M-\C-q" 'fortran-indent-subprogram)
   (define-key fortran-mode-map "\C-c\C-w" 'fortran-window-create-momentarily)
   (define-key fortran-mode-map "\C-c\C-r" 'fortran-column-ruler)
   (define-key fortran-mode-map "\C-c\C-p" 'fortran-previous-statement)
   (define-key fortran-mode-map "\C-c\C-n" 'fortran-next-statement)
-  (define-key fortran-mode-map "\t" 'fortran-indent-line)
+  (define-key fortran-mode-map "\C-c\C-d" 'fortran-join-line) ; like f90
+  (define-key fortran-mode-map "\M-^" 'fortran-join-line) ; subvert delete-indentation
+  (define-key fortran-mode-map "\C-xnd" 'fortran-narrow-to-subprogram)
+  ;(define-key fortran-mode-map "\t" 'fortran-indent-line)
   (define-key fortran-mode-map "0" 'fortran-electric-line-number)
   (define-key fortran-mode-map "1" 'fortran-electric-line-number)
   (define-key fortran-mode-map "2" 'fortran-electric-line-number)
@@ -218,7 +441,50 @@ Normally $.")
   (define-key fortran-mode-map "6" 'fortran-electric-line-number)
   (define-key fortran-mode-map "7" 'fortran-electric-line-number)
   (define-key fortran-mode-map "8" 'fortran-electric-line-number)
-  (define-key fortran-mode-map "9" 'fortran-electric-line-number))
+  (define-key fortran-mode-map "9" 'fortran-electric-line-number)
+
+  ;; Menu
+  (unless (boundp 'fortran-mode-menu)
+    (easy-menu-define
+     fortran-mode-menu fortran-mode-map ""
+     '("Fortran"
+       ["Toggle Auto-fill" fortran-auto-fill-mode :style toggle
+        :selected (eq auto-fill-function 'fortran-do-auto-fill)]
+       ["Toggle abbrev-mode" abbrev-mode :style toggle :selected abbrev-mode]
+       "----"
+       ["Comment-out Region" fortran-comment-region mark-active]
+       ["Uncomment-out region"
+        (fortran-comment-region (region-beginning) (region-end) 1)
+        mark-active]
+       ["Indent Region" indent-region mark-active]
+       ["Indent Subprogram" fortran-indent-subprogram t]
+       "----"
+       ["Beginning of Subprogram" beginning-of-fortran-subprogram t]
+       ["End of Subprogram" end-of-fortran-subprogram t]
+       ("Mark"
+        ["Subprogram" mark-fortran-subprogram t]
+        ["IF Block" fortran-mark-if t]
+        ["DO Block" fortran-mark-do t])
+       ["Narrow to Subprogram" fortran-narrow-to-subprogram t]
+       ["Widen" widen t]
+       "----"
+       ["Temporary column ruler" fortran-column-ruler t]
+       ["72-column window" fortran-window-create t]
+       ["Full Width Window"
+        (enlarge-window-horizontally (- (frame-width) (window-width)))
+        (< (window-width) (frame-width))]
+       ["Momentary 72-column window" fortran-window-create-momentarily t]
+       "----"
+       ["Break Line at Point" fortran-split-line t]
+       ["Join Line" fortran-join-line t]
+       ["Fill Statement/Comment" fill-paragraph  t]
+       "----"
+       ["Add imenu menu"
+        (progn (imenu-add-menubar-index)
+               ;; Prod menu bar to update -- is this the right way?
+               (menu-bar-mode 1))
+        (not (and (boundp 'imenu--index-alist)
+                 imenu--index-alist))]))))
 \f
 (defvar fortran-mode-abbrev-table nil)
 (if fortran-mode-abbrev-table
@@ -227,7 +493,7 @@ Normally $.")
     (define-abbrev-table 'fortran-mode-abbrev-table ())
     (define-abbrev fortran-mode-abbrev-table  ";au"  "automatic" nil)
     (define-abbrev fortran-mode-abbrev-table  ";b"   "byte" nil)
-    (define-abbrev fortran-mode-abbrev-table  ";bl"  "block data" nil)
+    (define-abbrev fortran-mode-abbrev-table  ";bd"  "block data" nil)
     (define-abbrev fortran-mode-abbrev-table  ";ch"  "character" nil)
     (define-abbrev fortran-mode-abbrev-table  ";cl"  "close" nil)
     (define-abbrev fortran-mode-abbrev-table  ";c"   "continue" nil)
@@ -244,6 +510,7 @@ Normally $.")
     (define-abbrev fortran-mode-abbrev-table  ";el"  "elseif" nil)
     (define-abbrev fortran-mode-abbrev-table  ";en"  "endif" nil)
     (define-abbrev fortran-mode-abbrev-table  ";eq"  "equivalence" nil)
+    (define-abbrev fortran-mode-abbrev-table  ";ew"  "endwhere" nil)
     (define-abbrev fortran-mode-abbrev-table  ";ex"  "external" nil)
     (define-abbrev fortran-mode-abbrev-table  ";ey"  "entry" nil)
     (define-abbrev fortran-mode-abbrev-table  ";f"   "format" nil)
@@ -281,83 +548,106 @@ Normally $.")
     (define-abbrev fortran-mode-abbrev-table  ";ty"  "type" nil)
     (define-abbrev fortran-mode-abbrev-table  ";vo"  "volatile" nil)
     (define-abbrev fortran-mode-abbrev-table  ";w"   "write" nil)
+    (define-abbrev fortran-mode-abbrev-table  ";wh"  "where" nil)
     (setq abbrevs-changed ac)))
 \f
+(eval-when-compile                     ; silence compiler
+  (defvar imenu-case-fold-search)
+  (defvar imenu-syntax-alist))
+
 ;;;###autoload
 (defun fortran-mode ()
-  "Major mode for editing fortran code.
-Tab indents the current fortran line correctly. 
-`do' statements must not share a common `continue'.
+  "Major mode for editing Fortran code.
+\\[fortran-indent-line] indents the current Fortran line correctly.
+DO statements must not share a common CONTINUE.
 
-Type `;?' or `;\\[help-command]' to display a list of built-in\
- abbrevs for Fortran keywords.
+Type ;? or ;\\[help-command] to display a list of built-in abbrevs for
+Fortran keywords.
 
 Key definitions:
 \\{fortran-mode-map}
 
 Variables controlling indentation style and extra features:
 
- comment-start
+ `comment-start'
     Normally nil in Fortran mode.  If you want to use comments
     starting with `!', set this to the string \"!\".
- fortran-do-indent
+ `fortran-do-indent'
     Extra indentation within do blocks.  (default 3)
- fortran-if-indent
+ `fortran-if-indent'
     Extra indentation within if blocks.  (default 3)
- fortran-continuation-indent
-    Extra indentation appled to continuation statements.  (default 5)
- fortran-comment-line-column
-    Amount of indentation for text within full-line comments. (default 6)
- fortran-comment-indent-style
+ `fortran-structure-indent'
+    Extra indentation within structure, union, map and interface blocks.
+    (default 3)
+ `fortran-continuation-indent'
+    Extra indentation applied to continuation statements.  (default 5)
+ `fortran-comment-line-extra-indent'
+    Amount of extra indentation for text within full-line comments.  (default 0)
+ `fortran-comment-indent-style'
     nil    means don't change indentation of text in full-line comments,
-    fixed  means indent that text at column fortran-comment-line-column
-    relative  means indent at fortran-comment-line-column beyond the
+    fixed  means indent that text at `fortran-comment-line-extra-indent' beyond
+           the value of `fortran-minimum-statement-indent-fixed' (for fixed
+           format continuation style) or `fortran-minimum-statement-indent-tab'
+           (for TAB format continuation style).
+    relative  means indent at `fortran-comment-line-extra-indent' beyond the
              indentation for a line of code.
     (default 'fixed)
- fortran-comment-indent-char
-    Single-character string be inserted instead of space for
+ `fortran-comment-indent-char'
+    Single-character string to be inserted instead of space for
     full-line comment indentation.  (default \" \")
- fortran-minimum-statement-indent
-    Minimum indentation for fortran statements. (default 6)
- fortran-line-number-indent
+ `fortran-minimum-statement-indent-fixed'
+    Minimum indentation for Fortran statements in fixed format mode.  (def.6)
+ `fortran-minimum-statement-indent-tab'
+    Minimum indentation for Fortran statements in TAB format mode.  (default 9)
+ `fortran-line-number-indent'
     Maximum indentation for line numbers.  A line number will get
     less than this much indentation if necessary to avoid reaching
     column 5.  (default 1)
- fortran-check-all-num-for-matching-do
-    Non-nil causes all numbered lines to be treated as possible 'continue'
+ `fortran-check-all-num-for-matching-do'
+    Non-nil causes all numbered lines to be treated as possible \"continue\"
     statements.  (default nil)
- fortran-blink-matching-if 
-    From a fortran `endif' statement, blink the matching `if' statement.
-    (default nil)
- fortran-continuation-string
+ `fortran-blink-matching-if'
+    Non-nil causes \\[fortran-indent-line] on an ENDIF statement to blink on
+    matching IF.  Also, from an ENDDO statement, blink on matching DO [WHILE]
+    statement.  (default nil)
+ `fortran-continuation-string'
     Single-character string to be inserted in column 5 of a continuation
     line.  (default \"$\")
- fortran-comment-region
-    String inserted by \\[fortran-comment-region] at start of each line in 
+ `fortran-comment-region'
+    String inserted by \\[fortran-comment-region] at start of each line in
     region.  (default \"c$$$\")
- fortran-electric-line-number
-    Non-nil causes line number digits to be moved to the correct column 
+ `fortran-electric-line-number'
+    Non-nil causes line number digits to be moved to the correct column
     as typed.  (default t)
- fortran-startup-message
-    Set to nil to inhibit message first time Fortran mode is used.
+ `fortran-break-before-delimiters'
+    Non-nil causes `fortran-fill' to break lines before delimiters.
+    (default t)
 
-Turning on Fortran mode calls the value of the variable fortran-mode-hook 
+Turning on Fortran mode calls the value of the variable `fortran-mode-hook'
 with no args, if that value is non-nil."
   (interactive)
   (kill-all-local-variables)
-  (if fortran-startup-message
-      (message "Emacs Fortran mode version %s.  Bugs to %s"
-              fortran-mode-version bug-fortran-mode))
-  (setq fortran-startup-message nil)
   (setq local-abbrev-table fortran-mode-abbrev-table)
   (set-syntax-table fortran-mode-syntax-table)
+  ;; Font Lock mode support.
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '((fortran-font-lock-keywords
+                             fortran-font-lock-keywords-1
+                             fortran-font-lock-keywords-2
+                             fortran-font-lock-keywords-3)
+                            nil t ((?/ . "$/") ("_$" . "w"))
+                            beginning-of-fortran-subprogram))
+  (set (make-local-variable 'font-lock-syntactic-keywords)
+       fortran-font-lock-syntactic-keywords)
+  (make-local-variable 'fortran-break-before-delimiters)
+  (setq fortran-break-before-delimiters t)
   (make-local-variable 'indent-line-function)
   (setq indent-line-function 'fortran-indent-line)
-  (make-local-variable 'comment-indent-hook)
-  (setq comment-indent-hook 'fortran-comment-hook)
+  (make-local-variable 'comment-indent-function)
+  (setq comment-indent-function 'fortran-comment-hook)
   (make-local-variable 'comment-line-start-skip)
   (setq comment-line-start-skip
-       "^[Cc*]\\(\\([^ \t\n]\\)\\1*\\)?[ \t]*") ;[^ \t\n]* handles c$$$
+       "^[Cc*]\\(\\([^ \t\n]\\)\\2\\2*\\)?[ \t]*\\|^#.*")
   (make-local-variable 'comment-line-start)
   (setq comment-line-start "c")
   (make-local-variable 'comment-start-skip)
@@ -370,16 +660,29 @@ with no args, if that value is non-nil."
   (setq abbrev-all-caps t)
   (make-local-variable 'indent-tabs-mode)
   (setq indent-tabs-mode nil)
-  (setq abbrev-mode t) ; ?? (abbrev-mode 1) instead??
+;;;(setq abbrev-mode t) ; ?? (abbrev-mode 1) instead??
+  (set (make-local-variable 'fill-column) 72)
   (use-local-map fortran-mode-map)
   (setq mode-name "Fortran")
   (setq major-mode 'fortran-mode)
-  (make-local-variable 'fortran-tab-mode)
-  (make-local-variable 'fortran-comment-line-column)
-  (make-local-variable 'fortran-minimum-statement-indent)
-  (make-local-variable 'fortran-column-ruler)
-  (make-local-variable 'fortran-tab-mode-string)
-  (fortran-tab-mode (fortran-analyze-file-format))
+  (make-local-variable 'fortran-comment-line-extra-indent)
+  (make-local-variable 'fortran-minimum-statement-indent-fixed)
+  (make-local-variable 'fortran-minimum-statement-indent-tab)
+  (make-local-variable 'fortran-column-ruler-fixed)
+  (make-local-variable 'fortran-column-ruler-tab)
+  (setq fortran-tab-mode-string " TAB-format")
+  (setq indent-tabs-mode (fortran-analyze-file-format))
+  (setq imenu-case-fold-search t)
+  (make-local-variable 'imenu-generic-expression)
+  (setq imenu-generic-expression fortran-imenu-generic-expression)
+  (setq imenu-syntax-alist '(("_$" . "w")))
+  (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
+  (set (make-local-variable 'indent-line-function) 'fortran-indent-line)
+  (set (make-local-variable 'indent-region-function)
+       (lambda (start end)
+         (let (fortran-blink-matching-if ; avoid blinking delay
+               indent-region-function)
+           (indent-region start end nil))))
   (run-hooks 'fortran-mode-hook))
 \f
 (defun fortran-comment-hook ()
@@ -392,7 +695,7 @@ with no args, if that value is non-nil."
   "Align or create comment on current line.
 Existing comments of all types are recognized and aligned.
 If the line has no comment, a side-by-side comment is inserted and aligned
-if the value of  comment-start  is not nil.
+if the value of  `comment-start'  is not nil.
 Otherwise, a separate-line comment is inserted, on this line
 or on a new line inserted before this line if this line is not blank."
   (interactive)
@@ -400,9 +703,14 @@ or on a new line inserted before this line if this line is not blank."
   ;; Recognize existing comments of either kind.
   (cond ((looking-at comment-line-start-skip)
         (fortran-indent-line))
-       ((re-search-forward comment-start-skip
-                           (save-excursion (end-of-line) (point)) t)
-        (indent-for-comment))
+       ((fortran-find-comment-start-skip) ; catches any inline comment and
+                                       ; leaves point after comment-start-skip
+        (if comment-start-skip
+            (progn (goto-char (match-beginning 0))
+                   (if (not (= (current-column) (fortran-comment-hook)))
+                       (progn (delete-horizontal-space)
+                              (indent-to (fortran-comment-hook)))))
+          (end-of-line)))        ; otherwise goto end of line or sth else?
        ;; No existing comment.
        ;; If side-by-side comments are defined, insert one,
        ;; unless line is now blank.
@@ -421,13 +729,13 @@ or on a new line inserted before this line if this line is not blank."
         (insert comment-line-start)
         (insert-char (if (stringp fortran-comment-indent-char)
                          (aref fortran-comment-indent-char 0)
-                         fortran-comment-indent-char)
-                     (- (calculate-fortran-indent) (current-column))))))
+                       fortran-comment-indent-char)
+                     (- (fortran-calculate-indent) (current-column))))))
 
 (defun fortran-comment-region (beg-region end-region arg)
   "Comments every line in the region.
-Puts fortran-comment-region at the beginning of every line in the region. 
-BEG-REGION and END-REGION are args which specify the region boundaries. 
+Puts `fortran-comment-region' at the beginning of every line in the region.
+BEG-REGION and END-REGION are args which specify the region boundaries.
 With non-nil ARG, uncomments the region."
   (interactive "*r\nP")
   (let ((end-region-mark (make-marker)) (save-point (point-marker)))
@@ -451,63 +759,85 @@ With non-nil ARG, uncomments the region."
     (set-marker save-point nil)))
 \f
 (defun fortran-abbrev-start ()
-  "Typing \";\\[help-command]\" or \";?\" lists all the fortran abbrevs. 
+  "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs.
 Any other key combination is executed normally."
   (interactive)
   (let (c)
     (insert last-command-char)
-    (if (or (= (setq c (read-char)) ??)        ;insert char if not equal to `?'
-           (= c help-char))
+    (if (or (eq (setq c (read-event)) ??)    ;insert char if not equal to `?'
+           (eq c help-char))
        (fortran-abbrev-help)
-      (setq unread-command-char c))))
+      (setq unread-command-events (list c)))))
 
 (defun fortran-abbrev-help ()
   "List the currently defined abbrevs in Fortran mode."
   (interactive)
   (message "Listing abbrev table...")
-  (require 'abbrevlist)
-  (list-one-abbrev-table fortran-mode-abbrev-table "*Help*")
+  (display-buffer (fortran-prepare-abbrev-list-buffer))
   (message "Listing abbrev table...done"))
 
+(defun fortran-prepare-abbrev-list-buffer ()
+  (save-excursion
+    (set-buffer (get-buffer-create "*Abbrevs*"))
+    (erase-buffer)
+    (insert-abbrev-table-description 'fortran-mode-abbrev-table t)
+    (goto-char (point-min))
+    (set-buffer-modified-p nil)
+    (edit-abbrevs-mode))
+  (get-buffer-create "*Abbrevs*"))
+
 (defun fortran-column-ruler ()
-  "Inserts a column ruler momentarily above current line, till next keystroke.
-The ruler is defined by the value of fortran-column-ruler.
+  "Insert a column ruler momentarily above current line, till next keystroke.
+The ruler is defined by the value of `fortran-column-ruler-fixed' when in fixed
+format mode, and `fortran-column-ruler-tab' when in TAB format mode.
 The key typed is executed unless it is SPC."
   (interactive)
-  (momentary-string-display 
-   fortran-column-ruler (save-excursion (beginning-of-line) (point))
+  (momentary-string-display
+   (if indent-tabs-mode
+       fortran-column-ruler-tab
+     fortran-column-ruler-fixed)
+   (save-excursion
+     (beginning-of-line)
+     (if (eq (window-start (selected-window))
+            (window-point (selected-window)))
+        (progn (forward-line) (point))
+       (point)))
    nil "Type SPC or any command to erase ruler."))
 
 (defun fortran-window-create ()
-  "Makes the window 72 columns wide.
-See also fortran-window-create-momentarily."
+  "Make the window 72 columns wide.
+See also `fortran-window-create-momentarily'."
   (interactive)
   (condition-case error
       (progn
        (let ((window-min-width 2))
-         (if (< (window-width) (screen-width))
-             (enlarge-window-horizontally (- (screen-width)
+         (if (< (window-width) (frame-width))
+             (enlarge-window-horizontally (- (frame-width)
                                              (window-width) 1)))
-         (split-window-horizontally 73)
+         (let* ((window-edges (window-edges))
+                (scroll-bar-width (- (nth 2 window-edges)
+                                     (car window-edges)
+                                     (window-width))))
+           (split-window-horizontally (+ 72 scroll-bar-width)))
          (other-window 1)
          (switch-to-buffer " fortran-window-extra" t)
          (select-window (previous-window))))
-    (error (message "No room for fortran window.")
+    (error (message "No room for Fortran window.")
           'error)))
 
 (defun fortran-window-create-momentarily (&optional arg)
-  "Momentarily makes the window 72 columns wide.
+  "Momentarily make the window 72 columns wide.
 Optional ARG non-nil and non-unity disables the momentary feature.
-See also fortran-window-create."
+See also `fortran-window-create'."
   (interactive "p")
   (if (or (not arg)
          (= arg 1))
       (save-window-excursion
        (if (not (equal (fortran-window-create) 'error))
            (progn (message "Type SPC to continue editing.")
-                  (let ((char (read-char)))
+                  (let ((char (read-event)))
                     (or (equal char (string-to-char " "))
-                        (setq unread-command-char char))))))
+                        (setq unread-command-events (list char)))))))
     (fortran-window-create)))
 
 (defun fortran-split-line ()
@@ -516,15 +846,36 @@ See also fortran-window-create."
   (delete-horizontal-space)
   (if (save-excursion (beginning-of-line) (looking-at comment-line-start-skip))
       (insert "\n" comment-line-start " ")
-    (if fortran-tab-mode
-       (progn 
-         (insert "\n\t")
-         (insert-char (fortran-numerical-continuation-char) 1))
-      (insert "\n" fortran-continuation-string)))
-    (fortran-indent-line))
+    (if indent-tabs-mode
+       (insert "\n\t" (fortran-numerical-continuation-char))
+      (insert "\n " fortran-continuation-string))) ; Space after \n important
+  (fortran-indent-line))               ; when the cont string is C, c or *.
+
+(defun fortran-remove-continuation ()
+  (if (looking-at "\\(     [^ 0\n]\\|\t[1-9]\\|&\\)")
+      (progn (replace-match "")
+            (delete-indentation)
+            t)))
+
+(defun fortran-join-line (arg)
+  "Join current line to the previous one and re-indent.
+With a prefix argument, repeat this operation that many times.
+If the prefix argument ARG is negative, join the next -ARG lines.
+Continuation lines are correctly handled."
+  (interactive "*p")
+  (save-excursion
+    (when (> 0 arg)
+      (setq arg (- arg))
+      (forward-line arg))
+    (while (not (zerop arg))
+      (beginning-of-line)
+      (or (fortran-remove-continuation)
+          (delete-indentation))
+      (setq arg (1- arg)))
+    (fortran-indent-line)))
 
 (defun fortran-numerical-continuation-char ()
-  "Return a digit for tab-digit style of continution lines.
+  "Return a digit for tab-digit style of continuation lines.
 If, previous line is a tab-digit continuation line, returns that digit
 plus one.  Otherwise return 1.  Zero not allowed."
   (save-excursion
@@ -541,78 +892,112 @@ except that ] is never special and \ quotes ^, - or \."
   (skip-chars-backward chars)
   (delete-region (point) (progn (skip-chars-forward chars) (point))))
 
+(put 'fortran-electric-line-number 'delete-selection t)
 (defun fortran-electric-line-number (arg)
   "Self insert, but if part of a Fortran line number indent it automatically.
-Auto-indent does not happen if a numeric arg is used."
-;The use of arg may be superfluous here since there apears to be no way to
-;prefix a digit key with an argument.
+Auto-indent does not happen if a numeric ARG is used."
   (interactive "P")
   (if (or arg (not fortran-electric-line-number))
-      (if arg 
-         (self-insert-command arg)
+      (if arg
+         (self-insert-command (prefix-numeric-value arg))
        (self-insert-command 1))
     (if (or (and (= 5 (current-column))
                 (save-excursion
                   (beginning-of-line)
                   (looking-at "     ")));In col 5 with only spaces to left.
-           (and (= fortran-minimum-statement-indent (current-column))
+           (and (= (if indent-tabs-mode
+                       fortran-minimum-statement-indent-tab
+                     fortran-minimum-statement-indent-fixed) (current-column))
                 (save-excursion
                   (beginning-of-line)
                   (looking-at "\t"));In col 8 with a single tab to the left.
                 (not (or (eq last-command 'fortran-indent-line)
                          (eq last-command
-                             'fortran-reindent-then-newline-and-indent))))
+                             'fortran-indent-new-line))))
            (save-excursion
              (re-search-backward "[^ \t0-9]"
                                  (save-excursion
                                    (beginning-of-line)
                                    (point))
-                                 t)) ;not a line number
-           (looking-at "[0-9]")        ;within a line number
-           )
-       (insert last-command-char)
+                                 t))   ;not a line number
+           (looking-at "[0-9]"))       ;within a line number
+       (self-insert-command (prefix-numeric-value arg))
       (skip-chars-backward " \t")
       (insert last-command-char)
       (fortran-indent-line))))
 \f
+(defvar fortran-end-prog-re1
+  "end\
+\\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\
+\\([ \t]*\\(\\sw\\|\\s_\\)+\\)?\\)?")
+(defvar fortran-end-prog-re
+  (concat "^[ \t0-9]*" fortran-end-prog-re1)
+  "Regexp possibly marking subprogram end.")
+
+(defun fortran-check-end-prog-re ()
+  "Check a preliminary match against `fortran-end-prog-re'."
+  ;; Having got a possible match for the subprogram end, we need a
+  ;; 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.
 (defun beginning-of-fortran-subprogram ()
-  "Moves point to the beginning of the current fortran subprogram."
+  "Moves point to the beginning of the current Fortran subprogram."
   (interactive)
-  (let ((case-fold-search t))
-    (beginning-of-line -1)
-    (re-search-backward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
-    (if (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")
-       (forward-line 1))))
+  (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)))))
 
 (defun end-of-fortran-subprogram ()
-  "Moves point to the end of the current fortran subprogram."
+  "Moves point to the end of the current Fortran subprogram."
   (interactive)
-  (let ((case-fold-search t))
-    (beginning-of-line 2)
-    (re-search-forward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
-    (goto-char (match-beginning 0))
-    (forward-line 1)))
+  (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)))))
 
 (defun mark-fortran-subprogram ()
-  "Put mark at end of fortran subprogram, point at beginning. 
+  "Put mark at end of Fortran subprogram, point at beginning.
 The marks are pushed."
   (interactive)
   (end-of-fortran-subprogram)
-  (push-mark (point))
+  (push-mark (point) nil t)
   (beginning-of-fortran-subprogram))
-  
+
 (defun fortran-previous-statement ()
-  "Moves point to beginning of the previous fortran statement.
-Returns 'first-statement if that statement is the first
+  "Moves point to beginning of the previous Fortran statement.
+Returns `first-statement' if that statement is the first
 non-comment Fortran statement in the file, and nil otherwise."
   (interactive)
   (let (not-first-statement continue-test)
     (beginning-of-line)
     (setq continue-test
-         (or (looking-at
+         (and
+          (not (looking-at comment-line-start-skip))
+          (or (looking-at
                (concat "[ \t]*" (regexp-quote fortran-continuation-string)))
-             (or (looking-at "     [^ 0\n]")
-                  (looking-at "\t[1-9]"))))
+              (or (looking-at "     [^ 0\n]")
+                  (looking-at "\t[1-9]")))))
     (while (and (setq not-first-statement (= (forward-line -1) 0))
                (or (looking-at comment-line-start-skip)
                    (looking-at "[ \t]*$")
@@ -622,19 +1007,21 @@ non-comment Fortran statement in the file, and nil otherwise."
     (cond ((and continue-test
                (not not-first-statement))
           (message "Incomplete continuation statement."))
-         (continue-test        
+         (continue-test
           (fortran-previous-statement))
          ((not not-first-statement)
           'first-statement))))
 
 (defun fortran-next-statement ()
-  "Moves point to beginning of the next fortran statement.
+  "Moves point to beginning of the next Fortran statement.
 Returns `last-statement' if that statement is the last
 non-comment Fortran statement in the file, and nil otherwise."
   (interactive)
   (let (not-last-statement)
     (beginning-of-line)
-    (while (and (setq not-last-statement (= (forward-line 1) 0))
+    (while (and (setq not-last-statement
+                     (and (= (forward-line 1) 0)
+                          (not (eobp))))
                (or (looking-at comment-line-start-skip)
                    (looking-at "[ \t]*$")
                    (looking-at "     [^ 0\n]")
@@ -642,60 +1029,277 @@ non-comment Fortran statement in the file, and nil otherwise."
                    (looking-at (concat "[ \t]*"  comment-start-skip)))))
     (if (not not-last-statement)
        'last-statement)))
+
+(defun fortran-narrow-to-subprogram ()
+  "Make text outside the current subprogram invisible.
+The subprogram visible is the one that contains or follows point."
+  (interactive)
+  (save-excursion
+    (mark-fortran-subprogram)
+    (narrow-to-region (point) (mark))))
+
+(defmacro fortran-with-subprogram-narrowing (&rest forms)
+  "Execute FORMS with buffer temporarily narrowed to current subprogram.
+Doesn't push a mark."
+  `(save-restriction
+     (save-excursion
+       (narrow-to-region (progn
+                          (beginning-of-fortran-subprogram)
+                          (point))
+                        (progn
+                          (end-of-fortran-subprogram)
+                          (point))))
+     ,@forms))
 \f
 (defun fortran-blink-matching-if ()
-  "From a fortran `endif' statement, blink the matching `if' statement."
-  (let ((count 1) (top-of-window (window-start)) matching-if
-       (endif-point (point)) message)
+  "From an ENDIF statement, blink the matching IF statement."
+  (let ((top-of-window (window-start))
+       (endif-point (point))
+       (case-fold-search t)
+       matching-if
+       message)
     (if (save-excursion (beginning-of-line)
                        (skip-chars-forward " \t0-9")
-                       (looking-at "end[ \t]*if\\b"))
+                       (looking-at "e\\(nd[ \t]*if\\|lse\\([ \t]*if\\)?\\)\\b"))
        (progn
-         (save-excursion
-           (while (and (not (= count 0))
-                       (not (eq (fortran-previous-statement)
-                                'first-statement))
-                       (not (looking-at
-                             "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")))
-                                       ; Keep local to subprogram
-             (skip-chars-forward " \t0-9")
-             (cond ((looking-at "if[ \t]*(")
-                    (save-excursion (if (or (looking-at ".*)[
-\t]*then\\b[ \t]*[^ \t(=a-z0-9]")
-                                            (let (then-test);multi-line if-then
-                                              (while (and (= (forward-line 1) 0)
-                                       ;search forward for then
-                                                          (or
-(looking-at "     [^ 0\n]")
-                                                             
-(looking-at "\t[1-9]"))
-                                                          (not (setq
-then-test (looking-at
-                                                               
-        ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
-                                            then-test))
-                    (setq count (- count 1)))))
-                   ((looking-at "end[ \t]*if\\b")
-                    (setq count (+ count 1)))))
-           (if (not (= count 0))
-               (setq message "No matching if.")
-             (if (< (point) top-of-window)
-                 (setq message (concat "Matches " (buffer-substring
-                                                   (progn (beginning-of-line)
-                                                          (point))
-                                                   (progn (end-of-line)
-                                                          (point)))))
-               (setq matching-if (point)))))
+          (if (not (setq matching-if (fortran-beginning-if)))
+              (setq message "No matching if.")
+            (if (< matching-if top-of-window)
+                (save-excursion
+                  (goto-char matching-if)
+                  (beginning-of-line)
+                  (setq message
+                        (concat "Matches "
+                                (buffer-substring
+                                 (point) (progn (end-of-line) (point))))))))
          (if message
-             (message message)
+             (message "%s" message)
            (goto-char matching-if)
            (sit-for 1)
            (goto-char endif-point))))))
+
+(defun fortran-blink-matching-do ()
+  "From an ENDDO statement, blink the matching DO or DO WHILE statement."
+  ;; This is basically copied from fortran-blink-matching-if.
+  (let ((top-of-window (window-start))
+       (enddo-point (point))
+       (case-fold-search t)
+       matching-do
+       message)
+    (if (save-excursion (beginning-of-line)
+                       (skip-chars-forward " \t0-9")
+                       (looking-at "end[ \t]*do\\b"))
+       (progn
+          (if (not (setq matching-do (fortran-beginning-do)))
+              (setq message "No matching do.")
+            (if (< matching-do top-of-window)
+                (save-excursion
+                  (goto-char matching-do)
+                  (beginning-of-line)
+                  (setq message
+                        (concat "Matches "
+                                (buffer-substring
+                                 (point) (progn (end-of-line) (point))))))))
+         (if message
+             (message "%s" message)
+           (goto-char matching-do)
+           (sit-for 1)
+           (goto-char enddo-point))))))
+
+(defun fortran-mark-do ()
+  "Put mark at end of Fortran DO [WHILE]-ENDDO construct, point at beginning.
+The marks are pushed."
+  (interactive)
+  (let (enddo-point do-point)
+    (if (setq enddo-point (fortran-end-do))
+        (if (not (setq do-point (fortran-beginning-do)))
+            (message "No matching do.")
+          ;; Set mark, move point.
+          (goto-char enddo-point)
+          (push-mark)
+          (goto-char do-point)))))
+
+(defun fortran-end-do ()
+  "Search forward for first unmatched ENDDO.
+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)
+      ;; Search for one.
+      (save-excursion
+       (let ((count 1))
+        (while (and (not (= count 0))
+                     (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 (+ count 1)))))
+        (and (= count 0)
+              ;; All pairs accounted for.
+              (point)))))))
+
+(defun fortran-beginning-do ()
+  "Search backwards for first unmatched DO [WHILE].
+Return point or nil."
+  (let ((case-fold-search t))
+    (if (save-excursion (beginning-of-line)
+                       (skip-chars-forward " \t0-9")
+                       (looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+"))
+       ;; Sitting on one.
+       (match-beginning 0)
+      ;; Search for one.
+      (save-excursion
+       (let ((count 1))
+        (while (and (not (= count 0))
+                     (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 "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]")
+                  (setq count (1- count)))
+                 ((looking-at "end[ \t]*do\\b")
+                  (setq count (1+ count)))))
+
+        (and (= count 0)
+              ;; All pairs accounted for.
+              (point)))))))
+
+(defun fortran-mark-if ()
+  "Put mark at end of Fortran IF-ENDIF construct, point at beginning.
+The marks are pushed."
+  (interactive)
+  (let (endif-point if-point)
+    (if (setq endif-point (fortran-end-if))
+        (if (not (setq if-point (fortran-beginning-if)))
+            (message "No matching if.")
+          ;; Set mark, move point.
+          (goto-char endif-point)
+          (push-mark)
+          (goto-char if-point)))))
+
+(defvar fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(")
+
+(defun fortran-end-if ()
+  "Search forwards for first unmatched ENDIF.
+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)
+      ;; 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 (= count 0))
+                     (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 (- count 1)))
+
+                 ((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 (= (forward-line 1) 0)
+                                    ;; Search forward for then.
+                                    (or (looking-at "     [^ 0\n]")
+                                        (looking-at "\t[1-9]"))
+                                    (not
+                                     (setq then-test
+                                           (looking-at
+                                            ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
+                           then-test))
+                       (setq count (+ count 1)))))))
+
+        (and (= count 0)
+              ;; All pairs accounted for.
+              (point)))))))
+
+(defun fortran-beginning-if ()
+  "Search backwards for first unmatched IF-THEN.
+Return point or nil."
+  (let ((case-fold-search t))
+    (if (save-excursion
+         ;; May be sitting on multi-line if-then statement, first move to
+         ;; beginning of current statement.  Note: `fortran-previous-statement'
+         ;; moves to previous statement *unless* current statement is first
+         ;; one.  Only move forward if not first-statement.
+         (if (not (eq (fortran-previous-statement) 'first-statement))
+             (fortran-next-statement))
+         (skip-chars-forward " \t0-9")
+         (and
+          (looking-at fortran-if-start-re)
+          (save-match-data
+            (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
+                ;; Multi-line if-then.
+                (let (then-test)
+                  (while
+                     (and (= (forward-line 1) 0)
+                           ;; Search forward for then.
+                           (or (looking-at "     [^ 0\n]")
+                               (looking-at "\t[1-9]"))
+                           (not
+                            (setq then-test
+                                  (looking-at
+                                   ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
+                  then-test)))))
+       ;; Sitting on one.
+       (match-beginning 0)
+      ;; Search for one.
+      (save-excursion
+       (let ((count 1))
+        (while (and (not (= count 0))
+                     (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 (= (forward-line 1) 0)
+                                    ;; Search forward for then.
+                                    (or (looking-at "     [^ 0\n]")
+                                        (looking-at "\t[1-9]"))
+                                    (not
+                                     (setq then-test
+                                           (looking-at
+                                            ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
+                           then-test))
+                       (setq count (- count 1)))))
+                 ((looking-at "end[ \t]*if\\b")
+                 (setq count (+ count 1)))))
+
+        (and (= count 0)
+              ;; All pairs accounted for.
+              (point)))))))
 \f
 (defun fortran-indent-line ()
-  "Indents current fortran line based on its contents and on previous lines."
+  "Indent current Fortran line based on its contents and on previous lines."
   (interactive)
-  (let ((cfi (calculate-fortran-indent)))
+  (let ((cfi (fortran-calculate-indent)))
     (save-excursion
       (beginning-of-line)
       (if (or (not (= cfi (fortran-current-line-indentation)))
@@ -704,33 +1308,40 @@ then-test (looking-at
          (fortran-indent-to-column cfi)
        (beginning-of-line)
        (if (and (not (looking-at comment-line-start-skip))
-                (re-search-forward comment-start-skip
-                              (save-excursion (end-of-line) (point)) 'move))
+                (fortran-find-comment-start-skip))
            (fortran-indent-comment))))
     ;; Never leave point in left margin.
     (if (< (current-column) cfi)
        (move-to-column cfi))
+    (if (and auto-fill-function
+            (> (save-excursion (end-of-line) (current-column)) fill-column))
+       (save-excursion
+         (end-of-line)
+         (fortran-fill)))
     (if fortran-blink-matching-if
-       (fortran-blink-matching-if))))
+        (progn
+         (fortran-blink-matching-if)
+         (fortran-blink-matching-do)))))
 
-(defun fortran-reindent-then-newline-and-indent ()
-  "Reindent the current fortran line, insert a newline and indent the newline.
-An abbrev before point is expanded if abbrev-mode is non-nil."
+(defun fortran-indent-new-line ()
+  "Reindent the current Fortran line, insert a newline and indent the newline.
+An abbrev before point is expanded if variable `abbrev-mode' is non-nil."
   (interactive)
   (if abbrev-mode (expand-abbrev))
   (save-excursion
     (beginning-of-line)
     (skip-chars-forward " \t")
-    (if (or (looking-at "[0-9]")       ;Reindent only where it is most
-           (looking-at "end")          ;likely to be necessary
-           (looking-at "else")
-           (looking-at (regexp-quote fortran-continuation-string)))
-       (fortran-indent-line)))
-  (insert "\n")
+    (let ((case-fold-search t))
+      (if (or (looking-at "[0-9]")     ;Reindent only where it is most
+             (looking-at "end")        ;likely to be necessary
+             (looking-at "else")
+             (looking-at (regexp-quote fortran-continuation-string)))
+         (fortran-indent-line))))
+  (newline)
   (fortran-indent-line))
-    
+
 (defun fortran-indent-subprogram ()
-  "Properly indents the Fortran subprogram which contains point."
+  "Properly indent the Fortran subprogram which contains point."
   (interactive)
   (save-excursion
     (mark-fortran-subprogram)
@@ -738,11 +1349,13 @@ An abbrev before point is expanded if abbrev-mode is non-nil."
     (indent-region (point) (mark) nil))
   (message "Indenting subprogram...done."))
 
-(defun calculate-fortran-indent ()
-  "Calculates the fortran indent column based on previous lines."
+(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
-             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
@@ -752,38 +1365,57 @@ An abbrev before point is expanded if abbrev-mode is non-nil."
              (setq icol fortran-minimum-statement-indent)
            (setq icol (fortran-current-line-indentation)))
          (skip-chars-forward " \t0-9")
-         (cond ((looking-at "if[ \t]*(")
-                (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-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
                           (while (and (= (forward-line 1) 0)
-                                       ;search forward for then
+                                      ;;search forward for then
                                       (or (looking-at "     [^ 0\n]")
                                           (looking-at "\t[1-9]"))
                                       (not (setq then-test (looking-at
- ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
+                                                            ".*then\\b[ \t]\
+*[^ \t_$(=a-z0-9]")))))
                           then-test))
                     (setq icol (+ icol fortran-if-indent))))
-               ((looking-at "\\(else\\|elseif\\)\\b")
+               ((looking-at "else\\(if\\)?\\b")
+                (setq icol (+ icol fortran-if-indent)))
+               ((looking-at "select[ \t]*case[ \t](.*)")
+                (setq icol (+ icol fortran-if-indent)))
+               ((looking-at "case[ \t]*(.*)")
+                (setq icol (+ icol fortran-if-indent)))
+               ((looking-at "case[ \t]*default\\b")
+                (setq icol (+ icol fortran-if-indent)))
+               ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
+                (setq icol (+ icol fortran-if-indent)))
+               ((looking-at "where[ \t]*(.*)[ \t]*\n")
                 (setq icol (+ icol fortran-if-indent)))
                ((looking-at "do\\b")
                 (setq icol (+ icol fortran-do-indent)))
-               ((looking-at "end\\b[ \t]*[^ \t=(a-z]")
-                                       ; Previous END resets indent to minimum
+               ((looking-at
+                 "\\(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))
+                ;; Previous END resets indent to minimum
                 (setq icol fortran-minimum-statement-indent))))))
     (save-excursion
       (beginning-of-line)
       (cond ((looking-at "[ \t]*$"))
            ((looking-at comment-line-start-skip)
-            (setq fortran-minimum-statement-indent 0)
             (cond ((eq fortran-comment-indent-style 'relative)
-                   (setq icol (+ icol fortran-comment-line-column)))
+                   (setq icol (+ icol fortran-comment-line-extra-indent)))
                   ((eq fortran-comment-indent-style 'fixed)
-                   (setq icol fortran-comment-line-column))))
+                   (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)))
+                                    (regexp-quote
+                                     fortran-continuation-string)))
                 (looking-at "     [^ 0\n]")
                 (looking-at "\t[1-9]"))
             (setq icol (+ icol fortran-continuation-indent)))
+           ((looking-at "[ \t]*#")     ; Check for cpp directive.
+            (setq fortran-minimum-statement-indent 0 icol 0))
            (first-statement)
            ((and fortran-check-all-num-for-matching-do
                  (looking-at "[ \t]*[0-9]+")
@@ -791,16 +1423,24 @@ An abbrev before point is expanded if abbrev-mode is non-nil."
             (setq icol (- icol fortran-do-indent)))
            (t
             (skip-chars-forward " \t0-9")
-            (cond ((looking-at "end[ \t]*if\\b")
+            (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 "\\(else\\|elseif\\)\\b")
+                   ((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)))
-                  ((and (looking-at "end\\b[ \t]*[^ \t=(a-z]")
+                  ((looking-at "end[ \t]*\
+\\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]")
+                   (setq icol (- icol fortran-structure-indent)))
+                  ((and (looking-at fortran-end-prog-re1)
+                        (fortran-check-end-prog-re)
                         (not (= icol fortran-minimum-statement-indent)))
                    (message "Warning: `end' not in column %d.  Probably\
  an unclosed block." fortran-minimum-statement-indent))))))
@@ -817,62 +1457,66 @@ non-indentation text within the comment."
     (cond ((looking-at 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))))
+           (if (stringp fortran-comment-indent-char)
+               fortran-comment-indent-char
+             (char-to-string fortran-comment-indent-char))))
          ((or (looking-at "     [^ 0\n]")
-             (looking-at "\t[1-9]"))
+              (looking-at "\t[1-9]"))
           (goto-char (match-end 0)))
          (t
           ;; Move past line number.
-          (re-search-forward "^[ \t0-9]*" (+ (point) 4) t)))
+          (skip-chars-forward "[ \t0-9]");From Uli
+          ))
     ;; Move past whitespace.
     (skip-chars-forward " \t")
     (current-column)))
 
 (defun fortran-indent-to-column (col)
-  "Indents current line with spaces to column COL.
+  "Indent current line with spaces to column COL.
 notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
           line, and this continuation character is retained on indentation;
-       2) If fortran-continuation-string is the first non-whitespace character,
-          this is a continuation line;
+       2) If `fortran-continuation-string' is the first non-whitespace
+          character, this is a continuation line;
        3) A non-continuation line which has a number as the first
           non-whitespace character is a numbered line.
-       4) A tab followed by a digit indicates a continuation line."
+       4) A TAB followed by a digit indicates a continuation line."
   (save-excursion
     (beginning-of-line)
     (if (looking-at 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)))
+                         fortran-comment-indent-char)))
              (goto-char (match-end 0))
              (delete-horizontal-regexp (concat " \t" (char-to-string char)))
              (insert-char char (- col (current-column)))))
       (if (looking-at "\t[1-9]")
-         (if fortran-tab-mode
+         (if indent-tabs-mode
              (goto-char (match-end 0))
            (delete-char 2)
            (insert "     ")
            (insert fortran-continuation-string))
        (if (looking-at "     [^ 0\n]")
-           (if fortran-tab-mode
+           (if indent-tabs-mode
                (progn (delete-char 6)
                       (insert "\t")
                       (insert-char (fortran-numerical-continuation-char) 1))
              (forward-char 6))
          (delete-horizontal-space)
-       ;; Put line number in columns 0-4
-       ;; or put continuation character in column 5.
+         ;; Put line number in columns 0-4
+         ;; or put continuation character in column 5.
          (cond ((eobp))
                ((looking-at (regexp-quote fortran-continuation-string))
-                (if fortran-tab-mode
+                (if indent-tabs-mode
                     (progn
-                      (indent-to fortran-minimum-statement-indent)
+                      (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))
+                  (indent-to 5)
+                  (forward-char 1)))
                ((looking-at "[0-9]+")
                 (let ((extra-space (- 5 (- (match-end 0) (point)))))
                   (if (< extra-space 0)
@@ -885,8 +1529,7 @@ notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
       (indent-to col)
       ;; Indent any comment following code on the same line.
       (if (and comment-start-skip
-              (re-search-forward comment-start-skip
-                            (save-excursion (end-of-line) (point)) t))
+              (fortran-find-comment-start-skip))
          (progn (goto-char (match-beginning 0))
                 (if (not (= (current-column) (fortran-comment-hook)))
                     (progn (delete-horizontal-space)
@@ -904,8 +1547,8 @@ Do not call if there is no line number."
                    (= (current-column) 5))))))
 
 (defun fortran-check-for-matching-do ()
-  "When called from a numbered statement, returns t if matching 'do' is found.
-Otherwise return nil."
+  "When called from a numbered statement, return t if matching DO is found.
+Otherwise return nil."
   (let (charnum
        (case-fold-search t))
     (save-excursion
@@ -918,82 +1561,315 @@ Otherwise return a nil."
                                            (progn (skip-chars-forward "0-9")
                                                   (point))))
            (beginning-of-line)
-           (and (re-search-backward
-                 (concat
"\\(^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]\\)\\|\\(^[ \t0-9]*do[ \t]*0*"
-                         charnum "\\b\\)\\|\\(^[ \t]*0*" charnum "\\b\\)")
-                 nil t)
-                (looking-at (concat "^[ \t0-9]*do[ \t]*0*" charnum))))))))
+           (fortran-with-subprogram-narrowing
+            (and (re-search-backward
                 (concat "\\(^[ \t0-9]*do[ \t]*0*" charnum "\\b\\)\\|"
+                          "\\(^[ \t]*0*" charnum "\\b\\)")
+                  nil t)
+                 (looking-at (concat "^[ \t0-9]*do[ \t]*0*" charnum)))))))))
 
-(defun fortran-analyze-file-format ()
-  "Return 0 if Fixed format is used, 1 if Tab formatting is used.
-Use fortran-tab-mode-default if no non-comment statements are found in the
-file before the end or the first fortran-analyze-depth lines."
+(defun fortran-find-comment-start-skip ()
+  "Move to past `comment-start-skip' found on current line.
+Return t if `comment-start-skip' found, nil if not."
+  ;; In order to move point only if comment-start-skip is found, this
+  ;; one uses a lot of save-excursions.  Note that re-search-forward
+  ;; moves point even if comment-start-skip is inside a string-constant.
+  ;; Some code expects certain values for match-beginning and end
+  (interactive)
+  (if (save-excursion
+       (re-search-forward comment-start-skip
+                          (save-excursion (end-of-line) (point)) t))
+      (let ((save-match-beginning (match-beginning 0))
+           (save-match-end (match-end 0)))
+       (if (fortran-is-in-string-p (match-beginning 0))
+           (save-excursion
+             (goto-char save-match-end)
+             (fortran-find-comment-start-skip)) ; recurse for rest of line
+         (goto-char save-match-beginning)
+         (re-search-forward comment-start-skip
+                            (save-excursion (end-of-line) (point)) t)
+         (goto-char (match-end 0))
+         t))
+    nil))
+
+;;From: ralf@up3aud1.gwdg.de (Ralf Fassel)
+;; Test if TAB format continuation lines work.
+(defun fortran-is-in-string-p (where)
+  "Return non-nil iff WHERE (a buffer position) is inside a Fortran string."
   (save-excursion
-    (goto-char (point-min))
-    (setq i 0)
-    (while (not (or
-                (eobp)
-                (looking-at "\t")
-                (looking-at "      ")
-                (> i fortran-analyze-depth)))
-      (forward-line)
-      (setq i (1+ i)))
+    (goto-char where)
     (cond
-     ((looking-at "\t") 1)
-     ((looking-at "      ") 0)
-     (fortran-tab-mode-default 1)
-     (t 0))))
-
-(defun fortran-tab-mode (arg)
-  "Toggle fortran-tab-mode which indicates style of continuation lines.
-With no argument, toggle on/off the tabbing mode of continuation lines.
-If argument is a positive number, or non-nil if not a number, fortran-tab-mode
-is turned on.  Otherwise 
-If `fortran-tab-mode' is false"
+     ((bolp) nil)                      ; bol is never inside a string
+     ((save-excursion                  ; comment lines too
+       (beginning-of-line)
+       (looking-at comment-line-start-skip)) nil)
+     (t (let (;; ok, serious now. Init some local vars:
+             (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 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 (save-excursion (end-of-line)(point)))
+             (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 is
+         (nth 3 parse-state))))))
+
+(defun fortran-auto-fill-mode (arg)
+  "Toggle fortran-auto-fill mode.
+With ARG, turn `fortran-auto-fill' mode on iff ARG is positive.
+In `fortran-auto-fill' mode, inserting a space at a column beyond `fill-column'
+automatically breaks the line at a previous space."
   (interactive "P")
-  (setq fortran-tab-mode
-       (if (null arg) (not fortran-tab-mode)
-         (if (numberp arg)
-             (> (prefix-numeric-value arg) 0)
-           (arg))))
-  (if fortran-tab-mode
-      (fortran-setup-tab-format-style)
-    (fortran-setup-fixed-format-style))
-  (set-buffer-modified-p (buffer-modified-p))) ;No-op, but updates mode line.
-
-(defun fortran-setup-tab-format-style ()
-  "Set up fortran mode to use the TAB-digit mode of continuation lines.
-Use the command fortran-tab-mode to toggle between this and fixed format style."
-  (setq fortran-comment-line-column (max tab-width 6))
-  (setq fortran-minimum-statement-indent (max tab-width 6))
-  (setq indent-tabs-mode t)
-  (setq fortran-column-ruler
-       (concat
- "0       810        20        30        40        50        60        70\n"
- "[   ]|  { |    |    |    |    |    |    |    |    |    |    |    |    |}\n"))
-  (setq fortran-tab-mode-string " TAB-format")
-  (set-buffer-modified-p (buffer-modified-p)))
-
-(defun fortran-setup-fixed-format-style ()
-  "Set up fortran mode to use the column 6 mode of continuation lines.
-Use the command fortran-tab-mode to toggle between this and tab
-character format style."
-  (setq fortran-comment-line-column 6)
-  (setq fortran-minimum-statement-indent 6)
-  (setq indent-tabs-mode nil)
-  (setq fortran-column-ruler
-       (concat
- "0   4 6  10        20        30        40        50        60        70\n"
- "[   ]|{   |    |    |    |    |    |    |    |    |    |    |    |    |}\n"))
-  (setq fortran-tab-mode-string " Fixed-format")
-  (set-buffer-modified-p (buffer-modified-p)))
-
-(or (assq 'fortran-tab-mode minor-mode-alist)
+  (prog1 (setq auto-fill-function
+              (if (if (null arg)
+                      (not auto-fill-function)
+                    (> (prefix-numeric-value arg) 0))
+                  #'fortran-do-auto-fill
+                nil))
+    (force-mode-line-update)))
+
+(defun fortran-do-auto-fill ()
+  (if (> (current-column) fill-column)
+      (fortran-indent-line)))
+
+(defun fortran-fill ()
+  (interactive)
+  (let* ((auto-fill-function #'fortran-do-auto-fill)
+        (opoint (point))
+        (bol (save-excursion (beginning-of-line) (point)))
+        (eol (save-excursion (end-of-line) (point)))
+        (bos (min eol (+ bol (fortran-current-line-indentation))))
+        (quote
+         (save-excursion
+           (goto-char bol)
+           (if (looking-at comment-line-start-skip)
+               nil                     ; OK to break quotes on comment lines.
+             (move-to-column fill-column)
+             (if (fortran-is-in-string-p (point))
+                 (save-excursion (re-search-backward "\\S\"\\s\"\\S\"" bol t)
+                                 (if fortran-break-before-delimiters
+                                     (point)
+                                   (1+ (point))))))))
+        ;; decide where to split the line. If a position for a quoted
+        ;; string was found above then use that, else break the line
+        ;; before the last delimiter.
+        ;; Delimiters are whitespace, commas, and operators.
+        ;; Will break before a pair of *'s.
+        (fill-point
+         (or quote
+             (save-excursion
+               (move-to-column (1+ fill-column))
+               (skip-chars-backward "^ \t\n,'+-/*=)"
+;;;             (if fortran-break-before-delimiters
+;;;                 "^ \t\n,'+-/*=" "^ \t\n,'+-/*=)")
+                )
+               (if (<= (point) (1+ bos))
+                   (progn
+                     (move-to-column (1+ fill-column))
+                     ;;what is this doing???
+                     (if (not (re-search-forward "[\t\n,'+-/*)=]" eol t))
+                         (goto-char bol))))
+               (if (bolp)
+                   (re-search-forward "[ \t]" opoint t)
+                 (backward-char)
+                 (if (looking-at "\\s\"")
+                     (forward-char)
+                   (skip-chars-backward " \t\*")))
+               (if fortran-break-before-delimiters
+                   (point)
+                 (1+ (point)))))))
+    ;; if we are in an in-line comment, don't break unless the
+    ;; line of code is longer than it should be. Otherwise
+    ;; break the line at the column computed above.
+    ;;
+    ;; Need to use fortran-find-comment-start-skip to make sure that quoted !'s
+    ;; don't prevent a break.
+    (if (not (or (save-excursion
+                  (if (and (re-search-backward comment-start-skip bol t)
+                           (not (fortran-is-in-string-p (point))))
+                      (progn
+                        (skip-chars-backward " \t")
+                        (< (current-column) (1+ fill-column)))))
+                (save-excursion
+                  (goto-char fill-point)
+                  (bolp))))
+       (if (> (save-excursion
+                (goto-char fill-point) (current-column))
+              (1+ fill-column))
+           (progn (goto-char fill-point)
+                  (fortran-break-line))
+         (save-excursion
+           (if (> (save-excursion
+                    (goto-char fill-point)
+                    (current-column))
+                  (+ (fortran-calculate-indent) fortran-continuation-indent))
+               (progn
+                 (goto-char fill-point)
+                 (fortran-break-line))))))
+    ))
+(defun fortran-break-line ()
+  (let ((opoint (point))
+       (bol (save-excursion (beginning-of-line) (point)))
+       (eol (save-excursion (end-of-line) (point)))
+       (comment-string nil))
+
+    (save-excursion
+      (if (and comment-start-skip (fortran-find-comment-start-skip))
+         (progn
+           (re-search-backward comment-start-skip bol t)
+           (setq comment-string (buffer-substring (point) eol))
+           (delete-region (point) eol))))
+    ;; Forward line 1 really needs to go to next non white line
+    (if (save-excursion (forward-line)
+                       (or (looking-at "     [^ 0\n]")
+                           (looking-at "\t[1-9]")))
+       (progn
+         (end-of-line)
+         (delete-region (point) (match-end 0))
+         (delete-horizontal-space)
+         (fortran-fill))
+      (fortran-split-line))
+    (if comment-string
+       (save-excursion
+         (goto-char bol)
+         (end-of-line)
+         (delete-horizontal-space)
+         (indent-to (fortran-comment-hook))
+         (insert comment-string)))))
+
+(defun fortran-analyze-file-format ()
+  "Return nil if fixed format is used, t if TAB formatting is used.
+Use `fortran-tab-mode-default' if no non-comment statements are found in the
+file before the end or the first `fortran-analyze-depth' lines."
+  (let ((i 0))
+    (save-excursion
+      (goto-char (point-min))
+      (setq i 0)
+      (while (not (or
+                  (eobp)
+                  (looking-at "\t")
+                  (looking-at "      ")
+                  (> i fortran-analyze-depth)))
+       (forward-line)
+       (setq i (1+ i)))
+      (cond
+       ((looking-at "\t") t)
+       ((looking-at "      ") nil)
+       (fortran-tab-mode-default t)
+       (t nil)))))
+
+(or (assq 'fortran-tab-mode-string minor-mode-alist)
     (setq minor-mode-alist (cons
-                           '(fortran-tab-mode-string fortran-tab-mode-string)
+                           '(fortran-tab-mode-string
+                             (indent-tabs-mode fortran-tab-mode-string))
                            minor-mode-alist)))
 
+(defun fortran-fill-paragraph (&optional justify)
+  "Fill surrounding comment block as paragraphs, else fill statement.
+
+Intended as the value of `fill-paragraph-function'."
+  (interactive "P")
+  (save-excursion
+    (beginning-of-line)
+    (if (not (looking-at "[Cc*]"))
+       (fortran-fill-statement)
+      ;; We're in a comment block.  Find the start and end of a
+      ;; paragraph, delimited either by non-comment lines or empty
+      ;; comments.  (Get positions as markers, since the
+      ;; `indent-region' below can shift the block's end).
+      (let* ((non-empty-comment (concat "\\(" comment-line-start-skip
+                                       "\\)" "[^ \t\n]"))
+            (start (save-excursion
+                     ;; Find (start of) first line.
+                     (while (and (zerop (forward-line -1))
+                                 (looking-at non-empty-comment)))
+                     (or (looking-at non-empty-comment)
+                         (forward-line)) ; overshot
+                     (point-marker)))
+            (end (save-excursion
+                   ;; Find start of first line past region to fill.
+                   (while (progn (forward-line)
+                                 (looking-at non-empty-comment)))
+                   (point-marker))))
+       ;; Indent the block, find the string comprising the effective
+       ;; comment start skip and use that as a fill-prefix for
+       ;; filling the region.
+       (indent-region start end nil)
+       (let ((paragraph-ignore-fill-prefix nil)
+             (fill-prefix (progn (beginning-of-line)
+                                 (looking-at comment-line-start-skip)
+                                 (match-string 0))))
+         (let (fill-paragraph-function)
+           (fill-region start end justify))) ; with normal `fill-paragraph'
+       (set-marker start nil)
+       (set-marker end nil))))
+  t)
+
+(defun fortran-fill-statement ()
+  "Fill a fortran statement up to `fill-column'."
+  (interactive)
+  (let ((auto-fill-function #'fortran-do-auto-fill))
+    (if (not (save-excursion
+              (beginning-of-line)
+              (or (looking-at "[ \t]*$")
+                  (looking-at comment-line-start-skip)
+                  (and comment-start-skip
+                       (looking-at (concat "[ \t]*" comment-start-skip))))))
+       (save-excursion
+         ;; Find beginning of statement.
+         (fortran-next-statement)
+         (fortran-previous-statement)
+         ;; Re-indent initially.
+         (fortran-indent-line)
+         ;; Replace newline plus continuation field plus indentation with
+         ;; single space.
+         (while (progn
+                  (forward-line)
+                  (fortran-remove-continuation)))
+         (fortran-previous-statement)))
+    (fortran-indent-line)))
+
 (provide 'fortran)
 
 ;;; fortran.el ends here