xref: /386bsd/usr/local/lib/emacs/19.25/lisp/fortran.el (revision a2142627)
1;;; fortran.el --- Fortran mode for GNU Emacs
2
3;;; Copyright (c) 1986, 1993, 1994 Free Software Foundation, Inc.
4
5;; Author: Michael D. Prange <prange@erl.mit.edu>
6;; Maintainer: bug-fortran-mode@erl.mit.edu
7;; Version 1.30.5 (May 20, 1994)
8;; Keywords: languages
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING.  If not, write to
24;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25
26;;; Commentary:
27
28;; Fortran mode has been upgraded and is now maintained by Stephen A. Wood
29;; (saw@cebaf.gov).  It now will use either fixed format continuation line
30;; markers (character in 6th column), or tab format continuation line style
31;; (digit after a TAB character.)  A auto-fill mode has been added to
32;; automatically wrap fortran lines that get too long.
33
34;; We acknowledge many contributions and valuable suggestions by
35;; Lawrence R. Dodd, Ralf Fassel, Ralph Finch, Stephen Gildea,
36;; Dr. Anil Gokhale, Ulrich Mueller, Mark Neale, Eric Prestemon,
37;; Gary Sabot and Richard Stallman.
38
39;;; This file may be used with GNU Emacs version 18.xx if the following
40;;; variable and function substitutions are made.
41;;;  Replace:
42;;;   frame-width                           with screen-width
43;;;   auto-fill-function                    with auto-fill-hook
44;;;   comment-indent-function               with comment-indent-hook
45;;;   (setq unread-command-events (list c)) with (setq unread-command-char c)
46
47;;; Bugs to bug-fortran-mode@erl.mit.edu
48
49(defconst fortran-mode-version "version 1.30.5")
50
51;;; Code:
52
53;;;###autoload
54(defvar fortran-tab-mode-default nil
55  "*Default tabbing/carriage control style for empty files in Fortran mode.
56A value of t specifies tab-digit style of continuation control.
57A value of nil specifies that continuation lines are marked
58with a character in column 6.")
59
60;; Buffer local, used to display mode line.
61(defvar fortran-tab-mode-string nil
62  "String to appear in mode line when TAB format mode is on.")
63
64(defvar fortran-do-indent 3
65  "*Extra indentation applied to DO blocks.")
66
67(defvar fortran-if-indent 3
68  "*Extra indentation applied to IF blocks.")
69
70(defvar fortran-structure-indent 3
71  "*Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks.")
72
73(defvar fortran-continuation-indent 5
74  "*Extra indentation applied to Fortran continuation lines.")
75
76(defvar fortran-comment-indent-style 'fixed
77  "*nil forces comment lines not to be touched,
78'fixed makes fixed comment indentation to `fortran-comment-line-extra-indent'
79columns beyond `fortran-minimum-statement-indent-fixed' (for
80`indent-tabs-mode' of nil) or `fortran-minimum-statement-indent-tab' (for
81`indent-tabs-mode' of t), and 'relative indents to current
82Fortran indentation plus `fortran-comment-line-extra-indent'.")
83
84(defvar fortran-comment-line-extra-indent 0
85  "*Amount of extra indentation for text within full-line comments.")
86
87(defvar comment-line-start nil
88  "*Delimiter inserted to start new full-line comment.")
89
90(defvar comment-line-start-skip nil
91  "*Regexp to match the start of a full-line comment.")
92
93(defvar fortran-minimum-statement-indent-fixed 6
94  "*Minimum statement indentation for fixed format continuation style.")
95
96(defvar fortran-minimum-statement-indent-tab (max tab-width 6)
97  "*Minimum statement indentation for TAB format continuation style.")
98
99;; Note that this is documented in the v18 manuals as being a string
100;; of length one rather than a single character.
101;; The code in this file accepts either format for compatibility.
102(defvar fortran-comment-indent-char " "
103  "*Single-character string inserted for Fortran comment indentation.
104Normally a space.")
105
106(defvar fortran-line-number-indent 1
107  "*Maximum indentation for Fortran line numbers.
1085 means right-justify them within their five-column field.")
109
110(defvar fortran-check-all-num-for-matching-do nil
111  "*Non-nil causes all numbered lines to be treated as possible DO loop ends.")
112
113(defvar fortran-blink-matching-if nil
114  "*From a Fortran ENDIF statement, blink the matching IF statement.
115Also, from an ENDDO statement, blink on matching DO [WHILE] statement.")
116
117(defvar fortran-continuation-string "$"
118  "*Single-character string used for Fortran continuation lines.
119In fixed format continuation style, this character is inserted in
120column 6 by \\[fortran-split-line] to begin a continuation line.
121Also, if \\[fortran-indent-line] finds this at the beginning of a line, it will
122convert the line into a continuation line of the appropriate style.
123Normally $.")
124
125(defvar fortran-comment-region "c$$$"
126  "*String inserted by \\[fortran-comment-region]\
127 at start of each line in region.")
128
129(defvar fortran-electric-line-number t
130  "*Non-nil causes line number digits to be moved to the correct column as\
131 typed.")
132
133(defvar fortran-startup-message t
134  "*Non-nil displays a startup message when Fortran mode is first called.")
135
136(defvar fortran-column-ruler-fixed
137  "0   4 6  10        20        30        40        5\
1380        60        70\n\
139[   ]|{   |    |    |    |    |    |    |    |    \
140|    |    |    |    |}\n"
141  "*String displayed above current line by \\[fortran-column-ruler].
142This variable used in fixed format mode.")
143
144(defvar fortran-column-ruler-tab
145  "0       810        20        30        40        5\
1460        60        70\n\
147[   ]|  { |    |    |    |    |    |    |    |    \
148|    |    |    |    |}\n"
149  "*String displayed above current line by \\[fortran-column-ruler].
150This variable used in TAB format mode.")
151
152(defconst bug-fortran-mode "bug-fortran-mode@erl.mit.edu"
153  "Address of mailing list for Fortran mode bugs.")
154
155(defvar fortran-mode-syntax-table nil
156  "Syntax table in use in Fortran mode buffers.")
157
158(defvar fortran-analyze-depth 100
159  "Number of lines to scan to determine whether to use fixed or TAB format\
160 style.")
161
162(defvar fortran-break-before-delimiters t
163  "*Non-nil causes `fortran-do-auto-fill' to break lines before delimiters.")
164
165(if fortran-mode-syntax-table
166    ()
167  (setq fortran-mode-syntax-table (make-syntax-table))
168  (modify-syntax-entry ?\; "w" fortran-mode-syntax-table)
169  (modify-syntax-entry ?\r " " fortran-mode-syntax-table)
170  (modify-syntax-entry ?+ "." fortran-mode-syntax-table)
171  (modify-syntax-entry ?- "." fortran-mode-syntax-table)
172  (modify-syntax-entry ?= "." fortran-mode-syntax-table)
173  (modify-syntax-entry ?* "." fortran-mode-syntax-table)
174  (modify-syntax-entry ?/ "." fortran-mode-syntax-table)
175  (modify-syntax-entry ?\' "\"" fortran-mode-syntax-table)
176  (modify-syntax-entry ?\" "\"" fortran-mode-syntax-table)
177  (modify-syntax-entry ?\\ "/" fortran-mode-syntax-table)
178  (modify-syntax-entry ?. "w" fortran-mode-syntax-table)
179  (modify-syntax-entry ?_ "w" fortran-mode-syntax-table)
180  (modify-syntax-entry ?\n ">" fortran-mode-syntax-table))
181
182(defvar fortran-mode-map ()
183  "Keymap used in Fortran mode.")
184(if fortran-mode-map
185    ()
186  (setq fortran-mode-map (make-sparse-keymap))
187  (define-key fortran-mode-map ";" 'fortran-abbrev-start)
188  (define-key fortran-mode-map "\C-c;" 'fortran-comment-region)
189  (define-key fortran-mode-map "\e\C-a" 'beginning-of-fortran-subprogram)
190  (define-key fortran-mode-map "\e\C-e" 'end-of-fortran-subprogram)
191  (define-key fortran-mode-map "\e;" 'fortran-indent-comment)
192  (define-key fortran-mode-map "\e\C-h" 'mark-fortran-subprogram)
193  (define-key fortran-mode-map "\e\n" 'fortran-split-line)
194  (define-key fortran-mode-map "\n" 'fortran-indent-new-line)
195  (define-key fortran-mode-map "\e\C-q" 'fortran-indent-subprogram)
196  (define-key fortran-mode-map "\C-c\C-w" 'fortran-window-create-momentarily)
197  (define-key fortran-mode-map "\C-c\C-r" 'fortran-column-ruler)
198  (define-key fortran-mode-map "\C-c\C-p" 'fortran-previous-statement)
199  (define-key fortran-mode-map "\C-c\C-n" 'fortran-next-statement)
200  (define-key fortran-mode-map "\t" 'fortran-indent-line)
201  (define-key fortran-mode-map "0" 'fortran-electric-line-number)
202  (define-key fortran-mode-map "1" 'fortran-electric-line-number)
203  (define-key fortran-mode-map "2" 'fortran-electric-line-number)
204  (define-key fortran-mode-map "3" 'fortran-electric-line-number)
205  (define-key fortran-mode-map "4" 'fortran-electric-line-number)
206  (define-key fortran-mode-map "5" 'fortran-electric-line-number)
207  (define-key fortran-mode-map "6" 'fortran-electric-line-number)
208  (define-key fortran-mode-map "7" 'fortran-electric-line-number)
209  (define-key fortran-mode-map "8" 'fortran-electric-line-number)
210  (define-key fortran-mode-map "9" 'fortran-electric-line-number))
211
212(defvar fortran-mode-abbrev-table nil)
213(if fortran-mode-abbrev-table
214    ()
215  (let ((ac abbrevs-changed))
216    (define-abbrev-table 'fortran-mode-abbrev-table ())
217    (define-abbrev fortran-mode-abbrev-table  ";au"  "automatic" nil)
218    (define-abbrev fortran-mode-abbrev-table  ";b"   "byte" nil)
219    (define-abbrev fortran-mode-abbrev-table  ";bd"  "block data" nil)
220    (define-abbrev fortran-mode-abbrev-table  ";ch"  "character" nil)
221    (define-abbrev fortran-mode-abbrev-table  ";cl"  "close" nil)
222    (define-abbrev fortran-mode-abbrev-table  ";c"   "continue" nil)
223    (define-abbrev fortran-mode-abbrev-table  ";cm"  "common" nil)
224    (define-abbrev fortran-mode-abbrev-table  ";cx"  "complex" nil)
225    (define-abbrev fortran-mode-abbrev-table  ";df"  "define" nil)
226    (define-abbrev fortran-mode-abbrev-table  ";di"  "dimension" nil)
227    (define-abbrev fortran-mode-abbrev-table  ";do"  "double" nil)
228    (define-abbrev fortran-mode-abbrev-table  ";dc"  "double complex" nil)
229    (define-abbrev fortran-mode-abbrev-table  ";dp"  "double precision" nil)
230    (define-abbrev fortran-mode-abbrev-table  ";dw"  "do while" nil)
231    (define-abbrev fortran-mode-abbrev-table  ";e"   "else" nil)
232    (define-abbrev fortran-mode-abbrev-table  ";ed"  "enddo" nil)
233    (define-abbrev fortran-mode-abbrev-table  ";el"  "elseif" nil)
234    (define-abbrev fortran-mode-abbrev-table  ";en"  "endif" nil)
235    (define-abbrev fortran-mode-abbrev-table  ";eq"  "equivalence" nil)
236    (define-abbrev fortran-mode-abbrev-table  ";ew"  "endwhere" nil)
237    (define-abbrev fortran-mode-abbrev-table  ";ex"  "external" nil)
238    (define-abbrev fortran-mode-abbrev-table  ";ey"  "entry" nil)
239    (define-abbrev fortran-mode-abbrev-table  ";f"   "format" nil)
240    (define-abbrev fortran-mode-abbrev-table  ";fa"  ".false." nil)
241    (define-abbrev fortran-mode-abbrev-table  ";fu"  "function" nil)
242    (define-abbrev fortran-mode-abbrev-table  ";g"   "goto" nil)
243    (define-abbrev fortran-mode-abbrev-table  ";im"  "implicit" nil)
244    (define-abbrev fortran-mode-abbrev-table  ";ib"  "implicit byte" nil)
245    (define-abbrev fortran-mode-abbrev-table  ";ic"  "implicit complex" nil)
246    (define-abbrev fortran-mode-abbrev-table  ";ich" "implicit character" nil)
247    (define-abbrev fortran-mode-abbrev-table  ";ii"  "implicit integer" nil)
248    (define-abbrev fortran-mode-abbrev-table  ";il"  "implicit logical" nil)
249    (define-abbrev fortran-mode-abbrev-table  ";ir"  "implicit real" nil)
250    (define-abbrev fortran-mode-abbrev-table  ";inc" "include" nil)
251    (define-abbrev fortran-mode-abbrev-table  ";in"  "integer" nil)
252    (define-abbrev fortran-mode-abbrev-table  ";intr" "intrinsic" nil)
253    (define-abbrev fortran-mode-abbrev-table  ";l"   "logical" nil)
254    (define-abbrev fortran-mode-abbrev-table  ";n"   "namelist" nil)
255    (define-abbrev fortran-mode-abbrev-table  ";o"   "open" nil) ; was ;op
256    (define-abbrev fortran-mode-abbrev-table  ";pa"  "parameter" nil)
257    (define-abbrev fortran-mode-abbrev-table  ";pr"  "program" nil)
258    (define-abbrev fortran-mode-abbrev-table  ";ps"  "pause" nil)
259    (define-abbrev fortran-mode-abbrev-table  ";p"   "print" nil)
260    (define-abbrev fortran-mode-abbrev-table  ";rc"  "record" nil)
261    (define-abbrev fortran-mode-abbrev-table  ";re"  "real" nil)
262    (define-abbrev fortran-mode-abbrev-table  ";r"   "read" nil)
263    (define-abbrev fortran-mode-abbrev-table  ";rt"  "return" nil)
264    (define-abbrev fortran-mode-abbrev-table  ";rw"  "rewind" nil)
265    (define-abbrev fortran-mode-abbrev-table  ";s"   "stop" nil)
266    (define-abbrev fortran-mode-abbrev-table  ";sa"  "save" nil)
267    (define-abbrev fortran-mode-abbrev-table  ";st"  "structure" nil)
268    (define-abbrev fortran-mode-abbrev-table  ";sc"  "static" nil)
269    (define-abbrev fortran-mode-abbrev-table  ";su"  "subroutine" nil)
270    (define-abbrev fortran-mode-abbrev-table  ";tr"  ".true." nil)
271    (define-abbrev fortran-mode-abbrev-table  ";ty"  "type" nil)
272    (define-abbrev fortran-mode-abbrev-table  ";vo"  "volatile" nil)
273    (define-abbrev fortran-mode-abbrev-table  ";w"   "write" nil)
274    (define-abbrev fortran-mode-abbrev-table  ";wh"  "where" nil)
275    (setq abbrevs-changed ac)))
276
277;;;###autoload
278(defun fortran-mode ()
279  "Major mode for editing Fortran code.
280\\[fortran-indent-line] indents the current Fortran line correctly.
281DO statements must not share a common CONTINUE.
282
283Type ;? or ;\\[help-command] to display a list of built-in\
284 abbrevs for Fortran keywords.
285
286Key definitions:
287\\{fortran-mode-map}
288
289Variables controlling indentation style and extra features:
290
291 comment-start
292    Normally nil in Fortran mode.  If you want to use comments
293    starting with `!', set this to the string \"!\".
294 fortran-do-indent
295    Extra indentation within do blocks.  (default 3)
296 fortran-if-indent
297    Extra indentation within if blocks.  (default 3)
298 fortran-structure-indent
299    Extra indentation within structure, union, map and interface blocks.
300    (default 3)
301 fortran-continuation-indent
302    Extra indentation applied to continuation statements.  (default 5)
303 fortran-comment-line-extra-indent
304    Amount of extra indentation for text within full-line comments. (default 0)
305 fortran-comment-indent-style
306    nil    means don't change indentation of text in full-line comments,
307    fixed  means indent that text at `fortran-comment-line-extra-indent' beyond
308           the value of `fortran-minimum-statement-indent-fixed' (for fixed
309           format continuation style) or `fortran-minimum-statement-indent-tab'
310           (for TAB format continuation style).
311    relative  means indent at `fortran-comment-line-extra-indent' beyond the
312 	      indentation for a line of code.
313    (default 'fixed)
314 fortran-comment-indent-char
315    Single-character string to be inserted instead of space for
316    full-line comment indentation.  (default \" \")
317 fortran-minimum-statement-indent-fixed
318    Minimum indentation for Fortran statements in fixed format mode. (def.6)
319 fortran-minimum-statement-indent-tab
320    Minimum indentation for Fortran statements in TAB format mode. (default 9)
321 fortran-line-number-indent
322    Maximum indentation for line numbers.  A line number will get
323    less than this much indentation if necessary to avoid reaching
324    column 5.  (default 1)
325 fortran-check-all-num-for-matching-do
326    Non-nil causes all numbered lines to be treated as possible \"continue\"
327    statements.  (default nil)
328 fortran-blink-matching-if
329    From a Fortran ENDIF statement, blink the matching IF statement.
330    Also, from an ENDDO statement, blink on matching DO [WHILE] statement.
331    (default nil)
332 fortran-continuation-string
333    Single-character string to be inserted in column 5 of a continuation
334    line.  (default \"$\")
335 fortran-comment-region
336    String inserted by \\[fortran-comment-region] at start of each line in
337    region.  (default \"c$$$\")
338 fortran-electric-line-number
339    Non-nil causes line number digits to be moved to the correct column
340    as typed.  (default t)
341 fortran-break-before-delimiters
342    Non-nil causes `fortran-do-auto-fill' breaks lines before delimiters.
343    (default t)
344 fortran-startup-message
345    Set to nil to inhibit message first time Fortran mode is used.
346
347Turning on Fortran mode calls the value of the variable `fortran-mode-hook'
348with no args, if that value is non-nil."
349  (interactive)
350  (kill-all-local-variables)
351  (if fortran-startup-message
352      (message "Emacs Fortran mode %s.  Bugs to %s"
353	       fortran-mode-version bug-fortran-mode))
354  (setq fortran-startup-message nil)
355  (setq local-abbrev-table fortran-mode-abbrev-table)
356  (set-syntax-table fortran-mode-syntax-table)
357  (make-local-variable 'fortran-break-before-delimiters)
358  (setq fortran-break-before-delimiters t)
359  (make-local-variable 'indent-line-function)
360  (setq indent-line-function 'fortran-indent-line)
361  (make-local-variable 'comment-indent-function)
362  (setq comment-indent-function 'fortran-comment-hook)
363  (make-local-variable 'comment-line-start-skip)
364  (setq comment-line-start-skip
365	"^[Cc*]\\(\\([^ \t\n]\\)\\2\\2*\\)?[ \t]*\\|^#.*")
366  (make-local-variable 'comment-line-start)
367  (setq comment-line-start "c")
368  (make-local-variable 'comment-start-skip)
369  (setq comment-start-skip "![ \t]*")
370  (make-local-variable 'comment-start)
371  (setq comment-start nil)
372  (make-local-variable 'require-final-newline)
373  (setq require-final-newline t)
374  (make-local-variable 'abbrev-all-caps)
375  (setq abbrev-all-caps t)
376  (make-local-variable 'indent-tabs-mode)
377  (setq indent-tabs-mode nil)
378;;;(setq abbrev-mode t) ; ?? (abbrev-mode 1) instead??
379  (setq fill-column 72) ; Already local?
380  (use-local-map fortran-mode-map)
381  (setq mode-name "Fortran")
382  (setq major-mode 'fortran-mode)
383;;;(make-local-variable 'fortran-tab-mode)
384  (make-local-variable 'fortran-comment-line-extra-indent)
385  (make-local-variable 'fortran-minimum-statement-indent-fixed)
386  (make-local-variable 'fortran-minimum-statement-indent-tab)
387  (make-local-variable 'fortran-column-ruler-fixed)
388  (make-local-variable 'fortran-column-ruler-tab)
389  (make-local-variable 'fortran-tab-mode-string)
390  (setq fortran-tab-mode-string " TAB-format")
391  (setq indent-tabs-mode (fortran-analyze-file-format))
392  (run-hooks 'fortran-mode-hook))
393
394(defun fortran-comment-hook ()
395  (save-excursion
396    (skip-chars-backward " \t")
397    (max (+ 1 (current-column))
398	 comment-column)))
399
400(defun fortran-indent-comment ()
401  "Align or create comment on current line.
402Existing comments of all types are recognized and aligned.
403If the line has no comment, a side-by-side comment is inserted and aligned
404if the value of  comment-start  is not nil.
405Otherwise, a separate-line comment is inserted, on this line
406or on a new line inserted before this line if this line is not blank."
407  (interactive)
408  (beginning-of-line)
409  ;; Recognize existing comments of either kind.
410  (cond ((looking-at comment-line-start-skip)
411	 (fortran-indent-line))
412	((fortran-find-comment-start-skip) ; catches any inline comment and
413					; leaves point after comment-start-skip
414	 (if comment-start-skip
415	     (progn (goto-char (match-beginning 0))
416		    (if (not (= (current-column) (fortran-comment-hook)))
417			(progn (delete-horizontal-space)
418			       (indent-to (fortran-comment-hook)))))
419	   (end-of-line)))        ; otherwise goto end of line or sth else?
420	;; No existing comment.
421	;; If side-by-side comments are defined, insert one,
422	;; unless line is now blank.
423	((and comment-start (not (looking-at "^[ \t]*$")))
424	 (end-of-line)
425	 (delete-horizontal-space)
426	 (indent-to (fortran-comment-hook))
427	 (insert comment-start))
428	;; Else insert separate-line comment, making a new line if nec.
429	(t
430	 (if (looking-at "^[ \t]*$")
431	     (delete-horizontal-space)
432	   (beginning-of-line)
433	   (insert "\n")
434	   (forward-char -1))
435	 (insert comment-line-start)
436	 (insert-char (if (stringp fortran-comment-indent-char)
437			  (aref fortran-comment-indent-char 0)
438			fortran-comment-indent-char)
439		      (- (calculate-fortran-indent) (current-column))))))
440
441(defun fortran-comment-region (beg-region end-region arg)
442  "Comments every line in the region.
443Puts fortran-comment-region at the beginning of every line in the region.
444BEG-REGION and END-REGION are args which specify the region boundaries.
445With non-nil ARG, uncomments the region."
446  (interactive "*r\nP")
447  (let ((end-region-mark (make-marker)) (save-point (point-marker)))
448    (set-marker end-region-mark end-region)
449    (goto-char beg-region)
450    (beginning-of-line)
451    (if (not arg)			;comment the region
452	(progn (insert fortran-comment-region)
453	       (while (and  (= (forward-line 1) 0)
454			    (< (point) end-region-mark))
455		 (insert fortran-comment-region)))
456      (let ((com (regexp-quote fortran-comment-region))) ;uncomment the region
457	(if (looking-at com)
458	    (delete-region (point) (match-end 0)))
459	(while (and  (= (forward-line 1) 0)
460		     (< (point) end-region-mark))
461	  (if (looking-at com)
462	      (delete-region (point) (match-end 0))))))
463    (goto-char save-point)
464    (set-marker end-region-mark nil)
465    (set-marker save-point nil)))
466
467(defun fortran-abbrev-start ()
468  "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs.
469Any other key combination is executed normally."
470  (interactive)
471  (let (c)
472    (insert last-command-char)
473    (if (or (eq (setq c (read-event)) ??)    ;insert char if not equal to `?'
474	    (eq c help-char))
475	(fortran-abbrev-help)
476      (setq unread-command-events (list c)))))
477
478(defun fortran-abbrev-help ()
479  "List the currently defined abbrevs in Fortran mode."
480  (interactive)
481  (message "Listing abbrev table...")
482  (display-buffer (fortran-prepare-abbrev-list-buffer))
483  (message "Listing abbrev table...done"))
484
485(defun fortran-prepare-abbrev-list-buffer ()
486  (save-excursion
487    (set-buffer (get-buffer-create "*Abbrevs*"))
488    (erase-buffer)
489    (insert-abbrev-table-description 'fortran-mode-abbrev-table t)
490    (goto-char (point-min))
491    (set-buffer-modified-p nil)
492    (edit-abbrevs-mode))
493  (get-buffer-create "*Abbrevs*"))
494
495(defun fortran-column-ruler ()
496  "Inserts a column ruler momentarily above current line, till next keystroke.
497The ruler is defined by the value of `fortran-column-ruler-fixed' when in fixed
498format mode, and `fortran-column-ruler-tab' when in TAB format mode.
499The key typed is executed unless it is SPC."
500  (interactive)
501  (momentary-string-display
502   (if indent-tabs-mode
503       fortran-column-ruler-tab
504     fortran-column-ruler-fixed)
505   (save-excursion
506     (beginning-of-line)
507     (if (eq (window-start (selected-window))
508	     (window-point (selected-window)))
509	 (progn (forward-line) (point))
510       (point)))
511   nil "Type SPC or any command to erase ruler."))
512
513(defun fortran-window-create ()
514  "Makes the window 72 columns wide.
515See also `fortran-window-create-momentarily'."
516  (interactive)
517  (condition-case error
518      (progn
519	(let ((window-min-width 2))
520	  (if (< (window-width) (frame-width))
521	      (enlarge-window-horizontally (- (frame-width)
522					      (window-width) 1)))
523	  (split-window-horizontally 73)
524	  (other-window 1)
525	  (switch-to-buffer " fortran-window-extra" t)
526	  (select-window (previous-window))))
527    (error (message "No room for Fortran window.")
528	   'error)))
529
530(defun fortran-window-create-momentarily (&optional arg)
531  "Momentarily makes the window 72 columns wide.
532Optional ARG non-nil and non-unity disables the momentary feature.
533See also `fortran-window-create'."
534  (interactive "p")
535  (if (or (not arg)
536	  (= arg 1))
537      (save-window-excursion
538	(if (not (equal (fortran-window-create) 'error))
539	    (progn (message "Type SPC to continue editing.")
540		   (let ((char (read-event)))
541		     (or (equal char (string-to-char " "))
542			 (setq unread-command-events (list char)))))))
543    (fortran-window-create)))
544
545(defun fortran-split-line ()
546  "Break line at point and insert continuation marker and alignment."
547  (interactive)
548  (delete-horizontal-space)
549  (if (save-excursion (beginning-of-line) (looking-at comment-line-start-skip))
550      (insert "\n" comment-line-start " ")
551    (if indent-tabs-mode
552	(progn
553	  (insert "\n\t")
554	  (insert-char (fortran-numerical-continuation-char) 1))
555      (insert "\n " fortran-continuation-string)));Space after \n important
556  (fortran-indent-line))		;when the cont string is C, c or *.
557
558(defun fortran-numerical-continuation-char ()
559  "Return a digit for tab-digit style of continuation lines.
560If, previous line is a tab-digit continuation line, returns that digit
561plus one.  Otherwise return 1.  Zero not allowed."
562  (save-excursion
563    (forward-line -1)
564    (if (looking-at "\t[1-9]")
565	(+ ?1 (% (- (char-after (+ (point) 1)) ?0) 9))
566      ?1)))
567
568(defun delete-horizontal-regexp (chars)
569  "Delete all characters in CHARS around point.
570CHARS is like the inside of a [...] in a regular expression
571except that ] is never special and \ quotes ^, - or \."
572  (interactive "*s")
573  (skip-chars-backward chars)
574  (delete-region (point) (progn (skip-chars-forward chars) (point))))
575
576(defun fortran-electric-line-number (arg)
577  "Self insert, but if part of a Fortran line number indent it automatically.
578Auto-indent does not happen if a numeric arg is used."
579  (interactive "P")
580  (if (or arg (not fortran-electric-line-number))
581      (if arg
582	  (self-insert-command (prefix-numeric-value arg))
583	(self-insert-command 1))
584    (if (or (and (= 5 (current-column))
585		 (save-excursion
586		   (beginning-of-line)
587		   (looking-at "     ")));In col 5 with only spaces to left.
588	    (and (= (if indent-tabs-mode
589		  fortran-minimum-statement-indent-tab
590		fortran-minimum-statement-indent-fixed) (current-column))
591		 (save-excursion
592		   (beginning-of-line)
593		   (looking-at "\t"));In col 8 with a single tab to the left.
594		 (not (or (eq last-command 'fortran-indent-line)
595			  (eq last-command
596			      'fortran-indent-new-line))))
597	    (save-excursion
598	      (re-search-backward "[^ \t0-9]"
599				  (save-excursion
600				    (beginning-of-line)
601				    (point))
602				  t)) ;not a line number
603	    (looking-at "[0-9]")	;within a line number
604	    )
605	(self-insert-command (prefix-numeric-value arg))
606      (skip-chars-backward " \t")
607      (insert last-command-char)
608      (fortran-indent-line))))
609
610(defun beginning-of-fortran-subprogram ()
611  "Moves point to the beginning of the current Fortran subprogram."
612  (interactive)
613  (let ((case-fold-search t))
614    (beginning-of-line -1)
615    (re-search-backward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
616    (if (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")
617	(forward-line 1))))
618
619(defun end-of-fortran-subprogram ()
620  "Moves point to the end of the current Fortran subprogram."
621  (interactive)
622  (let ((case-fold-search t))
623    (beginning-of-line 2)
624    (re-search-forward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
625    (goto-char (match-beginning 0))
626    (forward-line 1)))
627
628(defun mark-fortran-subprogram ()
629  "Put mark at end of Fortran subprogram, point at beginning.
630The marks are pushed."
631  (interactive)
632  (end-of-fortran-subprogram)
633  (push-mark (point))
634  (beginning-of-fortran-subprogram))
635
636(defun fortran-previous-statement ()
637  "Moves point to beginning of the previous Fortran statement.
638Returns `first-statement' if that statement is the first
639non-comment Fortran statement in the file, and nil otherwise."
640  (interactive)
641  (let (not-first-statement continue-test)
642    (beginning-of-line)
643    (setq continue-test
644	  (and
645	   (not (looking-at comment-line-start-skip))
646	   (or (looking-at
647	        (concat "[ \t]*" (regexp-quote fortran-continuation-string)))
648	       (or (looking-at "     [^ 0\n]")
649		   (looking-at "\t[1-9]")))))
650    (while (and (setq not-first-statement (= (forward-line -1) 0))
651		(or (looking-at comment-line-start-skip)
652		    (looking-at "[ \t]*$")
653		    (looking-at "     [^ 0\n]")
654		    (looking-at "\t[1-9]")
655		    (looking-at (concat "[ \t]*"  comment-start-skip)))))
656    (cond ((and continue-test
657		(not not-first-statement))
658	   (message "Incomplete continuation statement."))
659	  (continue-test
660	   (fortran-previous-statement))
661	  ((not not-first-statement)
662	   'first-statement))))
663
664(defun fortran-next-statement ()
665  "Moves point to beginning of the next Fortran statement.
666Returns `last-statement' if that statement is the last
667non-comment Fortran statement in the file, and nil otherwise."
668  (interactive)
669  (let (not-last-statement)
670    (beginning-of-line)
671    (while (and (setq not-last-statement
672		      (and (= (forward-line 1) 0)
673			   (not (eobp))))
674 		(or (looking-at comment-line-start-skip)
675 		    (looking-at "[ \t]*$")
676 		    (looking-at "     [^ 0\n]")
677 		    (looking-at "\t[1-9]")
678 		    (looking-at (concat "[ \t]*"  comment-start-skip)))))
679    (if (not not-last-statement)
680 	'last-statement)))
681
682(defun fortran-blink-matching-if ()
683  "From a Fortran ENDIF statement, blink the matching IF statement."
684  (let ((count 1) (top-of-window (window-start)) matching-if
685	(endif-point (point)) message)
686    (if (save-excursion (beginning-of-line)
687			(skip-chars-forward " \t0-9")
688			(looking-at "end[ \t]*if\\b"))
689	(progn
690	  (save-excursion
691	    (while (and (not (= count 0))
692			(not (eq (fortran-previous-statement)
693				 'first-statement))
694			(not (looking-at
695			      "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")))
696					; Keep local to subprogram
697	      (skip-chars-forward " \t0-9")
698	      (cond ((looking-at "if[ \t]*(")
699		     (save-excursion
700		       (if (or
701			    (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
702			    (let (then-test);multi-line if-then
703			      (while
704				  (and (= (forward-line 1) 0)
705					;search forward for then
706				       (or (looking-at "     [^ 0\n]")
707					   (looking-at "\t[1-9]"))
708				       (not
709					(setq
710					 then-test
711					 (looking-at
712					  ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
713			      then-test))
714			   (setq count (- count 1)))))
715		    ((looking-at "end[ \t]*if\\b")
716		     (setq count (+ count 1)))))
717	    (if (not (= count 0))
718		(setq message "No matching if.")
719	      (if (< (point) top-of-window)
720		  (setq message (concat "Matches " (buffer-substring
721						    (progn (beginning-of-line)
722							   (point))
723						    (progn (end-of-line)
724							   (point)))))
725		(setq matching-if (point)))))
726	  (if message
727	      (message "%s" message)
728	    (goto-char matching-if)
729	    (sit-for 1)
730	    (goto-char endif-point))))))
731
732(defun fortran-blink-matching-do ()
733  ;; From a Fortran ENDDO statement, blink on the matching DO or DO WHILE
734  ;; statement.  This is basically copied from fortran-blink-matching-if.
735  (let ((count 1) (top-of-window (window-start)) matching-do
736	(enddo-point (point)) message)
737    (if (save-excursion (beginning-of-line)
738			(skip-chars-forward " \t0-9")
739			(looking-at "end[ \t]*do\\b"))
740	(progn
741	  (save-excursion
742	    (while (and (not (= count 0))
743			(not (eq (fortran-previous-statement)
744				 'first-statement))
745			(not (looking-at
746			      "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")))
747					; Keep local to subprogram
748	      (skip-chars-forward " \t0-9")
749	      (cond ((looking-at "do[ \t]+")
750                     (setq count (- count 1)))
751		    ((looking-at "end[ \t]*do\\b")
752		     (setq count (+ count 1)))))
753	    (if (not (= count 0))
754		(setq message "No matching do.")
755	      (if (< (point) top-of-window)
756		  (setq message (concat "Matches " (buffer-substring
757						    (progn (beginning-of-line)
758							   (point))
759						    (progn (end-of-line)
760							   (point)))))
761		(setq matching-do (point)))))
762	  (if message
763	      (message "%s" message)
764	    (goto-char matching-do)
765	    (sit-for 1)
766	    (goto-char enddo-point))))))
767
768(defun fortran-indent-line ()
769  "Indents current Fortran line based on its contents and on previous lines."
770  (interactive)
771  (let ((cfi (calculate-fortran-indent)))
772    (save-excursion
773      (beginning-of-line)
774      (if (or (not (= cfi (fortran-current-line-indentation)))
775	      (and (re-search-forward "^[ \t]*[0-9]+" (+ (point) 4) t)
776		   (not (fortran-line-number-indented-correctly-p))))
777	  (fortran-indent-to-column cfi)
778	(beginning-of-line)
779	(if (and (not (looking-at comment-line-start-skip))
780		 (fortran-find-comment-start-skip))
781	    (fortran-indent-comment))))
782    ;; Never leave point in left margin.
783    (if (< (current-column) cfi)
784	(move-to-column cfi))
785    (if (and auto-fill-function
786	     (> (save-excursion (end-of-line) (current-column)) fill-column))
787	(save-excursion
788	  (end-of-line)
789	  (fortran-do-auto-fill)))
790    (if fortran-blink-matching-if
791	(progn
792	  (fortran-blink-matching-if)
793	  (fortran-blink-matching-do)))))
794
795(defun fortran-indent-new-line ()
796  "Reindent the current Fortran line, insert a newline and indent the newline.
797An abbrev before point is expanded if `abbrev-mode' is non-nil."
798  (interactive)
799  (if abbrev-mode (expand-abbrev))
800  (save-excursion
801    (beginning-of-line)
802    (skip-chars-forward " \t")
803    (if (or (looking-at "[0-9]")	;Reindent only where it is most
804	    (looking-at "end")		;likely to be necessary
805	    (looking-at "else")
806	    (looking-at (regexp-quote fortran-continuation-string)))
807	(fortran-indent-line)))
808  (newline)
809  (fortran-indent-line))
810
811(defun fortran-indent-subprogram ()
812  "Properly indents the Fortran subprogram which contains point."
813  (interactive)
814  (save-excursion
815    (mark-fortran-subprogram)
816    (message "Indenting subprogram...")
817    (indent-region (point) (mark) nil))
818  (message "Indenting subprogram...done."))
819
820(defun calculate-fortran-indent ()
821  "Calculates the Fortran indent column based on previous lines."
822  (let (icol first-statement (case-fold-search t)
823	     (fortran-minimum-statement-indent
824	      (if indent-tabs-mode
825		  fortran-minimum-statement-indent-tab
826		fortran-minimum-statement-indent-fixed)))
827    (save-excursion
828      (setq first-statement (fortran-previous-statement))
829      (if first-statement
830	  (setq icol fortran-minimum-statement-indent)
831	(progn
832	  (if (= (point) (point-min))
833	      (setq icol fortran-minimum-statement-indent)
834	    (setq icol (fortran-current-line-indentation)))
835	  (skip-chars-forward " \t0-9")
836	  (cond ((looking-at "if[ \t]*(")
837		 (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t_$(=a-z0-9]")
838			 (let (then-test)	;multi-line if-then
839			   (while (and (= (forward-line 1) 0)
840				       ;;search forward for then
841				       (or (looking-at "     [^ 0\n]")
842					   (looking-at "\t[1-9]"))
843				       (not (setq then-test (looking-at
844							     ".*then\\b[ \t]\
845*[^ \t_$(=a-z0-9]")))))
846			   then-test))
847		     (setq icol (+ icol fortran-if-indent))))
848		((looking-at "\\(else\\|elseif\\)\\b")
849		 (setq icol (+ icol fortran-if-indent)))
850		((looking-at "select[ \t]*case[ \t](.*)\\b")
851		 (setq icol (+ icol fortran-if-indent)))
852		((looking-at "case[ \t]*(.*)[ \t]*\n")
853		 (setq icol (+ icol fortran-if-indent)))
854		((looking-at "case[ \t]*default\\b")
855		 (setq icol (+ icol fortran-if-indent)))
856		((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
857		 (setq icol (+ icol fortran-if-indent)))
858		((looking-at "where[ \t]*(.*)[ \t]*\n")
859		 (setq icol (+ icol fortran-if-indent)))
860		((looking-at "do\\b")
861		 (setq icol (+ icol fortran-do-indent)))
862		((looking-at
863		  "\\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]")
864		 (setq icol (+ icol fortran-structure-indent)))
865		((looking-at "end\\b[ \t]*[^ \t=(a-z]")
866		 ;; Previous END resets indent to minimum
867		 (setq icol fortran-minimum-statement-indent))))))
868    (save-excursion
869      (beginning-of-line)
870      (cond ((looking-at "[ \t]*$"))
871	    ((looking-at comment-line-start-skip)
872	     (cond ((eq fortran-comment-indent-style 'relative)
873		    (setq icol (+ icol fortran-comment-line-extra-indent)))
874		   ((eq fortran-comment-indent-style 'fixed)
875		    (setq icol (+ fortran-minimum-statement-indent
876				  fortran-comment-line-extra-indent))))
877	     (setq fortran-minimum-statement-indent 0))
878	    ((or (looking-at (concat "[ \t]*"
879				     (regexp-quote
880				      fortran-continuation-string)))
881		 (looking-at "     [^ 0\n]")
882		 (looking-at "\t[1-9]"))
883	     (setq icol (+ icol fortran-continuation-indent)))
884	    ((looking-at "[ \t]*#")	; Check for cpp directive.
885	     (setq fortran-minimum-statement-indent 0 icol 0))
886	    (first-statement)
887	    ((and fortran-check-all-num-for-matching-do
888		  (looking-at "[ \t]*[0-9]+")
889		  (fortran-check-for-matching-do))
890	     (setq icol (- icol fortran-do-indent)))
891	    (t
892	     (skip-chars-forward " \t0-9")
893	     (cond ((looking-at "end[ \t]*if\\b")
894		    (setq icol (- icol fortran-if-indent)))
895		   ((looking-at "\\(else\\|elseif\\)\\b")
896		    (setq icol (- icol fortran-if-indent)))
897                   ((looking-at "case[ \t]*(.*)[ \t]*\n")
898		    (setq icol (- icol fortran-if-indent)))
899                   ((looking-at "case[ \t]*default\\b")
900		    (setq icol (- icol fortran-if-indent)))
901		   ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
902		    (setq icol (- icol fortran-if-indent)))
903		   ((looking-at "end[ \t]*where\\b")
904		    (setq icol (- icol fortran-if-indent)))
905		   ((and (looking-at "continue\\b")
906			 (fortran-check-for-matching-do))
907		    (setq icol (- icol fortran-do-indent)))
908		   ((looking-at "end[ \t]*do\\b")
909		    (setq icol (- icol fortran-do-indent)))
910		   ((looking-at
911		     "end[ \t]*\
912\\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]")
913		    (setq icol (- icol fortran-structure-indent)))
914		   ((looking-at
915		     "end[ \t]*select\\b[ \t]*[^ \t=(a-z]")
916		    (setq icol (- icol fortran-if-indent)))
917		   ((and (looking-at "end\\b[ \t]*[^ \t=(a-z]")
918			 (not (= icol fortran-minimum-statement-indent)))
919 		    (message "Warning: `end' not in column %d.  Probably\
920 an unclosed block." fortran-minimum-statement-indent))))))
921    (max fortran-minimum-statement-indent icol)))
922
923(defun fortran-current-line-indentation ()
924  "Indentation of current line, ignoring Fortran line number or continuation.
925This is the column position of the first non-whitespace character
926aside from the line number and/or column 5/8 line-continuation character.
927For comment lines, returns indentation of the first
928non-indentation text within the comment."
929  (save-excursion
930    (beginning-of-line)
931    (cond ((looking-at comment-line-start-skip)
932	   (goto-char (match-end 0))
933	   (skip-chars-forward
934	    (if (stringp fortran-comment-indent-char)
935		fortran-comment-indent-char
936	      (char-to-string fortran-comment-indent-char))))
937	  ((or (looking-at "     [^ 0\n]")
938	       (looking-at "\t[1-9]"))
939	   (goto-char (match-end 0)))
940	  (t
941	   ;; Move past line number.
942	   (skip-chars-forward "[ \t0-9]");From Uli
943	   ))
944    ;; Move past whitespace.
945    (skip-chars-forward " \t")
946    (current-column)))
947
948(defun fortran-indent-to-column (col)
949  "Indents current line with spaces to column COL.
950notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
951          line, and this continuation character is retained on indentation;
952       2) If `fortran-continuation-string' is the first non-whitespace
953          character, this is a continuation line;
954       3) A non-continuation line which has a number as the first
955          non-whitespace character is a numbered line.
956       4) A TAB followed by a digit indicates a continuation line."
957  (save-excursion
958    (beginning-of-line)
959    (if (looking-at comment-line-start-skip)
960	(if fortran-comment-indent-style
961	    (let ((char (if (stringp fortran-comment-indent-char)
962			    (aref fortran-comment-indent-char 0)
963			  fortran-comment-indent-char)))
964	      (goto-char (match-end 0))
965	      (delete-horizontal-regexp (concat " \t" (char-to-string char)))
966	      (insert-char char (- col (current-column)))))
967      (if (looking-at "\t[1-9]")
968	  (if indent-tabs-mode
969	      (goto-char (match-end 0))
970	    (delete-char 2)
971	    (insert "     ")
972	    (insert fortran-continuation-string))
973	(if (looking-at "     [^ 0\n]")
974	    (if indent-tabs-mode
975		(progn (delete-char 6)
976		       (insert "\t")
977		       (insert-char (fortran-numerical-continuation-char) 1))
978	      (forward-char 6))
979	  (delete-horizontal-space)
980	  ;; Put line number in columns 0-4
981	  ;; or put continuation character in column 5.
982	  (cond ((eobp))
983		((looking-at (regexp-quote fortran-continuation-string))
984		 (if indent-tabs-mode
985		     (progn
986		       (indent-to
987			(if indent-tabs-mode
988			    fortran-minimum-statement-indent-tab
989			  fortran-minimum-statement-indent-fixed))
990		       (delete-char 1)
991		       (insert-char (fortran-numerical-continuation-char) 1))
992		   (indent-to 5)
993		   (forward-char 1)))
994		((looking-at "[0-9]+")
995		 (let ((extra-space (- 5 (- (match-end 0) (point)))))
996		   (if (< extra-space 0)
997		       (message "Warning: line number exceeds 5-digit limit.")
998		     (indent-to (min fortran-line-number-indent extra-space))))
999		 (skip-chars-forward "0-9")))))
1000      ;; Point is now after any continuation character or line number.
1001      ;; Put body of statement where specified.
1002      (delete-horizontal-space)
1003      (indent-to col)
1004      ;; Indent any comment following code on the same line.
1005      (if (and comment-start-skip
1006	       (fortran-find-comment-start-skip))
1007	  (progn (goto-char (match-beginning 0))
1008		 (if (not (= (current-column) (fortran-comment-hook)))
1009		     (progn (delete-horizontal-space)
1010			    (indent-to (fortran-comment-hook)))))))))
1011
1012(defun fortran-line-number-indented-correctly-p ()
1013  "Return t if current line's line number is correctly indented.
1014Do not call if there is no line number."
1015  (save-excursion
1016    (beginning-of-line)
1017    (skip-chars-forward " \t")
1018    (and (<= (current-column) fortran-line-number-indent)
1019	 (or (= (current-column) fortran-line-number-indent)
1020	     (progn (skip-chars-forward "0-9")
1021		    (= (current-column) 5))))))
1022
1023(defun fortran-check-for-matching-do ()
1024  "When called from a numbered statement, returns t if matching DO is found.
1025Otherwise return a nil."
1026  (let (charnum
1027	(case-fold-search t))
1028    (save-excursion
1029      (beginning-of-line)
1030      (if (looking-at "[ \t]*[0-9]+")
1031	  (progn
1032	    (skip-chars-forward " \t")
1033	    (skip-chars-forward "0") ;skip past leading zeros
1034	    (setq charnum (buffer-substring (point)
1035					    (progn (skip-chars-forward "0-9")
1036						   (point))))
1037	    (beginning-of-line)
1038	    (and (re-search-backward
1039		  (concat
1040		   "\\(^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]\\)\\|\\(^[ \t0-9]*do\
1041[ \t]*0*"
1042		   charnum "\\b\\)\\|\\(^[ \t]*0*" charnum "\\b\\)")
1043		  nil t)
1044		 (looking-at (concat "^[ \t0-9]*do[ \t]*0*" charnum))))))))
1045
1046(defun fortran-find-comment-start-skip ()
1047  "Move to past `comment-start-skip' found on current line.
1048Return t if `comment-start-skip' found, nil if not."
1049;;; In order to move point only if comment-start-skip is found,
1050;;; this one uses a lot of save-excursions.  Note that re-search-forward
1051;;; moves point even if comment-start-skip is inside a string-constant.
1052;;; Some code expects certain values for match-beginning and end
1053  (interactive)
1054  (let ((save-match-beginning) (save-match-end))
1055    (if (save-excursion
1056	  (re-search-forward comment-start-skip
1057			     (save-excursion (end-of-line) (point)) t))
1058	(progn
1059	  (setq save-match-beginning (match-beginning 0))
1060	  (setq save-match-end (match-end 0))
1061	  (if (fortran-is-in-string-p (match-beginning 0))
1062	      (progn
1063		(save-excursion
1064		  (goto-char save-match-end)
1065		  (fortran-find-comment-start-skip)) ; recurse for rest of line
1066		)
1067	    (goto-char save-match-beginning)
1068	    (re-search-forward comment-start-skip
1069			       (save-excursion (end-of-line) (point)) t)
1070	    (goto-char (match-end 0))
1071	    t))
1072      nil)))
1073
1074;;;From: ralf@up3aud1.gwdg.de (Ralf Fassel)
1075;;; Test if TAB format continuation lines work.
1076(defun fortran-is-in-string-p (where)
1077  "Return non-nil if POS (a buffer position) is inside a Fortran string,
1078nil else."
1079  (save-excursion
1080    (goto-char where)
1081    (cond
1082     ((bolp) nil)			; bol is never inside a string
1083     ((save-excursion			; comment lines too
1084	(beginning-of-line)(looking-at comment-line-start-skip)) nil)
1085     (t (let (;; ok, serious now. Init some local vars:
1086	      (parse-state '(0 nil nil nil nil nil 0))
1087	      (quoted-comment-start (if comment-start
1088					(regexp-quote comment-start)))
1089	      (not-done t)
1090	      parse-limit
1091	      end-of-line
1092	      )
1093	  ;; move to start of current statement
1094	  (fortran-next-statement)
1095	  (fortran-previous-statement)
1096	  ;; now parse up to WHERE
1097	  (while not-done
1098	    (if (or ;; skip to next line if:
1099		 ;; - comment line?
1100		 (looking-at comment-line-start-skip)
1101		 ;; - at end of line?
1102		 (eolp)
1103		 ;; - not in a string and after comment-start?
1104		 (and (not (nth 3 parse-state))
1105		      comment-start
1106		      (equal comment-start
1107			     (char-to-string (preceding-char)))))
1108		;; get around a bug in forward-line in versions <= 18.57
1109		(if (or (> (forward-line 1) 0) (eobp))
1110		    (setq not-done nil))
1111	      ;; else:
1112	      ;; if we are at beginning of code line, skip any
1113	      ;; whitespace, labels and tab continuation markers.
1114	      (if (bolp) (skip-chars-forward " \t0-9"))
1115	      ;; if we are in column <= 5 now, check for continuation char
1116	      (cond ((= 5 (current-column)) (forward-char 1))
1117		    ((and (< (current-column) 5)
1118			  (equal fortran-continuation-string
1119				 (char-to-string (following-char)))
1120			  (forward-char 1))))
1121	      ;; find out parse-limit from here
1122	      (setq end-of-line (save-excursion (end-of-line)(point)))
1123	      (setq parse-limit (min where end-of-line))
1124	      ;; parse max up to comment-start, if non-nil and in current line
1125	      (if comment-start
1126		  (save-excursion
1127		    (if (re-search-forward quoted-comment-start end-of-line t)
1128			(setq parse-limit (min (point) parse-limit)))))
1129	      ;; now parse if still in limits
1130	      (if (< (point) where)
1131		  (setq parse-state (parse-partial-sexp
1132				     (point) parse-limit nil nil parse-state))
1133		(setq not-done nil))
1134	      ))
1135	  ;; result is
1136	  (nth 3 parse-state))))))
1137
1138(defun fortran-auto-fill-mode (arg)
1139  "Toggle fortran-auto-fill mode.
1140With ARG, turn `fortran-auto-fill' mode on iff ARG is positive.
1141In `fortran-auto-fill' mode, inserting a space at a column beyond `fill-column'
1142automatically breaks the line at a previous space."
1143  (interactive "P")
1144  (prog1 (setq auto-fill-function
1145	       (if (if (null arg)
1146		       (not auto-fill-function)
1147		     (> (prefix-numeric-value arg) 0))
1148		   'fortran-indent-line
1149		 nil))
1150    ;; update mode-line
1151    (set-buffer-modified-p (buffer-modified-p))))
1152
1153(defun fortran-do-auto-fill ()
1154  (interactive)
1155  (let* ((opoint (point))
1156	 (bol (save-excursion (beginning-of-line) (point)))
1157	 (eol (save-excursion (end-of-line) (point)))
1158	 (bos (min eol (+ bol (fortran-current-line-indentation))))
1159	 (quote
1160	  (save-excursion
1161	    (goto-char bol)
1162	    (if (looking-at comment-line-start-skip)
1163		nil			; OK to break quotes on comment lines.
1164	      (move-to-column fill-column)
1165	      (cond ((fortran-is-in-string-p (point))
1166		     (save-excursion (re-search-backward "[^']'[^']" bol t)
1167				     (if fortran-break-before-delimiters
1168					 (point)
1169				       (1+ (point)))))
1170		    (t nil)))))
1171	 ;;
1172	 ;; decide where to split the line. If a position for a quoted
1173	 ;; string was found above then use that, else break the line
1174	 ;; before the last delimiter.
1175	 ;; Delimiters are whitespace, commas, and operators.
1176	 ;; Will break before a pair of *'s.
1177	 ;;
1178	 (fill-point
1179	  (or quote
1180	      (save-excursion
1181		(move-to-column (1+ fill-column))
1182		(skip-chars-backward "^ \t\n,'+-/*=)"
1183;;;		 (if fortran-break-before-delimiters
1184;;;		     "^ \t\n,'+-/*=" "^ \t\n,'+-/*=)")
1185		 )
1186		(if (<= (point) (1+ bos))
1187		    (progn
1188		      (move-to-column (1+ fill-column))
1189;;;what is this doing???
1190		      (if (not (re-search-forward "[\t\n,'+-/*)=]" eol t))
1191			  (goto-char bol))))
1192		(if (bolp)
1193		    (re-search-forward "[ \t]" opoint t)
1194		  (forward-char -1)
1195		  (if (looking-at "'")
1196		      (forward-char 1)
1197		    (skip-chars-backward " \t\*")))
1198		(if fortran-break-before-delimiters
1199		    (point)
1200		  (1+ (point))))))
1201	 )
1202    ;; if we are in an in-line comment, don't break unless the
1203    ;; line of code is longer than it should be. Otherwise
1204    ;; break the line at the column computed above.
1205    ;;
1206    ;; Need to use fortran-find-comment-start-skip to make sure that quoted !'s
1207    ;; don't prevent a break.
1208    (if (not (or (save-excursion
1209		   (if (and (re-search-backward comment-start-skip bol t)
1210			    (not (fortran-is-in-string-p (point))))
1211		       (progn
1212			 (skip-chars-backward " \t")
1213			 (< (current-column) (1+ fill-column)))))
1214		 (save-excursion
1215		   (goto-char fill-point)
1216		   (bolp))))
1217	(if (> (save-excursion
1218		 (goto-char fill-point) (current-column))
1219	       (1+ fill-column))
1220	    (progn (goto-char fill-point)
1221		   (fortran-break-line))
1222	  (save-excursion
1223	    (if (> (save-excursion
1224		     (goto-char fill-point)
1225		     (current-column))
1226		   (+ (calculate-fortran-indent) fortran-continuation-indent))
1227		(progn
1228		  (goto-char fill-point)
1229		  (fortran-break-line))))))
1230    ))
1231(defun fortran-break-line ()
1232  (let ((opoint (point))
1233	(bol (save-excursion (beginning-of-line) (point)))
1234	(eol (save-excursion (end-of-line) (point)))
1235	(comment-string nil))
1236
1237    (save-excursion
1238      (if (and comment-start-skip (fortran-find-comment-start-skip))
1239	  (progn
1240	    (re-search-backward comment-start-skip bol t)
1241	    (setq comment-string (buffer-substring (point) eol))
1242	    (delete-region (point) eol))))
1243;;; Forward line 1 really needs to go to next non white line
1244    (if (save-excursion (forward-line 1)
1245			(or (looking-at "     [^ 0\n]")
1246			    (looking-at "\t[1-9]")))
1247	(progn
1248	  (forward-line 1)
1249	  (delete-indentation)
1250	  (delete-char 2)
1251	  (delete-horizontal-space)
1252	  (fortran-do-auto-fill))
1253      (fortran-split-line))
1254    (if comment-string
1255	(save-excursion
1256	  (goto-char bol)
1257	  (end-of-line)
1258	  (delete-horizontal-space)
1259	  (indent-to (fortran-comment-hook))
1260	  (insert comment-string)))))
1261
1262(defun fortran-analyze-file-format ()
1263  "Returns nil if fixed format is used, t if TAB formatting is used.
1264Use `fortran-tab-mode-default' if no non-comment statements are found in the
1265file before the end or the first `fortran-analyze-depth' lines."
1266  (let ((i 0))
1267    (save-excursion
1268      (goto-char (point-min))
1269      (setq i 0)
1270      (while (not (or
1271		   (eobp)
1272		   (looking-at "\t")
1273		   (looking-at "      ")
1274		   (> i fortran-analyze-depth)))
1275	(forward-line)
1276	(setq i (1+ i)))
1277      (cond
1278       ((looking-at "\t") t)
1279       ((looking-at "      ") nil)
1280       (fortran-tab-mode-default t)
1281       (t nil)))))
1282
1283(or (assq 'fortran-tab-mode-string minor-mode-alist)
1284    (setq minor-mode-alist (cons
1285			    '(fortran-tab-mode-string
1286			      (indent-tabs-mode fortran-tab-mode-string))
1287			    minor-mode-alist)))
1288
1289(provide 'fortran)
1290
1291;;; fortran.el ends here
1292
1293