Initial Commit
[packages] / xemacs-packages / fortran-modes / fortran.el
1 ;;; fortran.el --- Fortran mode for GNU Emacs
2
3 ;; Copyright (c) 1986, 1993, 1994, 1995 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.6-x (July 27, 1995)
8 ;; Keywords: languages
9
10 ;; This file is part of XEmacs.
11
12 ;; XEmacs is free software; you can redistribute it and/or modify it
13 ;; 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 ;; XEmacs is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with XEmacs; see the file COPYING.  If not, write to the Free
24 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 ;; 02111-1307, USA.
26
27 ;;; Synched up with: FSF 19.34.
28
29 ;;; Commentary:
30
31 ;; Fortran mode has been upgraded and is now maintained by Stephen A. Wood
32 ;; (saw@cebaf.gov).  It now will use either fixed format continuation line
33 ;; markers (character in 6th column), or tab format continuation line style
34 ;; (digit after a TAB character.)  A auto-fill mode has been added to
35 ;; automatically wrap fortran lines that get too long.
36
37 ;; We acknowledge many contributions and valuable suggestions by
38 ;; Lawrence R. Dodd, Ralf Fassel, Ralph Finch, Stephen Gildea,
39 ;; Dr. Anil Gokhale, Ulrich Mueller, Mark Neale, Eric Prestemon, 
40 ;; Gary Sabot and Richard Stallman.
41
42 ;; This file may be used with GNU Emacs version 18.xx if the following
43 ;; variable and function substitutions are made.
44 ;;  Replace:
45 ;;   frame-width                           with screen-width
46 ;;   auto-fill-function                    with auto-fill-hook
47 ;;   comment-indent-function               with comment-indent-hook
48 ;;   (setq unread-command-events (list c)) with (setq unread-command-char c)
49
50 ;; Bugs to bug-fortran-mode@erl.mit.edu
51
52 ;;; Code:
53
54 (defconst fortran-mode-version "version 1.30.6-x")
55
56 (defgroup fortran nil
57   "Fortran mode for Emacs"
58   :group 'languages)
59
60 (defgroup fortran-indent nil
61   "Indentation variables in Fortran mode"
62   :prefix "fortran-"
63   :group 'fortran)
64
65 (defgroup fortran-comment nil
66   "Comment-handling variables in Fortran mode"
67   :prefix "fortran-"
68   :group 'fortran)
69
70
71 ;;;###autoload
72 (defcustom fortran-tab-mode-default nil
73   "*Default tabbing/carriage control style for empty files in Fortran mode.
74 A value of t specifies tab-digit style of continuation control.
75 A value of nil specifies that continuation lines are marked
76 with a character in column 6."
77   :type 'boolean
78   :group 'fortran-indent)
79
80 ;; Buffer local, used to display mode line.
81 (defcustom fortran-tab-mode-string nil
82   "String to appear in mode line when TAB format mode is on."
83   :type '(choice (const nil) string)
84   :group 'fortran-indent)
85
86 (defcustom fortran-do-indent 3
87   "*Extra indentation applied to DO blocks."
88   :type 'integer
89   :group 'fortran-indent)
90
91 (defcustom fortran-if-indent 3
92   "*Extra indentation applied to IF blocks."
93   :type 'integer
94   :group 'fortran-indent)
95
96 (defcustom fortran-structure-indent 3
97   "*Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks."
98   :type 'integer
99   :group 'fortran-indent)
100
101 (defcustom fortran-continuation-indent 5
102   "*Extra indentation applied to Fortran continuation lines."
103   :type 'integer
104   :group 'fortran-indent)
105
106 (defcustom fortran-comment-indent-style 'fixed
107   "*nil forces comment lines not to be touched,
108 'fixed makes fixed comment indentation to `fortran-comment-line-extra-indent'
109 columns beyond `fortran-minimum-statement-indent-fixed' (for
110 `indent-tabs-mode' of nil) or `fortran-minimum-statement-indent-tab' (for
111 `indent-tabs-mode' of t), and 'relative indents to current
112 Fortran indentation plus `fortran-comment-line-extra-indent'."
113   :type '(radio (const nil) (const fixed) (const relative))
114   :group 'fortran-indent)
115
116 (defcustom fortran-comment-line-extra-indent 0
117   "*Amount of extra indentation for text within full-line comments."
118   :type 'integer
119   :group 'fortran-indent
120   :group 'fortran-comment)
121
122 (defcustom fortran-comment-line-start nil
123   "*Delimiter inserted to start new full-line comment."
124   :type '(choice string (const nil))
125   :group 'fortran-comment)
126
127 (defcustom fortran-comment-line-start-skip nil
128   "*Regexp to match the start of a full-line comment."
129   :type '(choice string (const nil))
130   :group 'fortran-comment)
131
132 (defcustom fortran-minimum-statement-indent-fixed 6
133   "*Minimum statement indentation for fixed format continuation style."
134   :type 'integer
135   :group 'fortran-indent)
136
137 (defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
138   "*Minimum statement indentation for TAB format continuation style."
139   :type 'integer
140   :group 'fortran-indent)
141
142 ;; Note that this is documented in the v18 manuals as being a string
143 ;; of length one rather than a single character.
144 ;; The code in this file accepts either format for compatibility.
145 (defcustom fortran-comment-indent-char " "
146   "*Single-character string inserted for Fortran comment indentation.
147 Normally a space."
148   :type 'string
149   :group 'fortran-comment)
150
151 (defcustom fortran-line-number-indent 1
152   "*Maximum indentation for Fortran line numbers.
153 5 means right-justify them within their five-column field."
154   :type 'integer
155   :group 'fortran-indent)
156
157 (defcustom fortran-check-all-num-for-matching-do nil
158   "*Non-nil causes all numbered lines to be treated as possible DO loop ends."
159   :type 'boolean
160   :group 'fortran)
161
162 (defcustom fortran-blink-matching-if nil
163   "*Non-nil causes \\[fortran-indent-line] on ENDIF statement to blink on matching IF.
164 Also, from an ENDDO statement blink on matching DO [WHILE] statement."
165   :type 'boolean
166   :group 'fortran)
167
168 (defcustom fortran-continuation-string "$"
169   "*Single-character string used for Fortran continuation lines.
170 In fixed format continuation style, this character is inserted in
171 column 6 by \\[fortran-split-line] to begin a continuation line.
172 Also, if \\[fortran-indent-line] finds this at the beginning of a line, it will
173 convert the line into a continuation line of the appropriate style.
174 Normally $."
175   :type 'string
176   :group 'fortran)
177
178 (defcustom fortran-comment-region "c$$$"
179   "*String inserted by \\[fortran-comment-region]\
180  at start of each line in region."
181   :type 'string
182   :group 'fortran-comment)
183
184 (defcustom fortran-electric-line-number t
185   "*Non-nil causes line number digits to be moved to the correct column as\
186  typed."
187   :type 'boolean
188   :group 'fortran)
189
190 (defcustom fortran-startup-message t
191   "*Non-nil displays a startup message when Fortran mode is first called."
192   :type 'boolean
193   :group 'fortran)
194
195 (defvar fortran-column-ruler-fixed
196   "0   4 6  10        20        30        40        5\
197 \0        60        70\n\
198 \[   ]|{   |    |    |    |    |    |    |    |    \
199 \|    |    |    |    |}\n"
200   "*String displayed above current line by \\[fortran-column-ruler].
201 This variable used in fixed format mode.")
202
203 (defvar fortran-column-ruler-tab
204   "0       810        20        30        40        5\
205 \0        60        70\n\
206 \[   ]|  { |    |    |    |    |    |    |    |    \
207 \|    |    |    |    |}\n"
208   "*String displayed above current line by \\[fortran-column-ruler].
209 This variable used in TAB format mode.")
210
211 (defconst bug-fortran-mode "bug-fortran-mode@erl.mit.edu"
212   "Address of mailing list for Fortran mode bugs.")
213
214 (defvar fortran-mode-syntax-table nil
215   "Syntax table in use in Fortran mode buffers.")
216
217 (defvar fortran-analyze-depth 100
218   "Number of lines to scan to determine whether to use fixed or TAB format\
219  style.")
220
221 (defcustom fortran-break-before-delimiters t
222   "*Non-nil causes `fortran-fill' to break lines before delimiters."
223   :type 'boolean
224   :group 'fortran)
225
226 (if fortran-mode-syntax-table
227     ()
228   (setq fortran-mode-syntax-table (make-syntax-table))
229   (modify-syntax-entry ?\; "w" fortran-mode-syntax-table)
230   (modify-syntax-entry ?\r " " fortran-mode-syntax-table)
231   (modify-syntax-entry ?+  "." fortran-mode-syntax-table)
232   (modify-syntax-entry ?-  "." fortran-mode-syntax-table)
233   (modify-syntax-entry ?=  "." fortran-mode-syntax-table)
234   ;; XEmacs change
235   ;;(modify-syntax-entry ?* "." fortran-mode-syntax-table)
236   (modify-syntax-entry ?/  "."  fortran-mode-syntax-table)
237   (modify-syntax-entry ?\' "\"" fortran-mode-syntax-table)
238   (modify-syntax-entry ?\" "\"" fortran-mode-syntax-table)
239   (modify-syntax-entry ?\\ "/"  fortran-mode-syntax-table)
240   (modify-syntax-entry ?.  "_"  fortran-mode-syntax-table)
241   (modify-syntax-entry ?_  "_"  fortran-mode-syntax-table)
242   (modify-syntax-entry ?$  "_"  fortran-mode-syntax-table)
243   (modify-syntax-entry ?@  "_"  fortran-mode-syntax-table)
244   (modify-syntax-entry ?\! "<"  fortran-mode-syntax-table)
245   ;; XEmacs change
246   ;;(modify-syntax-entry ?\n ">" fortran-mode-syntax-table)
247
248   ;; XEmacs: an attempt to make font-lock understand fortran comments.
249   (modify-syntax-entry ?\n "> 1" fortran-mode-syntax-table)
250   (modify-syntax-entry ?*  ". 2" fortran-mode-syntax-table)
251   (modify-syntax-entry ?c  "w 2" fortran-mode-syntax-table)
252   (modify-syntax-entry ?C  "w 2" fortran-mode-syntax-table)
253
254   )
255
256 ;; Comments are real pain in Fortran because there is no way to represent the
257 ;; standard comment syntax in an Emacs syntax table (we can for VAX-style).
258 ;; Therefore an unmatched quote in a standard comment will throw fontification
259 ;; off on the wrong track.  So we do syntactic fontification with regexps.
260
261 ;; Regexps done by simon@gnu with help from Ulrik Dickow <dickow@nbi.dk> and
262 ;; probably others Si's forgotten about (sorry).
263
264 (defconst fortran-font-lock-keywords-1 nil
265   "Subdued level highlighting for Fortran mode.")
266
267 (defconst fortran-font-lock-keywords-2 nil
268   "Medium level highlighting for Fortran mode.")
269
270 (defconst fortran-font-lock-keywords-3 nil
271   "Gaudy level highlighting for Fortran mode.")
272
273 (let ((comment-chars "c!*")
274       (fortran-type-types
275 ;     (make-regexp
276 ;      (let ((simple-types '("character" "byte" "integer" "logical"
277 ;                           "none" "real" "complex"
278 ;                           "double[ \t]*precision" "double[ \t]*complex"))
279 ;           (structured-types '("structure" "union" "map"))
280 ;           (other-types '("record" "dimension" "parameter" "common" "save"
281 ;                          "external" "intrinsic" "data" "equivalence")))
282 ;       (append
283 ;        (mapcar (lambda (x) (concat "implicit[ \t]*" x)) simple-types)
284 ;        simple-types
285 ;        (mapcar (lambda (x) (concat "end[ \t]*" x)) structured-types)
286 ;        structured-types
287 ;        other-types)))
288           (concat "byte\\|c\\(haracter\\|om\\(mon\\|plex\\)\\)\\|"
289                   "d\\(ata\\|imension\\|ouble"
290                   "[ \t]*\\(complex\\|precision\\)\\)\\|"
291                   "e\\(nd[ \t]*\\(map\\|structure\\|union\\)\\|"
292                   "quivalence\\|xternal\\)\\|"
293                   "i\\(mplicit[ \t]*\\(byte\\|"
294                   "c\\(haracter\\|omplex\\)\\|"
295                   "double[ \t]*\\(complex\\|precision\\)\\|"
296                   "integer\\|logical\\|none\\|real\\)\\|"
297                   "nt\\(eger\\|rinsic\\)\\)\\|"
298                   "logical\\|map\\|none\\|parameter\\|re\\(al\\|cord\\)\\|"
299                   "s\\(ave\\|tructure\\)\\|union"))
300          (fortran-keywords
301 ;         ("continue" "format" "end" "enddo" "if" "then" "else" "endif"
302 ;          "elseif" "while" "inquire" "stop" "return" "include" "open"
303 ;          "close" "read" "write" "format" "print")
304           (concat "c\\(lose\\|ontinue\\)\\|"
305                   "e\\(lse\\(\\|if\\)\\|nd\\(\\|do\\|if\\)\\)\\|format\\|"
306                   "i\\(f\\|n\\(clude\\|quire\\)\\)\\|open\\|print\\|"
307                   "re\\(ad\\|turn\\)\\|stop\\|then\\|w\\(hile\\|rite\\)"))
308         (fortran-logicals
309 ;       ("and" "or" "not" "lt" "le" "eq" "ge" "gt" "ne" "true" "false")
310          "and\\|eq\\|false\\|g[et]\\|l[et]\\|n\\(e\\|ot\\)\\|or\\|true"))
311
312   (setq fortran-font-lock-keywords-1
313    (list
314     ;;
315     ;; Fontify syntactically (assuming strings cannot be quoted or span lines).
316     (cons (concat "^[" comment-chars "].*") 'font-lock-comment-face)
317     '(fortran-match-!-comment . font-lock-comment-face)
318     (list (concat "^[^" comment-chars "\t\n]" (make-string 71 ?.) "\\(.*\\)")
319           '(1 font-lock-comment-face))
320     '("'[^'\n]*'?" . font-lock-string-face)
321     ;;
322     ;; Program, subroutine and function declarations, plus calls.
323     (list (concat "\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|"
324                   "program\\|subroutine\\)\\>[ \t]*\\(\\(\\sw\\|\\s_\\)+\\)?")
325           '(1 font-lock-keyword-face)
326           '(2 font-lock-function-name-face nil t))))
327
328   (setq fortran-font-lock-keywords-2
329    (append fortran-font-lock-keywords-1
330     (list
331      ;;
332      ;; Fontify all type specifiers (must be first; see below).
333      (cons (concat "\\<\\(" fortran-type-types "\\)\\>") 'font-lock-type-face)
334      ;;
335      ;; Fontify all builtin keywords (except logical, do and goto; see below).
336      (concat "\\<\\(" fortran-keywords "\\)\\>")
337      ;;
338      ;; Fontify all builtin operators.
339      (concat "\\.\\(" fortran-logicals "\\)\\.")
340      ;;
341      ;; Fontify do/goto keywords and targets, and goto tags.
342      (list "\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?"
343            '(1 font-lock-keyword-face)
344            '(2 font-lock-reference-face nil t))
345      (cons "^ *\\([0-9]+\\)" 'font-lock-reference-face))))
346
347   (setq fortran-font-lock-keywords-3
348    (append
349     ;;
350     ;; The list `fortran-font-lock-keywords-1'.
351     fortran-font-lock-keywords-1
352     ;;
353     ;; Fontify all type specifiers plus their declared items.
354     (list
355      (list (concat "\\<\\(" fortran-type-types "\\)\\>[ \t(/]*\\(*\\)?")
356            ;; Fontify the type specifier.
357            '(1 font-lock-type-face)
358            ;; Fontify each declaration item (or just the /.../ block name).
359            '(font-lock-match-c++-style-declaration-item-and-skip-to-next
360              ;; Start after any *(...) expression.
361              (and (match-beginning 15) (forward-sexp 1))
362              ;; No need to clean up.
363              nil
364              ;; Fontify as a variable name, functions are fontified elsewhere.
365              (1 font-lock-variable-name-face nil t))))
366     ;;
367     ;; Things extra to `fortran-font-lock-keywords-3' (must be done first).
368     (list
369      ;;
370      ;; Fontify goto-like `err=label'/`end=label' in read/write statements.
371      '(", *\\(e\\(nd\\|rr\\)\\)\\> *\\(= *\\([0-9]+\\)\\)?"
372        (1 font-lock-keyword-face) (4 font-lock-reference-face nil t))
373      ;;
374      ;; Highlight standard continuation character and in a TAB-formatted line.
375      '("^     \\([^ 0]\\)" 1 font-lock-string-face)
376      '("^\t\\([1-9]\\)" 1 font-lock-string-face))
377     ;;
378     ;; The list `fortran-font-lock-keywords-2' less that for types (see above).
379     (cdr (nthcdr (length fortran-font-lock-keywords-1)
380                  fortran-font-lock-keywords-2))))
381   )
382
383 (defvar fortran-font-lock-keywords fortran-font-lock-keywords-1
384   "Default expressions to highlight in Fortran mode.")
385
386 ;; XEmacs change
387 (put 'fortran-mode 'font-lock-defaults '((fortran-font-lock-keywords
388                                           fortran-font-lock-keywords-1
389                                           fortran-font-lock-keywords-2
390                                           fortran-font-lock-keywords-3)
391                                          t t ((?/ . "$/"))))
392
393 ;; Our previous version.
394
395 ;(defconst fortran-font-lock-keywords-1
396 ;  (purecopy
397 ;   (list
398 ;    ;; fontify comments
399 ;    '("^[cC*].*$" . font-lock-comment-face)
400 ;    ;;
401 ;    ;; fontify preprocessor directives.
402 ;    '("^#[ \t]*[a-z]+" . font-lock-preprocessor-face)
403 ;    ;;
404 ;    ;; fontify names being defined.
405 ;    '("^#[ \t]*\\(define\\|undef\\)[ \t]+\\(\\(\\sw\\|\\s_\\)+\\)" 2
406 ;      font-lock-function-name-face)
407 ;    ;;
408 ;    ;; fontify other preprocessor lines.
409 ;    '("^#[ \t]*\\(if\\|ifn?def\\|elif\\)[ \t]+\\([^\n]+\\)"
410 ;      2 font-lock-function-name-face t)
411
412 ;    ;; Subroutine and function declarations
413 ;    '("^[ \t]*subroutine.*$" . font-lock-function-name-face)
414 ;    '("^[ \t].*function.*$" . font-lock-function-name-face)
415 ;    '("^[ \t].*program.*$" . font-lock-function-name-face)
416 ;    '("^[ \t].*entry.*$" . font-lock-function-name-face)
417 ;    ))
418 ;  "For consideration as a value of `fortran-font-lock-keywords'.
419 ;This does fairly subdued highlighting of comments and function names.")
420
421 ;(defconst fortran-font-lock-keywords-2
422 ;  (purecopy
423 ;   (append fortran-font-lock-keywords-1
424 ;    (list
425 ;     ;; Variable declarations
426 ;     '("^[ \t]*\\(\\(integer\\|logical\\|real\\|complex\\|double[ \t]*precision\\|character\\|parameter\\)[^ \t]*\\)" 
427 ;       1 font-lock-keyword-face)
428 ;     ;; Common blocks, external, etc
429 ;     '("^[ \t]*\\(common\\|save\\|external\\|intrinsic\\|data\\)" 1 font-lock-keyword-face)
430 ;     ;; Other keywords
431 ;     '("^[ \t]*[0-9]*[ \t]*\\(if\\)[ \t]*("
432 ;       1 font-lock-keyword-face)
433
434 ;     ;; Then
435 ;     ;; '("^\\(\\([ \t]*[0-9]*[ \t]*\\)\\|\\(      [^ ]\\)\\).*[ \t]*\\(then\\)[ \t]*"
436 ;     ;;   4 font-lock-keyword-face)
437 ;     '("\\(then\\)[ \t]*$" 1 font-lock-keyword-face)
438
439 ;     ;; '("^[ \t]*[0-9]*[ \t]*\\(end[ \t]*if\\)[ \t]*$"
440 ;     '("\\(end[ \t]*if\\)[ \t]*$"
441 ;       1 font-lock-keyword-face)      
442 ;     ;; '("\\(else[ \t]*\\(if\\)?\\)"
443 ;     ;; the below works better <mdb@cdc.noaa.gov>
444 ;     '("^[ \t]*[0-9]*[ \t]*\\(else[ \t]*\\(if\\)?\\)"
445 ;       1 font-lock-keyword-face)
446 ;     '("^[ \t]*[0-9]*[ \t]*\\(do\\)[ \t]*[0-9]+"
447 ;       1 font-lock-keyword-face)
448 ;     '("^[ \t]*[0-9]*[ \t]*\\(do\\)[ \t]*[a-z0-9_$]+[ \t]*="
449 ;       1 font-lock-keyword-face)
450 ;     '("^[ \t]*[0-9]*[ \t]*\\(end[ \t]*do\\)"
451 ;       1 font-lock-keyword-face)
452 ;     '("^[ \t]*[0-9]+[ \t]*\\(continue\\)" 1 font-lock-keyword-face)
453 ;     '("^[ \t]*[0-9]*[ \t]*\\(call\\)" 1 font-lock-keyword-face)
454 ;     '("^[ \t]*[0-9]*[ \t]*\\(go[ \t]*to\\)" 1 font-lock-keyword-face)
455
456 ;     '("^[ \t]*[0-9]*[ \t]*\\(open\\|close\\|read\\|write\\|format\\)[ \t]*("
457 ;       1 font-lock-keyword-face)
458 ;     '("^[ \t]*[0-9]*[ \t]*\\(print\\)[ \t]*[*'0-9]+" 1 font-lock-keyword-face)
459
460 ;     '("^[ \t]*[0-9]*[ \t]*\\(end\\|return\\)[ \t]*$" 1 font-lock-keyword-face)
461
462 ;     '("^[ \t]*[0-9]*[ \t]*\\(stop\\)[ \t]*['0-9]*" 1 font-lock-keyword-face)
463
464 ;     ;; Boolean and relational operations, logical true and false
465 ;     '("\\.\\(and\\|or\\|not\\|lt\\|le\\|eq\\|ge\\|gt\\|ne\\|true\\|false\\)\\."
466 ;       . font-lock-keyword-face)
467 ;     )))
468 ;  "For consideration as a value of `fortran-font-lock-keywords'.
469 ;This highlights variable types, \"keywords,\" etc.")
470
471
472 (defvar fortran-mode-map () 
473   "Keymap used in Fortran mode.")
474 (if fortran-mode-map
475     ()
476   (setq fortran-mode-map (make-sparse-keymap))
477   (define-key fortran-mode-map ";" 'fortran-abbrev-start)
478   (define-key fortran-mode-map "\C-c;" 'fortran-comment-region)
479   (define-key fortran-mode-map "\e\C-a" 'beginning-of-fortran-subprogram)
480   (define-key fortran-mode-map "\e\C-e" 'end-of-fortran-subprogram)
481   (define-key fortran-mode-map "\e;" 'fortran-indent-comment)
482   ;; Separate M-BS from C-M-h.  The former should remain
483   ;; backward-kill-word.
484   (define-key fortran-mode-map [(control meta h)] 'mark-fortran-subprogram)
485   (define-key fortran-mode-map "\e\n" 'fortran-split-line)
486   (define-key fortran-mode-map "\n" 'fortran-indent-new-line)
487   (define-key fortran-mode-map "\e\C-q" 'fortran-indent-subprogram)
488   (define-key fortran-mode-map "\C-c\C-w" 'fortran-window-create-momentarily)
489   (define-key fortran-mode-map "\C-c\C-r" 'fortran-column-ruler)
490   (define-key fortran-mode-map "\C-c\C-p" 'fortran-previous-statement)
491   (define-key fortran-mode-map "\C-c\C-n" 'fortran-next-statement)
492   (define-key fortran-mode-map "\C-c\C-d" 'fortran-join-line) ; like f90
493   (define-key fortran-mode-map "\M-^" 'fortran-join-line) ; subvert delete-indentation
494   (define-key fortran-mode-map "\t" 'fortran-indent-line)
495   (define-key fortran-mode-map "0" 'fortran-electric-line-number)
496   (define-key fortran-mode-map "1" 'fortran-electric-line-number)
497   (define-key fortran-mode-map "2" 'fortran-electric-line-number)
498   (define-key fortran-mode-map "3" 'fortran-electric-line-number)
499   (define-key fortran-mode-map "4" 'fortran-electric-line-number)
500   (define-key fortran-mode-map "5" 'fortran-electric-line-number)
501   (define-key fortran-mode-map "6" 'fortran-electric-line-number)
502   (define-key fortran-mode-map "7" 'fortran-electric-line-number)
503   (define-key fortran-mode-map "8" 'fortran-electric-line-number)
504   (define-key fortran-mode-map "9" 'fortran-electric-line-number))
505 \f
506 (defvar fortran-mode-abbrev-table nil)
507 (if fortran-mode-abbrev-table
508     ()
509   (let ((ac abbrevs-changed))
510     (define-abbrev-table 'fortran-mode-abbrev-table ())
511     (define-abbrev fortran-mode-abbrev-table  ";au"  "automatic" nil)
512     (define-abbrev fortran-mode-abbrev-table  ";b"   "byte" nil)
513     (define-abbrev fortran-mode-abbrev-table  ";bd"  "block data" nil)
514     (define-abbrev fortran-mode-abbrev-table  ";ch"  "character" nil)
515     (define-abbrev fortran-mode-abbrev-table  ";cl"  "close" nil)
516     (define-abbrev fortran-mode-abbrev-table  ";c"   "continue" nil)
517     (define-abbrev fortran-mode-abbrev-table  ";cm"  "common" nil)
518     (define-abbrev fortran-mode-abbrev-table  ";cx"  "complex" nil)
519     (define-abbrev fortran-mode-abbrev-table  ";df"  "define" nil)
520     (define-abbrev fortran-mode-abbrev-table  ";di"  "dimension" nil)
521     (define-abbrev fortran-mode-abbrev-table  ";do"  "double" nil)
522     (define-abbrev fortran-mode-abbrev-table  ";dc"  "double complex" nil)
523     (define-abbrev fortran-mode-abbrev-table  ";dp"  "double precision" nil)
524     (define-abbrev fortran-mode-abbrev-table  ";dw"  "do while" nil)
525     (define-abbrev fortran-mode-abbrev-table  ";e"   "else" nil)
526     (define-abbrev fortran-mode-abbrev-table  ";ed"  "enddo" nil)
527     (define-abbrev fortran-mode-abbrev-table  ";el"  "elseif" nil)
528     (define-abbrev fortran-mode-abbrev-table  ";en"  "endif" nil)
529     (define-abbrev fortran-mode-abbrev-table  ";eq"  "equivalence" nil)
530     (define-abbrev fortran-mode-abbrev-table  ";ew"  "endwhere" nil)
531     (define-abbrev fortran-mode-abbrev-table  ";ex"  "external" nil)
532     (define-abbrev fortran-mode-abbrev-table  ";ey"  "entry" nil)
533     (define-abbrev fortran-mode-abbrev-table  ";f"   "format" nil)
534     (define-abbrev fortran-mode-abbrev-table  ";fa"  ".false." nil)
535     (define-abbrev fortran-mode-abbrev-table  ";fu"  "function" nil)
536     (define-abbrev fortran-mode-abbrev-table  ";g"   "goto" nil)
537     (define-abbrev fortran-mode-abbrev-table  ";im"  "implicit" nil)
538     (define-abbrev fortran-mode-abbrev-table  ";ib"  "implicit byte" nil)
539     (define-abbrev fortran-mode-abbrev-table  ";ic"  "implicit complex" nil)
540     (define-abbrev fortran-mode-abbrev-table  ";ich" "implicit character" nil)
541     (define-abbrev fortran-mode-abbrev-table  ";ii"  "implicit integer" nil)
542     (define-abbrev fortran-mode-abbrev-table  ";il"  "implicit logical" nil)
543     (define-abbrev fortran-mode-abbrev-table  ";ir"  "implicit real" nil)
544     (define-abbrev fortran-mode-abbrev-table  ";inc" "include" nil)
545     (define-abbrev fortran-mode-abbrev-table  ";in"  "integer" nil)
546     (define-abbrev fortran-mode-abbrev-table  ";intr" "intrinsic" nil)
547     (define-abbrev fortran-mode-abbrev-table  ";l"   "logical" nil)
548     (define-abbrev fortran-mode-abbrev-table  ";n"   "namelist" nil)
549     (define-abbrev fortran-mode-abbrev-table  ";o"   "open" nil) ; was ;op
550     (define-abbrev fortran-mode-abbrev-table  ";pa"  "parameter" nil)
551     (define-abbrev fortran-mode-abbrev-table  ";pr"  "program" nil)
552     (define-abbrev fortran-mode-abbrev-table  ";ps"  "pause" nil)
553     (define-abbrev fortran-mode-abbrev-table  ";p"   "print" nil)
554     (define-abbrev fortran-mode-abbrev-table  ";rc"  "record" nil)
555     (define-abbrev fortran-mode-abbrev-table  ";re"  "real" nil)
556     (define-abbrev fortran-mode-abbrev-table  ";r"   "read" nil)
557     (define-abbrev fortran-mode-abbrev-table  ";rt"  "return" nil)
558     (define-abbrev fortran-mode-abbrev-table  ";rw"  "rewind" nil)
559     (define-abbrev fortran-mode-abbrev-table  ";s"   "stop" nil)
560     (define-abbrev fortran-mode-abbrev-table  ";sa"  "save" nil)
561     (define-abbrev fortran-mode-abbrev-table  ";st"  "structure" nil)
562     (define-abbrev fortran-mode-abbrev-table  ";sc"  "static" nil)
563     (define-abbrev fortran-mode-abbrev-table  ";su"  "subroutine" nil)
564     (define-abbrev fortran-mode-abbrev-table  ";tr"  ".true." nil)
565     (define-abbrev fortran-mode-abbrev-table  ";ty"  "type" nil)
566     (define-abbrev fortran-mode-abbrev-table  ";vo"  "volatile" nil)
567     (define-abbrev fortran-mode-abbrev-table  ";w"   "write" nil)
568     (define-abbrev fortran-mode-abbrev-table  ";wh"  "where" nil)
569     (setq abbrevs-changed ac)))
570 \f
571 ;;;###autoload
572 (defun fortran-mode ()
573   "Major mode for editing Fortran code.
574 \\[fortran-indent-line] indents the current Fortran line correctly. 
575 DO statements must not share a common CONTINUE.
576
577 Type ;? or ;\\[help-command] to display a list of built-in\
578  abbrevs for Fortran keywords.
579
580 Key definitions:
581 \\{fortran-mode-map}
582
583 Variables controlling indentation style and extra features:
584
585  comment-start
586     Normally nil in Fortran mode.  If you want to use comments
587     starting with `!', set this to the string \"!\".
588  fortran-do-indent
589     Extra indentation within do blocks.  (default 3)
590  fortran-if-indent
591     Extra indentation within if blocks.  (default 3)
592  fortran-structure-indent
593     Extra indentation within structure, union, map and interface blocks.
594     (default 3)
595  fortran-continuation-indent
596     Extra indentation applied to continuation statements.  (default 5)
597  fortran-comment-line-extra-indent
598     Amount of extra indentation for text within full-line comments. (default 0)
599  fortran-comment-indent-style
600     nil    means don't change indentation of text in full-line comments,
601     fixed  means indent that text at `fortran-comment-line-extra-indent' beyond
602            the value of `fortran-minimum-statement-indent-fixed' (for fixed
603            format continuation style) or `fortran-minimum-statement-indent-tab'
604            (for TAB format continuation style).
605     relative  means indent at `fortran-comment-line-extra-indent' beyond the
606               indentation for a line of code.
607     (default 'fixed)
608  fortran-comment-indent-char
609     Single-character string to be inserted instead of space for
610     full-line comment indentation.  (default \" \")
611  fortran-minimum-statement-indent-fixed
612     Minimum indentation for Fortran statements in fixed format mode. (def.6)
613  fortran-minimum-statement-indent-tab
614     Minimum indentation for Fortran statements in TAB format mode. (default 9)
615  fortran-line-number-indent
616     Maximum indentation for line numbers.  A line number will get
617     less than this much indentation if necessary to avoid reaching
618     column 5.  (default 1)
619  fortran-check-all-num-for-matching-do
620     Non-nil causes all numbered lines to be treated as possible \"continue\"
621     statements.  (default nil)
622  fortran-blink-matching-if 
623     Non-nil causes \\[fortran-indent-line] on an ENDIF statement to blink on
624     matching IF.  Also, from an ENDDO statement, blink on matching DO [WHILE]
625     statement.  (default nil)
626  fortran-continuation-string
627     Single-character string to be inserted in column 5 of a continuation
628     line.  (default \"$\")
629  fortran-comment-region
630     String inserted by \\[fortran-comment-region] at start of each line in 
631     region.  (default \"c$$$\")
632  fortran-electric-line-number
633     Non-nil causes line number digits to be moved to the correct column 
634     as typed.  (default t)
635  fortran-break-before-delimiters
636     Non-nil causes `fortran-fill' breaks lines before delimiters.
637     (default t)
638  fortran-startup-message
639     Set to nil to inhibit message first time Fortran mode is used.
640
641 Turning on Fortran mode calls the value of the variable `fortran-mode-hook'
642 with no args, if that value is non-nil."
643   (interactive)
644   (kill-all-local-variables)
645   (if fortran-startup-message
646       (message "Emacs Fortran mode %s.  Bugs to %s"
647                fortran-mode-version bug-fortran-mode))
648   (setq fortran-startup-message nil)
649   (setq local-abbrev-table fortran-mode-abbrev-table)
650   (set-syntax-table fortran-mode-syntax-table)
651   ;; Font Lock mode support. (Removed for XEmacs)
652   ;; (make-local-variable 'font-lock-defaults)
653   ;; (setq font-lock-defaults '((fortran-font-lock-keywords
654                               ;; fortran-font-lock-keywords-1
655                               ;; fortran-font-lock-keywords-2
656                               ;; fortran-font-lock-keywords-3)
657                              ;; t t ((?/ . "$/"))))
658   (make-local-variable 'fortran-break-before-delimiters)
659   (setq fortran-break-before-delimiters t)
660   (make-local-variable 'indent-line-function)
661   (setq indent-line-function 'fortran-indent-line)
662   (make-local-variable 'comment-indent-function)
663   (setq comment-indent-function 'fortran-comment-hook)
664   (make-local-variable 'fortran-comment-line-start-skip)
665   (setq fortran-comment-line-start-skip
666         "^[Cc*]\\(\\([^ \t\n]\\)\\2\\2*\\)?[ \t]*\\|^#.*")
667   (make-local-variable 'fortran-comment-line-start)
668   (setq fortran-comment-line-start "c")
669   (make-local-variable 'fortran-comment-start-skip)
670   (setq comment-start-skip "![ \t]*")
671   (make-local-variable 'comment-start)
672   (setq comment-start nil)
673   (make-local-variable 'require-final-newline)
674   (setq require-final-newline t)
675   (make-local-variable 'abbrev-all-caps)
676   (setq abbrev-all-caps t)
677   (make-local-variable 'indent-tabs-mode)
678   (setq indent-tabs-mode nil)
679 ;;;(setq abbrev-mode t) ; ?? (abbrev-mode 1) instead??
680   (setq fill-column 72) ; Already local?
681   (use-local-map fortran-mode-map)
682   (setq mode-name "Fortran")
683   (setq major-mode 'fortran-mode)
684 ;;;(make-local-variable 'fortran-tab-mode)
685   (make-local-variable 'fortran-comment-line-extra-indent)
686   (make-local-variable 'fortran-minimum-statement-indent-fixed)
687   (make-local-variable 'fortran-minimum-statement-indent-tab)
688   (make-local-variable 'fortran-column-ruler-fixed)
689   (make-local-variable 'fortran-column-ruler-tab)
690   (make-local-variable 'fortran-tab-mode-string)
691   (setq fortran-tab-mode-string " TAB-format")
692   (setq indent-tabs-mode (fortran-analyze-file-format))
693   (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
694   (set (make-local-variable 'normal-auto-fill-function) 'fortran-auto-fill)
695   (run-hooks 'fortran-mode-hook))
696 \f
697 (defun fortran-comment-hook ()
698   (save-excursion
699     (skip-chars-backward " \t")
700     (max (+ 1 (current-column))
701          comment-column)))
702
703 (defun fortran-indent-comment ()
704   "Align or create comment on current line.
705 Existing comments of all types are recognized and aligned.
706 If the line has no comment, a side-by-side comment is inserted and aligned
707 if the value of  comment-start  is not nil.
708 Otherwise, a separate-line comment is inserted, on this line
709 or on a new line inserted before this line if this line is not blank."
710   (interactive)
711   (beginning-of-line)
712   ;; Recognize existing comments of either kind.
713   (cond ((looking-at fortran-comment-line-start-skip)
714          (fortran-indent-line))
715         ((fortran-find-comment-start-skip) ; catches any inline comment and
716                                         ; leaves point after comment-start-skip
717          (if comment-start-skip
718              (progn (goto-char (match-beginning 0))
719                     (if (not (= (current-column) (fortran-comment-hook)))
720                         (progn (delete-horizontal-space)
721                                (indent-to (fortran-comment-hook)))))
722            (end-of-line)))        ; otherwise goto end of line or sth else?
723         ;; No existing comment.
724         ;; If side-by-side comments are defined, insert one,
725         ;; unless line is now blank.
726         ((and comment-start (not (looking-at "^[ \t]*$")))
727          (end-of-line)
728          (delete-horizontal-space)
729          (indent-to (fortran-comment-hook))
730          (insert comment-start))
731         ;; Else insert separate-line comment, making a new line if nec.
732         (t
733          (if (looking-at "^[ \t]*$")
734              (delete-horizontal-space)
735            (beginning-of-line)
736            (insert "\n")
737            (forward-char -1))
738          (insert fortran-comment-line-start)
739          (insert-char (if (stringp fortran-comment-indent-char)
740                           (aref fortran-comment-indent-char 0)
741                         fortran-comment-indent-char)
742                       (- (calculate-fortran-indent) (current-column))))))
743
744 (defun fortran-comment-region (beg-region end-region arg)
745   "Comments every line in the region.
746 Puts fortran-comment-region at the beginning of every line in the region. 
747 BEG-REGION and END-REGION are args which specify the region boundaries. 
748 With non-nil ARG, uncomments the region."
749   (interactive "*r\nP")
750   (let ((end-region-mark (make-marker)) (save-point (point-marker)))
751     (set-marker end-region-mark end-region)
752     (goto-char beg-region)
753     (beginning-of-line)
754     (if (not arg)                       ;comment the region
755         (progn (insert fortran-comment-region)
756                (while (and  (= (forward-line 1) 0)
757                             (< (point) end-region-mark))
758                  (insert fortran-comment-region)))
759       (let ((com (regexp-quote fortran-comment-region))) ;uncomment the region
760         (if (looking-at com)
761             (delete-region (point) (match-end 0)))
762         (while (and  (= (forward-line 1) 0)
763                      (< (point) end-region-mark))
764           (if (looking-at com)
765               (delete-region (point) (match-end 0))))))
766     (goto-char save-point)
767     (set-marker end-region-mark nil)
768     (set-marker save-point nil)))
769 \f
770 (defun fortran-abbrev-start ()
771   "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs. 
772 Any other key combination is executed normally."
773   (interactive)
774   ;; XEmacs change
775   (let (e c)
776     (insert last-command-char)
777     (setq e (next-command-event)
778           c (event-to-character e))
779     ;; insert char if not equal to `?'
780     (if (or (= c ??) (eq c help-char))
781         (fortran-abbrev-help)
782       (setq unread-command-events (list e)))))
783
784 (defun fortran-abbrev-help ()
785   "List the currently defined abbrevs in Fortran mode."
786   (interactive)
787   (message "Listing abbrev table...")
788   (display-buffer (fortran-prepare-abbrev-list-buffer))
789   (message "Listing abbrev table...done"))
790
791 (defun fortran-prepare-abbrev-list-buffer ()
792   (save-excursion
793     (set-buffer (get-buffer-create "*Abbrevs*"))
794     (erase-buffer)
795     (insert-abbrev-table-description 'fortran-mode-abbrev-table t)
796     (goto-char (point-min))
797     (set-buffer-modified-p nil)
798     (edit-abbrevs-mode))
799   (get-buffer-create "*Abbrevs*"))
800
801 (defun fortran-column-ruler ()
802   "Inserts a column ruler momentarily above current line, till next keystroke.
803 The ruler is defined by the value of `fortran-column-ruler-fixed' when in fixed
804 format mode, and `fortran-column-ruler-tab' when in TAB format mode.
805 The key typed is executed unless it is SPC."
806   (interactive)
807   (momentary-string-display 
808    (if indent-tabs-mode
809        fortran-column-ruler-tab
810      fortran-column-ruler-fixed)
811    (save-excursion
812      (beginning-of-line) 
813      (if (eq (window-start (selected-window))
814              (window-point (selected-window)))
815          (progn (forward-line) (point))
816        (point)))
817    nil "Type SPC or any command to erase ruler."))
818
819 (defun fortran-window-create ()
820   "Makes the window 72 columns wide.
821 See also `fortran-window-create-momentarily'."
822   (interactive)
823   (condition-case error
824       (progn
825         (let ((window-min-width 2))
826           (if (< (window-width) (frame-width))
827               (enlarge-window-horizontally (- (frame-width)
828                                               (window-width) 1)))
829           (split-window-horizontally 73)
830           (other-window 1)
831           (switch-to-buffer " fortran-window-extra" t)
832           (select-window (previous-window))))
833     (error (message "No room for Fortran window.")
834            'error)))
835
836 (defun fortran-window-create-momentarily (&optional arg)
837   "Momentarily makes the window 72 columns wide.
838 Optional ARG non-nil and non-unity disables the momentary feature.
839 See also `fortran-window-create'."
840   (interactive "p")
841   (if (or (not arg)
842           (= arg 1))
843       (save-window-excursion
844         (if (not (equal (fortran-window-create) 'error))
845             (progn (message "Type SPC to continue editing.")
846                    ;; XEmacs change
847                    (let ((char (next-command-event)))
848                      (or (equal (event-to-character char) ? )
849                          (setq unread-command-events (list char)))))))
850     (fortran-window-create)))
851
852 (defun fortran-split-line ()
853   "Break line at point and insert continuation marker and alignment."
854   (interactive)
855   (delete-horizontal-space)
856   (if (save-excursion (beginning-of-line) (looking-at fortran-comment-line-start-skip))
857       (insert "\n" fortran-comment-line-start " ")
858     (if indent-tabs-mode
859         (progn 
860           (insert "\n\t")
861           (insert-char (fortran-numerical-continuation-char) 1))
862       (insert "\n " fortran-continuation-string)));Space after \n important
863   (fortran-indent-line))                ;when the cont string is C, c or *.
864
865 (defun fortran-numerical-continuation-char ()
866   "Return a digit for tab-digit style of continuation lines.
867 If, previous line is a tab-digit continuation line, returns that digit
868 plus one.  Otherwise return 1.  Zero not allowed."
869   (save-excursion
870     (forward-line -1)
871     (if (looking-at "\t[1-9]")
872         (+ ?1 (% (- (char-after (+ (point) 1)) ?0) 9))
873       ?1)))
874
875 (defun delete-horizontal-regexp (chars)
876   "Delete all characters in CHARS around point.
877 CHARS is like the inside of a [...] in a regular expression
878 except that ] is never special and \ quotes ^, - or \."
879   (interactive "*s")
880   (skip-chars-backward chars)
881   (delete-region (point) (progn (skip-chars-forward chars) (point))))
882
883 (defun fortran-electric-line-number (arg)
884   "Self insert, but if part of a Fortran line number indent it automatically.
885 Auto-indent does not happen if a numeric arg is used."
886   (interactive "P")
887   (if (or arg (not fortran-electric-line-number))
888       (if arg 
889           (self-insert-command (prefix-numeric-value arg))
890         (self-insert-command 1))
891     (if (or (and (= 5 (current-column))
892                  (save-excursion
893                    (beginning-of-line)
894                    (looking-at "     ")));In col 5 with only spaces to left.
895             (and (= (if indent-tabs-mode
896                   fortran-minimum-statement-indent-tab
897                 fortran-minimum-statement-indent-fixed) (current-column))
898                  (save-excursion
899                    (beginning-of-line)
900                    (looking-at "\t"));In col 8 with a single tab to the left.
901                  (not (or (eq last-command 'fortran-indent-line)
902                           (eq last-command
903                               'fortran-indent-new-line))))
904             (save-excursion
905               (re-search-backward "[^ \t0-9]"
906                                   (save-excursion
907                                     (beginning-of-line)
908                                     (point))
909                                   t)) ;not a line number
910             (looking-at "[0-9]")        ;within a line number
911             )
912         (self-insert-command (prefix-numeric-value arg))
913       (skip-chars-backward " \t")
914       (insert last-command-char)
915       (fortran-indent-line))))
916 \f
917 (defun beginning-of-fortran-subprogram ()
918   "Moves point to the beginning of the current Fortran subprogram."
919   (interactive)
920   (let ((case-fold-search t))
921     (beginning-of-line -1)
922     (re-search-backward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
923     (if (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")
924         (forward-line 1))))
925
926 (defun end-of-fortran-subprogram ()
927   "Moves point to the end of the current Fortran subprogram."
928   (interactive)
929   (let ((case-fold-search t))
930     (beginning-of-line 2)
931     (re-search-forward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
932     (goto-char (match-beginning 0))
933     (forward-line 1)))
934
935 (defun mark-fortran-subprogram ()
936   "Put mark at end of Fortran subprogram, point at beginning. 
937 The marks are pushed."
938   (interactive)
939   (end-of-fortran-subprogram)
940   (push-mark (point))
941   (beginning-of-fortran-subprogram))
942
943 (defun fortran-previous-statement ()
944   "Moves point to beginning of the previous Fortran statement.
945 Returns `first-statement' if that statement is the first
946 non-comment Fortran statement in the file, and nil otherwise."
947   (interactive)
948   (let (not-first-statement continue-test)
949     (beginning-of-line)
950     (setq continue-test
951           (and
952            (not (looking-at fortran-comment-line-start-skip))
953            (or (looking-at
954                 (concat "[ \t]*" (regexp-quote fortran-continuation-string)))
955                (or (looking-at "     [^ 0\n]")
956                    (looking-at "\t[1-9]")))))
957     (while (and (setq not-first-statement (= (forward-line -1) 0))
958                 (or (looking-at fortran-comment-line-start-skip)
959                     (looking-at "[ \t]*$")
960                     (looking-at "     [^ 0\n]")
961                     (looking-at "\t[1-9]")
962                     (looking-at (concat "[ \t]*"  comment-start-skip)))))
963     (cond ((and continue-test
964                 (not not-first-statement))
965            (message "Incomplete continuation statement."))
966           (continue-test        
967            (fortran-previous-statement))
968           ((not not-first-statement)
969            'first-statement))))
970
971 (defun fortran-next-statement ()
972   "Moves point to beginning of the next Fortran statement.
973 Returns `last-statement' if that statement is the last
974 non-comment Fortran statement in the file, and nil otherwise."
975   (interactive)
976   (let (not-last-statement)
977     (beginning-of-line)
978     (while (and (setq not-last-statement
979                       (and (= (forward-line 1) 0)
980                            (not (eobp))))
981                 (or (looking-at fortran-comment-line-start-skip)
982                     (looking-at "[ \t]*$")
983                     (looking-at "     [^ 0\n]")
984                     (looking-at "\t[1-9]")
985                     (looking-at (concat "[ \t]*"  comment-start-skip)))))
986     (if (not not-last-statement)
987         'last-statement)))
988 \f
989 (defun fortran-blink-matching-if ()
990   ;; From a Fortran ENDIF statement, blink the matching IF statement.
991   (let ((top-of-window (window-start)) matching-if
992         (endif-point (point)) message)
993     (if (save-excursion (beginning-of-line)
994                         (skip-chars-forward " \t0-9")
995                         (looking-at "end[ \t]*if\\b"))
996         (progn
997           (if (not (setq matching-if (fortran-beginning-if)))
998               (setq message "No matching if.")
999             (if (< matching-if top-of-window)
1000                 (save-excursion
1001                   (goto-char matching-if)
1002                   (beginning-of-line)
1003                   (setq message
1004                         (concat "Matches "
1005                                 (buffer-substring
1006                                  (point) (progn (end-of-line) (point))))))))
1007           (if message
1008               (message "%s" message)
1009             (goto-char matching-if)
1010             (sit-for 1)
1011             (goto-char endif-point))))))
1012
1013 (defun fortran-blink-matching-do ()
1014   ;; From a Fortran ENDDO statement, blink on the matching DO or DO WHILE
1015   ;; statement.  This is basically copied from fortran-blink-matching-if.
1016   (let ((top-of-window (window-start)) matching-do
1017         (enddo-point (point)) message)
1018     (if (save-excursion (beginning-of-line)
1019                         (skip-chars-forward " \t0-9")
1020                         (looking-at "end[ \t]*do\\b"))
1021         (progn
1022           (if (not (setq matching-do (fortran-beginning-do)))
1023               (setq message "No matching do.")
1024             (if (< matching-do top-of-window)
1025                 (save-excursion
1026                   (goto-char matching-do)
1027                   (beginning-of-line)
1028                   (setq message
1029                         (concat "Matches "
1030                                 (buffer-substring
1031                                  (point) (progn (end-of-line) (point))))))))
1032           (if message
1033               (message "%s" message)
1034             (goto-char matching-do)
1035             (sit-for 1)
1036             (goto-char enddo-point))))))
1037
1038 (defun fortran-mark-do ()
1039   "Put mark at end of Fortran DO [WHILE]-ENDDO construct, point at beginning. 
1040 The marks are pushed."
1041   (interactive)
1042   (let (enddo-point do-point)
1043     (if (setq enddo-point (fortran-end-do))
1044         (if (not (setq do-point (fortran-beginning-do)))
1045             (message "No matching do.")
1046           ;; Set mark, move point.
1047           (goto-char enddo-point)
1048           (push-mark)
1049           (goto-char do-point)))))
1050
1051 (defun fortran-end-do ()
1052   ;; Search forward for first unmatched ENDDO.  Return point or nil.
1053   (if (save-excursion (beginning-of-line)
1054                       (skip-chars-forward " \t0-9")
1055                       (looking-at "end[ \t]*do\\b"))
1056       ;; Sitting on one.
1057       (match-beginning 0)
1058     ;; Search for one.
1059     (save-excursion
1060       (let ((count 1))
1061         (while (and (not (= count 0))
1062                     (not (eq (fortran-next-statement) 'last-statement))
1063                     ;; Keep local to subprogram
1064                     (not (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")))
1065
1066           (skip-chars-forward " \t0-9")
1067           (cond ((looking-at "end[ \t]*do\\b")
1068                  (setq count (- count 1)))
1069                 ((looking-at "do[ \t]+[^0-9]")
1070                  (setq count (+ count 1)))))
1071         (and (= count 0)
1072              ;; All pairs accounted for.
1073              (point))))))
1074
1075 (defun fortran-beginning-do ()
1076   ;; Search backwards for first unmatched DO [WHILE].  Return point or nil.
1077   (if (save-excursion (beginning-of-line)
1078                       (skip-chars-forward " \t0-9")
1079                       (looking-at "do[ \t]+"))
1080       ;; Sitting on one.
1081       (match-beginning 0)
1082     ;; Search for one.
1083     (save-excursion
1084       (let ((count 1))
1085         (while (and (not (= count 0))
1086                     (not (eq (fortran-previous-statement) 'first-statement))
1087                     ;; Keep local to subprogram
1088                     (not (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")))
1089
1090           (skip-chars-forward " \t0-9")
1091           (cond ((looking-at "do[ \t]+[^0-9]")
1092                  (setq count (- count 1)))
1093                 ((looking-at "end[ \t]*do\\b")
1094                  (setq count (+ count 1)))))
1095
1096         (and (= count 0)
1097              ;; All pairs accounted for.
1098              (point))))))
1099
1100 (defun fortran-mark-if ()
1101   "Put mark at end of Fortran IF-ENDIF construct, point at beginning.
1102 The marks are pushed."
1103   (interactive)
1104   (let (endif-point if-point)
1105     (if (setq endif-point (fortran-end-if))
1106         (if (not (setq if-point (fortran-beginning-if)))
1107             (message "No matching if.")
1108           ;; Set mark, move point.
1109           (goto-char endif-point)
1110           (push-mark)
1111           (goto-char if-point)))))
1112
1113 (defun fortran-end-if ()
1114   ;; Search forwards for first unmatched ENDIF.  Return point or nil.
1115   (if (save-excursion (beginning-of-line)
1116                       (skip-chars-forward " \t0-9")
1117                       (looking-at "end[ \t]*if\\b"))
1118       ;; Sitting on one.
1119       (match-beginning 0)
1120     ;; Search for one.  The point has been already been moved to first
1121     ;; letter on line but this should not cause troubles.
1122     (save-excursion
1123       (let ((count 1))
1124         (while (and (not (= count 0))
1125                     (not (eq (fortran-next-statement) 'last-statement))
1126                     ;; Keep local to subprogram.
1127                     (not (looking-at
1128                           "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")))
1129
1130           (skip-chars-forward " \t0-9")
1131           (cond ((looking-at "end[ \t]*if\\b")
1132                  (setq count (- count 1)))
1133
1134                 ((looking-at "if[ \t]*(")
1135                  (save-excursion
1136                    (if (or
1137                         (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
1138                         (let (then-test) ; Multi-line if-then.
1139                           (while
1140                               (and (= (forward-line 1) 0)
1141                                    ;; Search forward for then.
1142                                    (or (looking-at "     [^ 0\n]")
1143                                        (looking-at "\t[1-9]"))
1144                                    (not
1145                                     (setq then-test
1146                                           (looking-at
1147                                            ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
1148                           then-test))
1149                        (setq count (+ count 1)))))))
1150
1151         (and (= count 0)
1152              ;; All pairs accounted for.
1153              (point))))))
1154
1155 (defun fortran-beginning-if ()
1156   ;; Search backwards for first unmatched IF-THEN.  Return point or nil.
1157   (if (save-excursion
1158         ;; May be sitting on multi-line if-then statement, first move to
1159         ;; beginning of current statement.  Note: `fortran-previous-statement'
1160         ;; moves to previous statement *unless* current statement is first
1161         ;; one.  Only move forward if not first-statement.
1162         (if (not (eq (fortran-previous-statement) 'first-statement))
1163             (fortran-next-statement))
1164         (skip-chars-forward " \t0-9")
1165         (and
1166          (looking-at "if[ \t]*(")
1167          (save-match-data
1168            (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
1169                ;; Multi-line if-then.
1170                (let (then-test)
1171                  (while
1172                      (and (= (forward-line 1) 0)
1173                           ;; Search forward for then.
1174                           (or (looking-at "     [^ 0\n]")
1175                               (looking-at "\t[1-9]"))
1176                           (not
1177                            (setq then-test
1178                                  (looking-at
1179                                   ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
1180                  then-test)))))
1181       ;; Sitting on one.
1182       (match-beginning 0)
1183     ;; Search for one.
1184     (save-excursion
1185       (let ((count 1))
1186         (while (and (not (= count 0))
1187                     (not (eq (fortran-previous-statement) 'first-statement))
1188                     ;; Keep local to subprogram.
1189                     (not (looking-at
1190                           "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")))
1191
1192           (skip-chars-forward " \t0-9")
1193           (cond ((looking-at "if[ \t]*(")
1194                  (save-excursion
1195                    (if (or
1196                         (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
1197                         (let (then-test) ; Multi-line if-then.
1198                           (while
1199                               (and (= (forward-line 1) 0)
1200                                    ;; Search forward for then.
1201                                    (or (looking-at "     [^ 0\n]")
1202                                        (looking-at "\t[1-9]"))
1203                                    (not
1204                                     (setq then-test
1205                                           (looking-at
1206                                            ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
1207                           then-test))
1208                        (setq count (- count 1)))))
1209                 ((looking-at "end[ \t]*if\\b")
1210                  (setq count (+ count 1)))))
1211
1212         (and (= count 0)
1213              ;; All pairs accounted for.
1214              (point))))))
1215 \f
1216 (defun fortran-indent-line ()
1217   "Indents current Fortran line based on its contents and on previous lines."
1218   (interactive)
1219   (let ((cfi (calculate-fortran-indent)))
1220     (save-excursion
1221       (beginning-of-line)
1222       (if (or (not (= cfi (fortran-current-line-indentation)))
1223               (and (re-search-forward "^[ \t]*[0-9]+" (+ (point) 4) t)
1224                    (not (fortran-line-number-indented-correctly-p))))
1225           (fortran-indent-to-column cfi)
1226         (beginning-of-line)
1227         (if (and (not (looking-at fortran-comment-line-start-skip))
1228                  (fortran-find-comment-start-skip))
1229             (fortran-indent-comment))))
1230     ;; Never leave point in left margin.
1231     (if (< (current-column) cfi)
1232         (move-to-column cfi))
1233     (if (and auto-fill-function
1234              (> (save-excursion (end-of-line) (current-column)) fill-column))
1235         (save-excursion
1236           (end-of-line)
1237           (fortran-fill)))
1238     (if fortran-blink-matching-if
1239         (progn
1240           (fortran-blink-matching-if)
1241           (fortran-blink-matching-do)))))
1242
1243 (defun fortran-indent-new-line ()
1244   "Reindent the current Fortran line, insert a newline and indent the newline.
1245 An abbrev before point is expanded if `abbrev-mode' is non-nil."
1246   (interactive)
1247   (if abbrev-mode (expand-abbrev))
1248   (save-excursion
1249     (beginning-of-line)
1250     (skip-chars-forward " \t")
1251     (if (or (looking-at "[0-9]")        ;Reindent only where it is most
1252             (looking-at "end")          ;likely to be necessary
1253             (looking-at "else")
1254             (looking-at (regexp-quote fortran-continuation-string)))
1255         (fortran-indent-line)))
1256   (newline)
1257   (fortran-indent-line))
1258
1259 (defun fortran-indent-subprogram ()
1260   "Properly indents the Fortran subprogram which contains point."
1261   (interactive)
1262   (save-excursion
1263     (mark-fortran-subprogram)
1264     (message "Indenting subprogram...")
1265     (indent-region (point) (mark t) nil)) ; XEmacs change
1266   (message "Indenting subprogram...done."))
1267
1268 (defun calculate-fortran-indent ()
1269   "Calculates the Fortran indent column based on previous lines."
1270   (let (icol first-statement (case-fold-search t)
1271              (fortran-minimum-statement-indent
1272               (if indent-tabs-mode
1273                   fortran-minimum-statement-indent-tab
1274                 fortran-minimum-statement-indent-fixed)))
1275     (save-excursion
1276       (setq first-statement (fortran-previous-statement))
1277       (if first-statement
1278           (setq icol fortran-minimum-statement-indent)
1279         (progn
1280           (if (= (point) (point-min))
1281               (setq icol fortran-minimum-statement-indent)
1282             (setq icol (fortran-current-line-indentation)))
1283           (skip-chars-forward " \t0-9")
1284           (cond ((looking-at "if[ \t]*(")
1285                  (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t_$(=a-z0-9]")
1286                          (let (then-test)       ;multi-line if-then
1287                            (while (and (= (forward-line 1) 0)
1288                                        ;;search forward for then
1289                                        (or (looking-at "     [^ 0\n]")
1290                                            (looking-at "\t[1-9]"))
1291                                        (not (setq then-test (looking-at
1292                                                              ".*then\\b[ \t]\
1293 *[^ \t_$(=a-z0-9]")))))
1294                            then-test))
1295                      (setq icol (+ icol fortran-if-indent))))
1296                 ((looking-at "\\(else\\|elseif\\)\\b")
1297                  (setq icol (+ icol fortran-if-indent)))
1298                 ((looking-at "select[ \t]*case[ \t](.*)\\b")
1299                  (setq icol (+ icol fortran-if-indent)))
1300                 ((looking-at "case[ \t]*(.*)[ \t]*\n")
1301                  (setq icol (+ icol fortran-if-indent)))
1302                 ((looking-at "case[ \t]*default\\b")
1303                  (setq icol (+ icol fortran-if-indent)))
1304                 ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
1305                  (setq icol (+ icol fortran-if-indent)))
1306                 ((looking-at "where[ \t]*(.*)[ \t]*\n")
1307                  (setq icol (+ icol fortran-if-indent)))
1308                 ((looking-at "do\\b")
1309                  (setq icol (+ icol fortran-do-indent)))
1310                 ((looking-at
1311                   "\\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]")
1312                  (setq icol (+ icol fortran-structure-indent)))
1313                 ((looking-at "end\\b[ \t]*[^ \t=(a-z]")
1314                  ;; Previous END resets indent to minimum
1315                  (setq icol fortran-minimum-statement-indent))))))
1316     (save-excursion
1317       (beginning-of-line)
1318       (cond ((looking-at "[ \t]*$"))
1319             ((looking-at fortran-comment-line-start-skip)
1320              (cond ((eq fortran-comment-indent-style 'relative)
1321                     (setq icol (+ icol fortran-comment-line-extra-indent)))
1322                    ((eq fortran-comment-indent-style 'fixed)
1323                     (setq icol (+ fortran-minimum-statement-indent
1324                                   fortran-comment-line-extra-indent))))
1325              (setq fortran-minimum-statement-indent 0))
1326             ((or (looking-at (concat "[ \t]*"
1327                                      (regexp-quote
1328                                       fortran-continuation-string)))
1329                  (looking-at "     [^ 0\n]")
1330                  (looking-at "\t[1-9]"))
1331              (setq icol (+ icol fortran-continuation-indent)))
1332             ((looking-at "[ \t]*#")     ; Check for cpp directive.
1333              (setq fortran-minimum-statement-indent 0 icol 0))
1334             (first-statement)
1335             ((and fortran-check-all-num-for-matching-do
1336                   (looking-at "[ \t]*[0-9]+")
1337                   (fortran-check-for-matching-do))
1338              (setq icol (- icol fortran-do-indent)))
1339             (t
1340              (skip-chars-forward " \t0-9")
1341              (cond ((looking-at "end[ \t]*if\\b")
1342                     (setq icol (- icol fortran-if-indent)))
1343                    ((looking-at "\\(else\\|elseif\\)\\b")
1344                     (setq icol (- icol fortran-if-indent)))
1345                    ((looking-at "case[ \t]*(.*)[ \t]*\n")
1346                     (setq icol (- icol fortran-if-indent)))
1347                    ((looking-at "case[ \t]*default\\b")
1348                     (setq icol (- icol fortran-if-indent)))
1349                    ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
1350                     (setq icol (- icol fortran-if-indent)))
1351                    ((looking-at "end[ \t]*where\\b")
1352                     (setq icol (- icol fortran-if-indent)))
1353                    ((and (looking-at "continue\\b")
1354                          (fortran-check-for-matching-do))
1355                     (setq icol (- icol fortran-do-indent)))
1356                    ((looking-at "end[ \t]*do\\b")
1357                     (setq icol (- icol fortran-do-indent)))
1358                    ((looking-at
1359                      "end[ \t]*\
1360 \\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]")
1361                     (setq icol (- icol fortran-structure-indent)))
1362                    ((looking-at
1363                      "end[ \t]*select\\b[ \t]*[^ \t=(a-z]")
1364                     (setq icol (- icol fortran-if-indent)))
1365                    ((and (looking-at "end\\b[ \t]*[^ \t=(a-z]")
1366                          (not (= icol fortran-minimum-statement-indent)))
1367                     (message "Warning: `end' not in column %d.  Probably\
1368  an unclosed block." fortran-minimum-statement-indent))))))
1369     (max fortran-minimum-statement-indent icol)))
1370 \f
1371 (defun fortran-current-line-indentation ()
1372   "Indentation of current line, ignoring Fortran line number or continuation.
1373 This is the column position of the first non-whitespace character
1374 aside from the line number and/or column 5/8 line-continuation character.
1375 For comment lines, returns indentation of the first
1376 non-indentation text within the comment."
1377   (save-excursion
1378     (beginning-of-line)
1379     (cond ((looking-at fortran-comment-line-start-skip)
1380            (goto-char (match-end 0))
1381            (skip-chars-forward
1382             (if (stringp fortran-comment-indent-char)
1383                 fortran-comment-indent-char
1384               (char-to-string fortran-comment-indent-char))))
1385           ((or (looking-at "     [^ 0\n]")
1386                (looking-at "\t[1-9]"))
1387            (goto-char (match-end 0)))
1388           (t
1389            ;; Move past line number.
1390            (skip-chars-forward "[ \t0-9]");From Uli
1391            ))
1392     ;; Move past whitespace.
1393     (skip-chars-forward " \t")
1394     (current-column)))
1395
1396 (defun fortran-indent-to-column (col)
1397   "Indents current line with spaces to column COL.
1398 notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
1399           line, and this continuation character is retained on indentation;
1400        2) If `fortran-continuation-string' is the first non-whitespace
1401           character, this is a continuation line;
1402        3) A non-continuation line which has a number as the first
1403           non-whitespace character is a numbered line.
1404        4) A TAB followed by a digit indicates a continuation line."
1405   (save-excursion
1406     (beginning-of-line)
1407     (if (looking-at fortran-comment-line-start-skip)
1408         (if fortran-comment-indent-style
1409             (let ((char (if (stringp fortran-comment-indent-char)
1410                             (aref fortran-comment-indent-char 0)
1411                           fortran-comment-indent-char)))
1412               (goto-char (match-end 0))
1413               (delete-horizontal-regexp (concat " \t" (char-to-string char)))
1414               (insert-char char (- col (current-column)))))
1415       (if (looking-at "\t[1-9]")
1416           (if indent-tabs-mode
1417               (goto-char (match-end 0))
1418             (delete-char 2)
1419             (insert "     ")
1420             (insert fortran-continuation-string))
1421         (if (looking-at "     [^ 0\n]")
1422             (if indent-tabs-mode
1423                 (progn (delete-char 6)
1424                        (insert "\t")
1425                        (insert-char (fortran-numerical-continuation-char) 1))
1426               (forward-char 6))
1427           (delete-horizontal-space)
1428           ;; Put line number in columns 0-4
1429           ;; or put continuation character in column 5.
1430           (cond ((eobp))
1431                 ((looking-at (regexp-quote fortran-continuation-string))
1432                  (if indent-tabs-mode
1433                      (progn
1434                        (indent-to 
1435                         (if indent-tabs-mode
1436                             fortran-minimum-statement-indent-tab
1437                           fortran-minimum-statement-indent-fixed))
1438                        (delete-char 1)
1439                        (insert-char (fortran-numerical-continuation-char) 1))
1440                    (indent-to 5)
1441                    (forward-char 1)))
1442                 ((looking-at "[0-9]+")
1443                  (let ((extra-space (- 5 (- (match-end 0) (point)))))
1444                    (if (< extra-space 0)
1445                        (message "Warning: line number exceeds 5-digit limit.")
1446                      (indent-to (min fortran-line-number-indent extra-space))))
1447                  (skip-chars-forward "0-9")))))
1448       ;; Point is now after any continuation character or line number.
1449       ;; Put body of statement where specified.
1450       (delete-horizontal-space)
1451       (indent-to col)
1452       ;; Indent any comment following code on the same line.
1453       (if (and comment-start-skip
1454                (fortran-find-comment-start-skip))
1455           (progn (goto-char (match-beginning 0))
1456                  (if (not (= (current-column) (fortran-comment-hook)))
1457                      (progn (delete-horizontal-space)
1458                             (indent-to (fortran-comment-hook)))))))))
1459
1460 (defun fortran-line-number-indented-correctly-p ()
1461   "Return t if current line's line number is correctly indented.
1462 Do not call if there is no line number."
1463   (save-excursion
1464     (beginning-of-line)
1465     (skip-chars-forward " \t")
1466     (and (<= (current-column) fortran-line-number-indent)
1467          (or (= (current-column) fortran-line-number-indent)
1468              (progn (skip-chars-forward "0-9")
1469                     (= (current-column) 5))))))
1470
1471 (defun fortran-check-for-matching-do ()
1472   "When called from a numbered statement, returns t if matching DO is found.
1473 Otherwise return a nil."
1474   (let (charnum
1475         (case-fold-search t))
1476     (save-excursion
1477       (beginning-of-line)
1478       (if (looking-at "[ \t]*[0-9]+")
1479           (progn
1480             (skip-chars-forward " \t")
1481             (skip-chars-forward "0") ;skip past leading zeros
1482             (setq charnum (buffer-substring (point)
1483                                             (progn (skip-chars-forward "0-9")
1484                                                    (point))))
1485             (beginning-of-line)
1486             (and (re-search-backward
1487                   (concat "\\(^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]\\)\\|"
1488                           "\\(^[ \t0-9]*do[ \t]*0*" charnum "\\b\\)\\|"
1489                           "\\(^[ \t]*0*" charnum "\\b\\)")
1490                   nil t)
1491                  (looking-at (concat "^[ \t0-9]*do[ \t]*0*" charnum))))))))
1492
1493 (defun fortran-find-comment-start-skip ()
1494   "Move to past `comment-start-skip' found on current line.
1495 Return t if `comment-start-skip' found, nil if not."
1496 ;;; In order to move point only if comment-start-skip is found,
1497 ;;; this one uses a lot of save-excursions.  Note that re-search-forward
1498 ;;; moves point even if comment-start-skip is inside a string-constant.
1499 ;;; Some code expects certain values for match-beginning and end
1500   (interactive)
1501   (if (save-excursion
1502         (re-search-forward comment-start-skip
1503                            (save-excursion (end-of-line) (point)) t))
1504       (let ((save-match-beginning (match-beginning 0))
1505             (save-match-end (match-end 0)))
1506         (if (fortran-is-in-string-p (match-beginning 0))
1507             (save-excursion
1508               (goto-char save-match-end)
1509               (fortran-find-comment-start-skip)) ; recurse for rest of line
1510           (goto-char save-match-beginning)
1511           (re-search-forward comment-start-skip
1512                              (save-excursion (end-of-line) (point)) t)
1513           (goto-char (match-end 0))
1514           t))
1515     nil))
1516
1517 ;;;From: simon@gnu (Simon Marshall)
1518 ;;; Find the next ! not in a string.
1519 (defun fortran-match-!-comment (limit)
1520   (let (found)
1521     (while (and (setq found (search-forward "!" limit t))
1522                 (fortran-is-in-string-p (point))))
1523     (if (not found)
1524         nil
1525       ;; Cheaper than `looking-at' "!.*".
1526       (store-match-data
1527        (list (1- (point)) (progn (end-of-line) (min (point) limit))))
1528       t)))
1529
1530 ;; The above function is about 10% faster than the below...
1531 ;;(defun fortran-match-!-comment (limit)
1532 ;;  (let (found)
1533 ;;    (while (and (setq found (re-search-forward "!.*" limit t))
1534 ;;                (fortran-is-in-string-p (match-beginning 0))))
1535 ;;    found))
1536
1537 ;;;From: ralf@up3aud1.gwdg.de (Ralf Fassel)
1538 ;;; Test if TAB format continuation lines work.
1539 (defun fortran-is-in-string-p (where)
1540   "Return non-nil if POS (a buffer position) is inside a Fortran string,
1541 nil else."
1542   (save-excursion
1543     (goto-char where)
1544     (cond
1545      ((bolp) nil)                       ; bol is never inside a string
1546      ((save-excursion                   ; comment lines too
1547         (beginning-of-line)(looking-at fortran-comment-line-start-skip)) nil)
1548      (t (let (;; ok, serious now. Init some local vars:
1549               (parse-state '(0 nil nil nil nil nil 0))
1550               (quoted-comment-start (if comment-start
1551                                         (regexp-quote comment-start)))
1552               (not-done t)
1553               parse-limit
1554               end-of-line
1555               )
1556           ;; move to start of current statement
1557           (fortran-next-statement)
1558           (fortran-previous-statement)
1559           ;; now parse up to WHERE
1560           (while not-done
1561             (if (or ;; skip to next line if:
1562                  ;; - comment line?
1563                  (looking-at fortran-comment-line-start-skip)
1564                  ;; - at end of line?
1565                  (eolp)
1566                  ;; - not in a string and after comment-start?
1567                  (and (not (nth 3 parse-state))
1568                       comment-start
1569                       (equal comment-start
1570                              (char-to-string (preceding-char)))))
1571                 ;; get around a bug in forward-line in versions <= 18.57
1572                 (if (or (> (forward-line 1) 0) (eobp))
1573                     (setq not-done nil))
1574               ;; else:
1575               ;; if we are at beginning of code line, skip any
1576               ;; whitespace, labels and tab continuation markers.
1577               (if (bolp) (skip-chars-forward " \t0-9"))
1578               ;; if we are in column <= 5 now, check for continuation char
1579               (cond ((= 5 (current-column)) (forward-char 1))
1580                     ((and (< (current-column) 5)
1581                           (equal fortran-continuation-string
1582                                  (char-to-string (following-char)))
1583                           (forward-char 1))))
1584               ;; find out parse-limit from here
1585               (setq end-of-line (save-excursion (end-of-line)(point)))
1586               (setq parse-limit (min where end-of-line))
1587               ;; parse max up to comment-start, if non-nil and in current line
1588               (if comment-start
1589                   (save-excursion
1590                     (if (re-search-forward quoted-comment-start end-of-line t)
1591                         (setq parse-limit (min (point) parse-limit)))))
1592               ;; now parse if still in limits
1593               (if (< (point) where)
1594                   (setq parse-state (parse-partial-sexp
1595                                      (point) parse-limit nil nil parse-state))
1596                 (setq not-done nil))
1597               ))
1598           ;; result is
1599           (nth 3 parse-state))))))
1600
1601 (defun fortran-auto-fill-mode (arg)
1602   "Toggle fortran-auto-fill mode.
1603 With ARG, turn `fortran-auto-fill' mode on iff ARG is positive.
1604 In `fortran-auto-fill' mode, inserting a space at a column beyond `fill-column'
1605 automatically breaks the line at a previous space."
1606   (interactive "P")
1607   (prog1 (setq auto-fill-function
1608                (if (if (null arg)
1609                        (not auto-fill-function)
1610                      (> (prefix-numeric-value arg) 0))
1611                    'fortran-do-auto-fill
1612                  nil))
1613     (redraw-modeline)))
1614
1615 (defun fortran-do-auto-fill ()
1616   (if (> (current-column) fill-column)
1617       (fortran-indent-line)))
1618
1619 (defun fortran-fill ()
1620   (interactive)
1621   (let* ((opoint (point))
1622          (bol (save-excursion (beginning-of-line) (point)))
1623          (eol (save-excursion (end-of-line) (point)))
1624          (bos (min eol (+ bol (fortran-current-line-indentation))))
1625          (quote
1626           (save-excursion
1627             (goto-char bol)
1628             (if (looking-at fortran-comment-line-start-skip)
1629                 nil                     ; OK to break quotes on comment lines.
1630               (move-to-column fill-column)
1631               (cond ((fortran-is-in-string-p (point))
1632                      (save-excursion (re-search-backward "[^']'[^']" bol t)
1633                                      (if fortran-break-before-delimiters
1634                                          (point)
1635                                        (1+ (point)))))
1636                     (t nil)))))
1637          ;;
1638          ;; decide where to split the line. If a position for a quoted
1639          ;; string was found above then use that, else break the line
1640          ;; before the last delimiter.
1641          ;; Delimiters are whitespace, commas, and operators.
1642          ;; Will break before a pair of *'s.
1643          ;;
1644          (fill-point
1645           (or quote
1646               (save-excursion
1647                 (move-to-column (1+ fill-column))
1648                 (skip-chars-backward "^ \t\n,'+-/*=)"
1649 ;;;              (if fortran-break-before-delimiters
1650 ;;;                  "^ \t\n,'+-/*=" "^ \t\n,'+-/*=)")
1651                  )
1652                 (if (<= (point) (1+ bos))
1653                     (progn
1654                       (move-to-column (1+ fill-column))
1655 ;;;what is this doing???
1656                       (if (not (re-search-forward "[\t\n,'+-/*)=]" eol t))
1657                           (goto-char bol))))
1658                 (if (bolp)
1659                     (re-search-forward "[ \t]" opoint t)
1660                   (forward-char -1)
1661                   (if (looking-at "'")
1662                       (forward-char 1)
1663                     (skip-chars-backward " \t\*")))
1664                 (if fortran-break-before-delimiters
1665                     (point)
1666                   (1+ (point))))))
1667          )
1668     ;; if we are in an in-line comment, don't break unless the
1669     ;; line of code is longer than it should be. Otherwise
1670     ;; break the line at the column computed above.
1671     ;;
1672     ;; Need to use fortran-find-comment-start-skip to make sure that quoted !'s
1673     ;; don't prevent a break.
1674     (if (not (or (save-excursion
1675                    (if (and (re-search-backward comment-start-skip bol t)
1676                             (not (fortran-is-in-string-p (point))))
1677                        (progn
1678                          (skip-chars-backward " \t")
1679                          (< (current-column) (1+ fill-column)))))
1680                  (save-excursion
1681                    (goto-char fill-point)
1682                    (bolp))))
1683         (if (> (save-excursion
1684                  (goto-char fill-point) (current-column))
1685                (1+ fill-column))
1686             (progn (goto-char fill-point)
1687                    (fortran-break-line))
1688           (save-excursion
1689             (if (> (save-excursion
1690                      (goto-char fill-point) 
1691                      (current-column))
1692                    (+ (calculate-fortran-indent) fortran-continuation-indent))
1693                 (progn
1694                   (goto-char fill-point)
1695                   (fortran-break-line))))))
1696     ))
1697 (defun fortran-break-line ()
1698   (let ((bol (save-excursion (beginning-of-line) (point)))
1699         (eol (save-excursion (end-of-line) (point)))
1700         (comment-string nil))
1701     
1702     (save-excursion
1703       (if (and comment-start-skip (fortran-find-comment-start-skip))
1704           (progn
1705             (re-search-backward comment-start-skip bol t)
1706             (setq comment-string (buffer-substring (point) eol))
1707             (delete-region (point) eol))))
1708 ;;; Forward line 1 really needs to go to next non white line
1709     (if (save-excursion (forward-line 1)
1710                         (or (looking-at "     [^ 0\n]")
1711                             (looking-at "\t[1-9]")))
1712         (progn
1713           (end-of-line)
1714           (delete-region (point) (match-end 0))
1715           (delete-horizontal-space)
1716           (fortran-fill))
1717       (fortran-split-line))
1718     (if comment-string
1719         (save-excursion
1720           (goto-char bol)
1721           (end-of-line)
1722           (delete-horizontal-space)
1723           (indent-to (fortran-comment-hook))
1724           (insert comment-string)))))
1725
1726 (defun fortran-analyze-file-format ()
1727   "Returns nil if fixed format is used, t if TAB formatting is used.
1728 Use `fortran-tab-mode-default' if no non-comment statements are found in the
1729 file before the end or the first `fortran-analyze-depth' lines."
1730   (let ((i 0))
1731     (save-excursion
1732       (goto-char (point-min))
1733       (setq i 0)
1734       (while (not (or
1735                    (eobp)
1736                    (looking-at "\t")
1737                    (looking-at "      ")
1738                    (> i fortran-analyze-depth)))
1739         (forward-line)
1740         (setq i (1+ i)))
1741       (cond
1742        ((looking-at "\t") t)
1743        ((looking-at "      ") nil)
1744        (fortran-tab-mode-default t)
1745        (t nil)))))
1746
1747 (or (assq 'fortran-tab-mode-string minor-mode-alist)
1748     (setq minor-mode-alist (cons
1749                             '(fortran-tab-mode-string
1750                               (indent-tabs-mode fortran-tab-mode-string))
1751                             minor-mode-alist)))
1752
1753 ; fortran-join-line and fill
1754 ; imported from GNU Emacs 21.3.1 by  s.ballestrero@firenze.linux.it
1755
1756 (defun fortran-remove-continuation ()
1757   (if (looking-at "\\(     [^ 0\n]\\|\t[1-9]\\|&\\)")
1758       (progn (replace-match "")
1759              (delete-indentation)
1760              t)))
1761
1762 (defun fortran-join-line (arg)
1763   "Join current line to the previous one and re-indent.
1764 With a prefix argument, repeat this operation that many times.
1765 If the prefix argument ARG is negative, join the next -ARG lines.
1766 Continuation lines are correctly handled."
1767   (interactive "*p")
1768   (save-excursion
1769     (when (> 0 arg)
1770       (setq arg (- arg))
1771       (forward-line arg))
1772     (while (not (zerop arg))
1773       (beginning-of-line)
1774       (or (fortran-remove-continuation)
1775           (delete-indentation))
1776       (setq arg (1- arg)))
1777     (fortran-indent-line)))
1778
1779 (defun fortran-fill-paragraph (&optional justify)
1780   "Fill surrounding comment block as paragraphs, else fill statement.
1781 Intended as the value of `fill-paragraph-function'."
1782   (interactive "P")
1783   (save-excursion
1784     (beginning-of-line)
1785     (if (not (looking-at fortran-comment-line-start-skip))
1786         (fortran-fill-statement)
1787         ;; We're in a comment block.  Find the start and end of a
1788         ;; paragraph, delimited either by non-comment lines or empty
1789         ;; comments.  (Get positions as markers, since the
1790         ;; `indent-region' below can shift the block's end).
1791         (let* ((non-empty-comment
1792                 (concat fortran-comment-line-start-skip "[^ \t\n]"))
1793                (start (save-excursion
1794                         ;; Find (start of) first line.
1795                         (while (and (zerop (forward-line -1))
1796                                     (looking-at non-empty-comment)))
1797                         (or (looking-at non-empty-comment)
1798                             (forward-line)) ; overshot
1799                         (point-marker)))
1800                (end (save-excursion
1801                       ;; Find start of first line past region to fill.
1802                       (while (progn
1803                                (forward-line)
1804                                (looking-at non-empty-comment)))
1805                       (point-marker))))
1806           ;; Indent the block, find the string comprising the effective
1807           ;; comment start skip and use that as a fill-prefix for
1808           ;; filling the region.
1809           (indent-region start end nil)
1810           (let ((paragraph-ignore-fill-prefix nil)
1811                 (fill-prefix (progn
1812                                (beginning-of-line)
1813                                (looking-at fortran-comment-line-start-skip)
1814                                (match-string 0))))
1815             (let (fill-paragraph-function)
1816               (fill-region start end justify))) ; with normal `fill-paragraph'
1817           (set-marker start nil)
1818           (set-marker end nil))))
1819   t)
1820
1821 (defun fortran-fill-statement ()
1822   "Fill a fortran statement up to `fill-column'."
1823   (interactive)
1824   (let ((auto-fill-function #'fortran-auto-fill))
1825     (if (not (save-excursion
1826                (beginning-of-line)
1827                (or (looking-at "[ \t]*$")
1828                    (looking-at fortran-comment-line-start-skip)
1829                    (and comment-start-skip
1830                         (looking-at (concat "[ \t]*"
1831                                             comment-start-skip))))))
1832         (save-excursion
1833           ;; Find beginning of statement.
1834           (fortran-next-statement)
1835           (fortran-previous-statement)
1836           ;; Re-indent initially.
1837           (fortran-indent-line)
1838           ;; Replace newline plus continuation field plus indentation with
1839           ;; single space.
1840           (while (progn
1841                    (forward-line)
1842                    (fortran-remove-continuation)))
1843           (fortran-previous-statement)))
1844     (fortran-indent-line)))
1845
1846
1847 ;; XEmacs additions
1848 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.f\\(?:or\\)?\\'" . fortran-mode))
1849 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.F\\(?:OR\\)?\\'" . fortran-mode))
1850
1851 (provide 'fortran)
1852
1853 ;;; fortran.el ends here