home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / NeXT / GnuSource / emacs-15.0.3 / lisp / fortran.el < prev    next >
Lisp/Scheme  |  1990-07-19  |  27KB  |  656 lines

  1. ;;; Fortran mode for GNU Emacs  (beta test version 1.21, Oct. 1, 1985)
  2. ;;; Copyright (c) 1986 Free Software Foundation, Inc.
  3. ;;; Written by Michael D. Prange (mit-eddie!mit-erl!prange).
  4.  
  5. ;;; This file is not part of the GNU Emacs distribution (yet).
  6.  
  7. ;; This file is distributed in the hope that it will be useful,
  8. ;; but WITHOUT ANY WARRANTY.  No author or distributor
  9. ;; accepts responsibility to anyone for the consequences of using it
  10. ;; or for whether it serves any particular purpose or works at all,
  11. ;; unless he says so in writing.  Refer to the GNU Emacs General Public
  12. ;; License for full details.
  13.  
  14. ;; Everyone is granted permission to copy, modify and redistribute
  15. ;; this file, but only under the conditions described in the
  16. ;; GNU Emacs General Public License.   A copy of this license is
  17. ;; supposed to have been given to you along with GNU Emacs so you
  18. ;; can know your rights and responsibilities.  It should be in a
  19. ;; file named COPYING.  Among other things, the copyright notice
  20. ;; and this notice must be preserved on all copies.
  21.  
  22. ;;; Author acknowledges help from Stephen Gildea <mit-erl!gildea>
  23.  
  24. ;;; Bugs to mit-erl!bug-fortran-mode.
  25.  
  26. (defvar fortran-do-indent 3
  27.   "*Extra indentation applied to `do' blocks.")
  28.  
  29. (defvar fortran-if-indent 3
  30.   "*Extra indentation applied to `if' blocks.")
  31.  
  32. (defvar fortran-continuation-indent 5
  33.   "*Extra indentation applied to `continuation' lines.")
  34.  
  35. (defvar fortran-comment-indent-style 'fixed
  36.   "*nil forces comment lines not to be touched,
  37. 'fixed produces fixed comment indentation to comment-column,
  38. and 'relative indents to current fortran indentation plus comment-column.")
  39.  
  40. (defvar fortran-comment-line-column 6
  41.   "*Indentation for text in comment lines.")
  42.  
  43. (defvar comment-line-start nil
  44.   "*Delimiter inserted to start new full-line comment.")
  45.  
  46. (defvar comment-line-start-skip nil
  47.   "*Regexp to match the start of a full-line comment.")
  48.  
  49. (defvar fortran-minimum-statement-indent 6
  50.   "*Minimum indentation for fortran statements.")
  51.  
  52. ;; Note that this is documented in the v18 manuals as being a string
  53. ;; of length one rather than a single character.
  54. ;; The code in this file accepts either format for compatibility.
  55. (defvar fortran-comment-indent-char ? 
  56.   "*Character to be inserted for Fortran comment indentation.
  57. Normally a space.")
  58.  
  59. (defvar fortran-line-number-indent 1
  60.   "*Maximum indentation for Fortran line numbers.
  61. 5 means right-justify them within their five-column field.")
  62.  
  63. (defvar fortran-check-all-num-for-matching-do nil
  64.   "*Non-nil causes all numbered lines to be treated as possible do-loop ends.")
  65.  
  66. (defvar fortran-continuation-char ?$
  67.   "*Character which is inserted in column 5 by \\[fortran-split-line]
  68. to begin a continuation line.  Normally $.")
  69.  
  70. (defvar fortran-comment-region "c$$$"
  71.   "*String inserted by \\[fortran-comment-region] at start of each line in region.")
  72.  
  73. (defvar fortran-electric-line-number t
  74.   "*Non-nil causes line number digits to be moved to the correct column as typed.")
  75.  
  76. (defvar fortran-startup-message t
  77.   "*Non-nil displays a startup message when fortran-mode is first called.")
  78.  
  79. (defvar fortran-column-ruler
  80.   (concat "0   4 6  10        20        30        40        50        60        70\n"
  81.       "[   ]|{   |    |    |    |    |    |    |    |    |    |    |    |    |}\n")
  82.   "*String displayed above current line by \\[fortran-column-ruler].")
  83.  
  84. (defconst fortran-mode-version "1.21")
  85.  
  86. (defvar fortran-mode-syntax-table nil
  87.   "Syntax table in use in fortran-mode buffers.")
  88.  
  89. (if fortran-mode-syntax-table
  90.     ()
  91.   (setq fortran-mode-syntax-table (make-syntax-table))
  92.   (modify-syntax-entry ?\; "w" fortran-mode-syntax-table)
  93.   (modify-syntax-entry ?+ "." fortran-mode-syntax-table)
  94.   (modify-syntax-entry ?- "." fortran-mode-syntax-table)
  95.   (modify-syntax-entry ?* "." fortran-mode-syntax-table)
  96.   (modify-syntax-entry ?/ "." fortran-mode-syntax-table)
  97.   (modify-syntax-entry ?\' "\"" fortran-mode-syntax-table)
  98.   (modify-syntax-entry ?\" "\"" fortran-mode-syntax-table)
  99.   (modify-syntax-entry ?\\ "/" fortran-mode-syntax-table)
  100.   (modify-syntax-entry ?. "w" fortran-mode-syntax-table)
  101.   (modify-syntax-entry ?\n ">" fortran-mode-syntax-table))
  102.  
  103. (defvar fortran-mode-map () 
  104.   "Keymap used in fortran mode.")
  105.  
  106. (if fortran-mode-map
  107.     ()
  108.   (setq fortran-mode-map (make-sparse-keymap))
  109.   (define-key fortran-mode-map ";" 'fortran-abbrev-start)
  110.   (define-key fortran-mode-map "\C-c;" 'fortran-comment-region)
  111.   (define-key fortran-mode-map "\e\C-a" 'beginning-of-fortran-subprogram)
  112.   (define-key fortran-mode-map "\e\C-e" 'end-of-fortran-subprogram)
  113.   (define-key fortran-mode-map "\e;" 'fortran-indent-comment)
  114.   (define-key fortran-mode-map "\e\C-h" 'mark-fortran-subprogram)
  115.   (define-key fortran-mode-map "\e\n" 'fortran-split-line)
  116.   (define-key fortran-mode-map "\e\C-q" 'fortran-indent-subprogram)
  117.   (define-key fortran-mode-map "\C-c\C-w" 'fortran-window-create)
  118.   (define-key fortran-mode-map "\C-c\C-r" 'fortran-column-ruler)
  119.   (define-key fortran-mode-map "\C-c\C-p" 'fortran-previous-statement)
  120.   (define-key fortran-mode-map "\C-c\C-n" 'fortran-next-statement)
  121.   (define-key fortran-mode-map "\t" 'fortran-indent-line)
  122.   (define-key fortran-mode-map "0" 'fortran-electric-line-number)
  123.   (define-key fortran-mode-map "1" 'fortran-electric-line-number)
  124.   (define-key fortran-mode-map "2" 'fortran-electric-line-number)
  125.   (define-key fortran-mode-map "3" 'fortran-electric-line-number)
  126.   (define-key fortran-mode-map "4" 'fortran-electric-line-number)
  127.   (define-key fortran-mode-map "5" 'fortran-electric-line-number)
  128.   (define-key fortran-mode-map "6" 'fortran-electric-line-number)
  129.   (define-key fortran-mode-map "7" 'fortran-electric-line-number)
  130.   (define-key fortran-mode-map "8" 'fortran-electric-line-number)
  131.   (define-key fortran-mode-map "9" 'fortran-electric-line-number))
  132.  
  133. (defvar fortran-mode-abbrev-table nil)
  134. (if fortran-mode-abbrev-table
  135.     ()
  136.   (define-abbrev-table 'fortran-mode-abbrev-table ())
  137.   (let ((abbrevs-changed nil))
  138.     (define-abbrev fortran-mode-abbrev-table  ";b"   "byte" nil)
  139.     (define-abbrev fortran-mode-abbrev-table  ";ch"  "character" nil)
  140.     (define-abbrev fortran-mode-abbrev-table  ";cl"  "close" nil)
  141.     (define-abbrev fortran-mode-abbrev-table  ";c"   "continue" nil)
  142.     (define-abbrev fortran-mode-abbrev-table  ";cm"  "common" nil)
  143.     (define-abbrev fortran-mode-abbrev-table  ";cx"  "complex" nil)
  144.     (define-abbrev fortran-mode-abbrev-table  ";di"  "dimension" nil)
  145.     (define-abbrev fortran-mode-abbrev-table  ";do"  "double" nil)
  146.     (define-abbrev fortran-mode-abbrev-table  ";dc"  "double complex" nil)
  147.     (define-abbrev fortran-mode-abbrev-table  ";dp"  "double precision" nil)
  148.     (define-abbrev fortran-mode-abbrev-table  ";dw"  "do while" nil)
  149.     (define-abbrev fortran-mode-abbrev-table  ";e"   "else" nil)
  150.     (define-abbrev fortran-mode-abbrev-table  ";ed"  "enddo" nil)
  151.     (define-abbrev fortran-mode-abbrev-table  ";el"  "elseif" nil)
  152.     (define-abbrev fortran-mode-abbrev-table  ";en"  "endif" nil)
  153.     (define-abbrev fortran-mode-abbrev-table  ";eq"  "equivalence" nil)
  154.     (define-abbrev fortran-mode-abbrev-table  ";ex"  "external" nil)
  155.     (define-abbrev fortran-mode-abbrev-table  ";ey"  "entry" nil)
  156.     (define-abbrev fortran-mode-abbrev-table  ";f"   "format" nil)
  157.     (define-abbrev fortran-mode-abbrev-table  ";fu"  "function" nil)
  158.     (define-abbrev fortran-mode-abbrev-table  ";g"   "goto" nil)
  159.     (define-abbrev fortran-mode-abbrev-table  ";im"  "implicit" nil)
  160.     (define-abbrev fortran-mode-abbrev-table  ";ib"  "implicit byte" nil)
  161.     (define-abbrev fortran-mode-abbrev-table  ";ic"  "implicit complex" nil)
  162.     (define-abbrev fortran-mode-abbrev-table  ";ich" "implicit character" nil)
  163.     (define-abbrev fortran-mode-abbrev-table  ";ii"  "implicit integer" nil)
  164.     (define-abbrev fortran-mode-abbrev-table  ";il"  "implicit logical" nil)
  165.     (define-abbrev fortran-mode-abbrev-table  ";ir"  "implicit real" nil)
  166.     (define-abbrev fortran-mode-abbrev-table  ";inc" "include" nil)
  167.     (define-abbrev fortran-mode-abbrev-table  ";in"  "integer" nil)
  168.     (define-abbrev fortran-mode-abbrev-table  ";intr" "intrinsic" nil)
  169.     (define-abbrev fortran-mode-abbrev-table  ";l"   "logical" nil)
  170.     (define-abbrev fortran-mode-abbrev-table  ";op"  "open" nil)
  171.     (define-abbrev fortran-mode-abbrev-table  ";pa"  "parameter" nil)
  172.     (define-abbrev fortran-mode-abbrev-table  ";pr"  "program" nil)
  173.     (define-abbrev fortran-mode-abbrev-table  ";p"   "print" nil)
  174.     (define-abbrev fortran-mode-abbrev-table  ";re"  "real" nil)
  175.     (define-abbrev fortran-mode-abbrev-table  ";r"   "read" nil)
  176.     (define-abbrev fortran-mode-abbrev-table  ";rt"  "return" nil)
  177.     (define-abbrev fortran-mode-abbrev-table  ";rw"  "rewind" nil)
  178.     (define-abbrev fortran-mode-abbrev-table  ";s"   "stop" nil)
  179.     (define-abbrev fortran-mode-abbrev-table  ";su"  "subroutine" nil)
  180.     (define-abbrev fortran-mode-abbrev-table  ";ty"  "type" nil)
  181.     (define-abbrev fortran-mode-abbrev-table  ";w"   "write" nil)))
  182.  
  183. (defun fortran-mode ()
  184.   "Major mode for editing fortran code.
  185. Tab indents the current fortran line correctly. 
  186. `do' statements must not share a common `continue'.
  187.  
  188. Type `;?' or `;\\[help-command]' to display a list of built-in abbrevs for Fortran keywords.
  189.  
  190. Variables controlling indentation style and extra features:
  191.  
  192.  comment-start
  193.     Normally nil in Fortran mode.  If you want to use comments
  194.     starting with `!', set this to the string \"!\".
  195.  fortran-do-indent
  196.     Extra indentation within do blocks.  (default 3)
  197.  fortran-if-indent
  198.     Extra indentation within if blocks.  (default 3)
  199.  fortran-continuation-indent
  200.     Extra indentation appled to continuation statements.  (default 5)
  201.  fortran-comment-line-column
  202.     Amount of indentation for text within full-line comments. (default 6)
  203.  fortran-comment-indent-style
  204.     nil    means don't change indentation of text in full-line comments,
  205.     fixed  means indent that text at column fortran-comment-line-column
  206.     relative  means indent at fortran-comment-line-column beyond the
  207.            indentation for a line of code.
  208.     Default value is fixed.
  209.  fortran-comment-indent-char
  210.     Character to be inserted instead of space for full-line comment
  211.     indentation.  (default is a space)
  212.  fortran-minimum-statement-indent
  213.     Minimum indentation for fortran statements. (default 6)
  214.  fortran-line-number-indent
  215.     Maximum indentation for line numbers.  A line number will get
  216.     less than this much indentation if necessary to avoid reaching
  217.     column 5.  (default 1)
  218.  fortran-check-all-num-for-matching-do
  219.     Non-nil causes all numbered lines to be treated as possible 'continue'
  220.     statements.  (default nil)
  221.  fortran-continuation-char
  222.     character to be inserted in column 5 of a continuation line.
  223.     (default $)
  224.  fortran-comment-region
  225.     String inserted by \\[fortran-comment-region] at start of each line in 
  226.     region.  (default \"c$$$\")
  227.  fortran-electric-line-number
  228.     Non-nil causes line number digits to be moved to the correct column 
  229.     as typed.  (default t)
  230.  fortran-startup-message
  231.     Set to nil to inhibit message first time fortran-mode is used.
  232.  
  233. Turning on Fortran mode calls the value of the variable fortran-mode-hook 
  234. with no args, if that value is non-nil.
  235. \\{fortran-mode-map}"
  236.   (interactive)
  237.   (kill-all-local-variables)
  238.   (if fortran-startup-message
  239.       (message "Emacs Fortran mode version %s.  Bugs to mit-erl!bug-fortran-mode" fortran-mode-version))
  240.   (setq fortran-startup-message nil)
  241.   (setq local-abbrev-table fortran-mode-abbrev-table)
  242.   (set-syntax-table fortran-mode-syntax-table)
  243.   (make-local-variable 'indent-line-function)
  244.   (setq indent-line-function 'fortran-indent-line)
  245.   (make-local-variable 'comment-indent-hook)
  246.   (setq comment-indent-hook 'fortran-comment-hook)
  247.   (make-local-variable 'comment-line-start-skip)
  248.   (setq comment-line-start-skip "^[Cc*][^ \t\n]*[ \t]*") ;[^ \t\n]* handles comment strings such as c$$$
  249.   (make-local-variable 'comment-line-start)
  250.   (setq comment-line-start "c")
  251.   (make-local-variable 'comment-start-skip)
  252.   (setq comment-start-skip "![ \t]*")
  253.   (make-local-variable 'comment-start)
  254.   (setq comment-start nil)
  255.   (make-local-variable 'require-final-newline)
  256.   (setq require-final-newline t)
  257.   (make-local-variable 'abbrev-all-caps)
  258.   (setq abbrev-all-caps t)
  259.   (make-local-variable 'indent-tabs-mode)
  260.   (setq indent-tabs-mode nil)
  261.   (use-local-map fortran-mode-map)
  262.   (setq mode-name "Fortran")
  263.   (setq major-mode 'fortran-mode)
  264.   (run-hooks 'fortran-mode-hook))
  265.  
  266. (defun fortran-comment-hook ()
  267.   (save-excursion
  268.     (skip-chars-backward " \t")
  269.     (max (+ 1 (current-column))
  270.      comment-column)))
  271.  
  272. (defun fortran-indent-comment ()
  273.   "Align or create comment on current line.
  274. Existing comments of all types are recognized and aligned.
  275. If the line has no comment, a side-by-side comment is inserted and aligned
  276. if the value of  comment-start  is not nil.
  277. Otherwise, a separate-line comment is inserted, on this line
  278. or on a new line inserted before this line if this line is not blank."
  279.   (interactive)
  280.   (beginning-of-line)
  281.   ;; Recognize existing comments of either kind.
  282.   (cond ((looking-at comment-line-start-skip)
  283.      (fortran-indent-line))
  284.     ((re-search-forward comment-start-skip
  285.                 (save-excursion (end-of-line) (point)) t)
  286.      (indent-for-comment))
  287.     ;; No existing comment.
  288.     ;; If side-by-side comments are defined, insert one,
  289.     ;; unless line is now blank.
  290.     ((and comment-start (not (looking-at "^[ \t]*$")))
  291.      (end-of-line)
  292.      (delete-horizontal-space)
  293.      (indent-to (fortran-comment-hook))
  294.      (insert comment-start))
  295.     ;; Else insert separate-line comment, making a new line if nec.
  296.     (t
  297.      (if (looking-at "^[ \t]*$")
  298.          (delete-horizontal-space)
  299.        (beginning-of-line)
  300.        (insert "\n")
  301.        (forward-char -1))
  302.      (insert comment-line-start)
  303.      (insert-char (if (stringp fortran-comment-indent-char)
  304.               (aref fortran-comment-indent-char 0)
  305.               fortran-comment-indent-char)
  306.               (- (calculate-fortran-indent) (current-column))))))
  307.  
  308. (defun fortran-comment-region (beg-region end-region arg)
  309.   "Comments every line in the region.
  310. Puts fortran-comment-region at the beginning of every line in the region. 
  311. BEG-REGION and END-REGION are args which specify the region boundaries. 
  312. With non-nil ARG, uncomments the region."
  313.   (interactive "*r\nP")
  314.   (let ((end-region-mark (make-marker)) (save-point (point-marker)))
  315.     (set-marker end-region-mark end-region)
  316.     (goto-char beg-region)
  317.     (beginning-of-line)
  318.     (if (not arg)            ;comment the region
  319.     (progn (insert fortran-comment-region)
  320.            (while (and  (= (forward-line 1) 0)
  321.                 (< (point) end-region-mark))
  322.          (insert fortran-comment-region)))
  323.       (let ((com (regexp-quote fortran-comment-region))) ;uncomment the region
  324.     (if (looking-at com)
  325.         (delete-region (point) (match-end 0)))
  326.     (while (and  (= (forward-line 1) 0)
  327.              (< (point) end-region-mark))
  328.       (if (looking-at com)
  329.           (delete-region (point) (match-end 0))))))
  330.     (goto-char save-point)
  331.     (set-marker end-region-mark nil)
  332.     (set-marker save-point nil)))
  333.  
  334. (defun fortran-abbrev-start ()
  335.   "Typing \";\\[help-command]\" or \";?\" lists all the fortran abbrevs. 
  336. Any other key combination is executed normally." ;\\[help-command] is just a way to print the value of the variable help-char.
  337.   (interactive)
  338.   (let (c)
  339.     (insert last-command-char)
  340.     (if (or (= (setq c (read-char)) ??)    ;insert char if not equal to `?'
  341.         (= c help-char))
  342.     (fortran-abbrev-help)
  343.       (setq unread-command-char c))))
  344.  
  345. (defun fortran-abbrev-help ()
  346.   "List the currently defined abbrevs in Fortran mode."
  347.   (interactive)
  348.   (message "Listing abbrev table...")
  349.   (require 'abbrevlist)
  350.   (list-one-abbrev-table fortran-mode-abbrev-table "*Help*")
  351.   (message "Listing abbrev table...done"))
  352.  
  353. (defun fortran-column-ruler ()
  354.   "Inserts a column ruler momentarily above current line, till next keystroke.
  355. The ruler is defined by the value of fortran-column-ruler.
  356. The key typed is executed unless it is SPC."
  357.   (interactive)
  358.   (momentary-string-display 
  359.    fortran-column-ruler (save-excursion (beginning-of-line) (point))
  360.    nil "Type SPC or any command to erase ruler."))
  361.  
  362. (defun fortran-window-create ()
  363.   "Makes the window 72 columns wide."
  364.   (interactive)
  365.   (let ((window-min-width 2))
  366.     (split-window-horizontally 73))
  367.   (other-window 1)
  368.   (switch-to-buffer " fortran-window-extra" t)
  369.   (select-window (previous-window)))
  370.  
  371. (defun fortran-split-line ()
  372.   "Break line at point and insert continuation marker and alignment."
  373.   (interactive)
  374.   (delete-horizontal-space)
  375.   (if (save-excursion (beginning-of-line) (looking-at comment-line-start-skip))
  376.       (insert "\n" comment-line-start " ")
  377.     (insert "\n " fortran-continuation-char))
  378.   (fortran-indent-line))
  379.  
  380. (defun delete-horizontal-regexp (chars)
  381.   "Delete all characters in CHARS around point.
  382. CHARS is like the inside of a [...] in a regular expression
  383. except that ] is never special and \ quotes ^, - or \."
  384.   (interactive "*s")
  385.   (skip-chars-backward chars)
  386.   (delete-region (point) (progn (skip-chars-forward chars) (point))))
  387.  
  388. (defun fortran-electric-line-number (arg)
  389.   "Self insert, but if part of a Fortran line number indent it automatically.
  390. Auto-indent does not happen if a numeric arg is used."
  391.   (interactive "P")
  392.   (if (or arg (not fortran-electric-line-number))
  393.       (self-insert-command arg)
  394.     (if (or (save-excursion (re-search-backward "[^ \t0-9]"
  395.                         (save-excursion
  396.                           (beginning-of-line)
  397.                           (point))
  398.                         t)) ;not a line number
  399.         (looking-at "[0-9]"))        ;within a line number
  400.     (insert last-command-char)
  401.       (skip-chars-backward " \t")
  402.       (insert last-command-char)
  403.       (fortran-indent-line))))
  404.  
  405. (defun beginning-of-fortran-subprogram ()
  406.   "Moves point to the beginning of the current fortran subprogram."
  407.   (interactive)
  408.   (let ((case-fold-search t))
  409.     (beginning-of-line -1)
  410.     (re-search-backward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
  411.     (if (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")
  412.     (forward-line 1))))
  413.  
  414. (defun end-of-fortran-subprogram ()
  415.   "Moves point to the end of the current fortran subprogram."
  416.   (interactive)
  417.   (let ((case-fold-search t))
  418.     (beginning-of-line 2)
  419.     (re-search-forward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
  420.     (goto-char (match-beginning 0))
  421.     (forward-line 1)))
  422.  
  423. (defun mark-fortran-subprogram ()
  424.   "Put mark at end of fortran subprogram, point at beginning. 
  425. The marks are pushed."
  426.   (interactive)
  427.   (end-of-fortran-subprogram)
  428.   (push-mark (point))
  429.   (beginning-of-fortran-subprogram))
  430.   
  431. (defun fortran-previous-statement ()
  432.   "Moves point to beginning of the previous fortran statement.
  433. Returns 'first-statement if that statement is the first
  434. non-comment Fortran statement in the file, and nil otherwise."
  435.   (interactive)
  436.   (let (not-first-statement continue-test)
  437.     (beginning-of-line)
  438.     (setq continue-test
  439.       (or (looking-at
  440.             (concat "[ \t]*" (regexp-quote (char-to-string
  441.                          fortran-continuation-char))))
  442.           (looking-at "     [^ 0\n]")))
  443.     (while (and (setq not-first-statement (= (forward-line -1) 0))
  444.         (or (looking-at comment-line-start-skip)
  445.             (looking-at "[ \t]*$")
  446.             (looking-at "     [^ 0\n]")
  447.             (looking-at (concat "[ \t]*"  comment-start-skip)))))
  448.     (cond ((and continue-test
  449.         (not not-first-statement))
  450.        (message "Incomplete continuation statement."))
  451.       (continue-test    
  452.        (fortran-previous-statement))
  453.       ((not not-first-statement)
  454.        'first-statement))))
  455.  
  456. (defun fortran-next-statement ()
  457.   "Moves point to beginning of the next fortran statement.
  458.  Returns 'last-statement if that statement is the last
  459.  non-comment Fortran statement in the file, and nil otherwise."
  460.   (interactive)
  461.   (let (not-last-statement)
  462.     (beginning-of-line)
  463.     (while (and (setq not-last-statement (= (forward-line 1) 0))
  464.          (or (looking-at comment-line-start-skip)
  465.              (looking-at "[ \t]*$")
  466.              (looking-at "     [^ 0\n]")
  467.              (looking-at (concat "[ \t]*"  comment-start-skip)))))
  468.     (if (not not-last-statement)
  469.      'last-statement)))
  470.  
  471. (defun fortran-indent-line ()
  472.   "Indents current fortran line based on its contents and on previous lines."
  473.   (interactive)
  474.   (let ((cfi (calculate-fortran-indent)))
  475.     (save-excursion
  476.       (beginning-of-line)
  477.       (if (or (not (= cfi (fortran-current-line-indentation)))
  478.           (and (re-search-forward "^[ \t]*[0-9]+" (+ (point) 4) t)
  479.            (not (fortran-line-number-indented-correctly-p))))
  480.       (fortran-indent-to-column cfi)
  481.     (beginning-of-line)
  482.     (if (re-search-forward comment-start-skip
  483.                    (save-excursion (end-of-line) (point)) 'move)
  484.         (fortran-indent-comment))))
  485.     ;; Never leave point in left margin.
  486.     (if (< (current-column) cfi)
  487.     (move-to-column cfi))))
  488.  
  489. (defun fortran-indent-subprogram ()
  490.   "Properly indents the Fortran subprogram which contains point."
  491.   (interactive)
  492.   (save-excursion
  493.     (mark-fortran-subprogram)
  494.     (message "Indenting subprogram...")
  495.     (indent-region (point) (mark) nil))
  496.   (message "Indenting subprogram...done."))
  497.  
  498. (defun calculate-fortran-indent ()
  499.   "Calculates the fortran indent column based on previous lines."
  500.   (let (icol first-statement (case-fold-search t))
  501.     (save-excursion
  502.       (setq first-statement (fortran-previous-statement))
  503.       (if first-statement
  504.       (setq icol fortran-minimum-statement-indent)
  505.     (progn
  506.       (if (= (point) (point-min))
  507.           (setq icol fortran-minimum-statement-indent)
  508.         (setq icol (fortran-current-line-indentation)))
  509.       (skip-chars-forward " \t0-9")
  510.       (cond ((looking-at "if[ \t]*(")
  511.          (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
  512.              (let (then-test)    ;multi-line if-then
  513.                (while (and (= (forward-line 1) 0) ;search forward for then
  514.                        (looking-at "     [^ 0]")
  515.                        (not (setq then-test (looking-at ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
  516.                then-test))
  517.              (setq icol (+ icol fortran-if-indent))))
  518.         ((looking-at "\\(else\\|elseif\\)\\b")
  519.          (setq icol (+ icol fortran-if-indent)))
  520.         ((looking-at "do\\b")
  521.          (setq icol (+ icol fortran-do-indent)))))))
  522.     (save-excursion
  523.       (beginning-of-line)
  524.       (cond ((looking-at "[ \t]*$"))
  525.         ((looking-at comment-line-start-skip)
  526.          (cond ((eq fortran-comment-indent-style 'relative)
  527.             (setq icol (+ icol fortran-comment-line-column)))
  528.            ((eq fortran-comment-indent-style 'fixed)
  529.             (setq icol fortran-comment-line-column))))
  530.         ((or (looking-at (concat "[ \t]*"
  531.                      (regexp-quote (char-to-string fortran-continuation-char))))
  532.          (looking-at "     [^ 0\n]"))
  533.          (setq icol (+ icol fortran-continuation-indent)))
  534.         (first-statement)
  535.         ((and fortran-check-all-num-for-matching-do
  536.           (looking-at "[ \t]*[0-9]+")
  537.           (fortran-check-for-matching-do))
  538.          (setq icol (- icol fortran-do-indent)))
  539.         (t
  540.          (skip-chars-forward " \t0-9")
  541.          (cond ((looking-at "end[ \t]*if\\b")
  542.             (setq icol (- icol fortran-if-indent)))
  543.            ((looking-at "\\(else\\|elseif\\)\\b")
  544.             (setq icol (- icol fortran-if-indent)))
  545.            ((and (looking-at "continue\\b")
  546.              (fortran-check-for-matching-do))
  547.             (setq icol (- icol fortran-do-indent)))
  548.            ((looking-at "end[ \t]*do\\b")
  549.             (setq icol (- icol fortran-do-indent)))
  550.            ((and (looking-at "end\\b[ \t]*[^ \t=(a-z]")
  551.              (not (= icol fortran-minimum-statement-indent)))
  552.              (message "Warning: `end' not in column %d.  Probably an unclosed block." fortran-minimum-statement-indent))))))
  553.     (max fortran-minimum-statement-indent icol)))
  554.  
  555. (defun fortran-current-line-indentation ()
  556.   "Indentation of current line, ignoring Fortran line number or continuation.
  557. This is the column position of the first non-whitespace character
  558. aside from the line number and/or column 5 line-continuation character.
  559. For comment lines, returns indentation of the first
  560. non-indentation text within the comment."
  561.   (save-excursion
  562.     (beginning-of-line)
  563.     (cond ((looking-at comment-line-start-skip)
  564.        (goto-char (match-end 0))
  565.        (skip-chars-forward
  566.          (if (stringp fortran-comment-indent-char)
  567.          fortran-comment-indent-char
  568.              (char-to-string fortran-comment-indent-char))))
  569.       ((looking-at "     [^ 0\n]")
  570.        (goto-char (match-end 0)))
  571.       (t
  572.        ;; Move past line number.
  573.        (move-to-column 5)))
  574.     ;; Move past whitespace.
  575.     (skip-chars-forward " \t")
  576.     (current-column)))
  577.  
  578. (defun fortran-indent-to-column (col)
  579.   "Indents current line with spaces to column COL.
  580. notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
  581.           line, and this continuation character is retained on indentation;
  582.        2) If fortran-continuation-char is the first non-whitespace character,
  583.           this is a continuation line;
  584.        3) A non-continuation line which has a number as the first
  585.           non-whitespace character is a numbered line."
  586.   (save-excursion
  587.     (beginning-of-line)
  588.     (if (looking-at comment-line-start-skip)
  589.     (if fortran-comment-indent-style
  590.         (let ((char (if (stringp fortran-comment-indent-char)
  591.                 (aref fortran-comment-indent-char 0)
  592.                 fortran-comment-indent-char)))
  593.           (goto-char (match-end 0))
  594.           (delete-horizontal-regexp (concat " \t" (char-to-string char)))
  595.           (insert-char char (- col (current-column)))))
  596.       (if (looking-at "     [^ 0\n]")
  597.       (forward-char 6)
  598.     (delete-horizontal-space)
  599.     ;; Put line number in columns 0-4
  600.     ;; or put continuation character in column 5.
  601.     (cond ((eobp))
  602.           ((= (following-char) fortran-continuation-char)
  603.            (indent-to 5)
  604.            (forward-char 1))
  605.           ((looking-at "[0-9]+")
  606.            (let ((extra-space (- 5 (- (match-end 0) (point)))))
  607.          (if (< extra-space 0)
  608.              (message "Warning: line number exceeds 5-digit limit.")
  609.            (indent-to (min fortran-line-number-indent extra-space))))
  610.            (skip-chars-forward "0-9"))))
  611.       ;; Point is now after any continuation character or line number.
  612.       ;; Put body of statement where specified.
  613.       (delete-horizontal-space)
  614.       (indent-to col)
  615.       ;; Indent any comment following code on the same line.
  616.       (if (re-search-forward comment-start-skip
  617.                  (save-excursion (end-of-line) (point)) t)
  618.       (progn (goto-char (match-beginning 0))
  619.          (if (not (= (current-column) (fortran-comment-hook)))
  620.              (progn (delete-horizontal-space)
  621.                 (indent-to (fortran-comment-hook)))))))))
  622.  
  623. (defun fortran-line-number-indented-correctly-p ()
  624.   "Return t if current line's line number is correctly indente.
  625. Do not call if there is no line number."
  626.   (save-excursion
  627.     (beginning-of-line)
  628.     (skip-chars-forward " \t")
  629.     (and (<= (current-column) fortran-line-number-indent)
  630.      (or (= (current-column) fortran-line-number-indent)
  631.          (progn (skip-chars-forward "0-9")
  632.             (= (current-column) 5))))))
  633.  
  634. (defun fortran-check-for-matching-do ()
  635.   "When called from a numbered statement, returns t
  636.  if matching 'do' is found, and nil otherwise."
  637.   (let (charnum
  638.     (case-fold-search t))
  639.     (save-excursion
  640.       (beginning-of-line)
  641.       (if (looking-at "[ \t]*[0-9]+")
  642.       (progn
  643.         (skip-chars-forward " \t")
  644.         (skip-chars-forward "0") ;skip past leading zeros
  645.         (setq charnum (buffer-substring (point)
  646.                         (progn (skip-chars-forward "0-9")
  647.                            (point))))
  648.         (beginning-of-line)
  649.         (and (re-search-backward
  650.           (concat "\\(^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]\\)\\|\\(^[ \t0-9]*do[ \t]*0*"
  651.               charnum "\\b\\)\\|\\(^[ \t]*0*" charnum "\\b\\)")
  652.           nil t)
  653.          (looking-at (concat "^[ \t0-9]*do[ \t]*0*" charnum))))))))
  654.  
  655.  
  656.