Findent: indent and relabel Fortran sources
Findent: what does it do?
Findent indents Fortran sources.
- supports Fortran 2018, and is validated against all constructs in 'Modern Fortran explained, Incorporating Fortran 2018, Metcalf; Reid; Cohen'
- supports vintage Fortran standards from Fortran IV and Fortran66 on
- by default, findent just indents: it changes the number of spaces at the beginning of a line, and nothing more
- the indentation to be used can be set different for BLOCK, IF, DO, CONTAINS ...
- optionally converts from fixed format to free format, and vice versa
- handles correct, but also incorrect Fortran sources without complaining
- optionally relabels (i.e. renumbers labels) Fortran sources
- handles cpp and coco preprocessor directives
- can be used in vim, gedit and emacs, incorporation in other editors should be easy
- indenting speed: > 100K lines/second
- relabeling speed: > 40K lines/second
- the script wfindent, a wrapper around findent, indents one or more Fortran sources in place
- runs on Linux, BSD, MacOS and Windows
- comes with a comprehensive man page
- is available on many Linux and BSD distributions and in MacOS
- source, Debian packages and Windows executable are available here and on sourceforge
As a bonus, I wrote a graphical front end, written in Java, and baptised 'jfindent'. (It appears that practically nobody is interested in jfindent).
use defaults, take as input prog.f and output prog1.f (either in fixed or free format):
findent < prog.f > prog1.f
indent prog.f90 in place:
convert fixed format to free format (input prog.f, output prog.f90):
findent -ofree < prog.f > prog.f90
the same, but also replace 'end' with 'end program program name', 'end subroutine subroutine name' as appropriate:
findent -ofree -Rr < prog.f > prog.f90
change default indentation (3 spaces) to 2 spaces, and start with 6 spaces:
findent -i2 -I6 < prog.f90 > prog1.f90
output comprehensive usage information:
Desirable properties of a Fortran indenter
I think a Fortran indenter should have the following properties:
- indents correctly old fashioned and modern Fortran and is not confused by wrong or unknown syntax
- indents fixed and free format, the amount of indent decided by the user
- indenting is increased at SUBROUTINE, MODULE, FUNCTION, SELECT CASE, DO and so on, and decreased as appropriate
- is capable to convert from fixed format to free format (the other way around would be nice)
- is capable to convert 'end' statements to 'end subroutine', 'end program' or 'end module' statements to facilitate the conversion from Fortran-77 to Fortran-90
- does not by default 'beautify' the source: if I put 3 spaces somewhere in the middle of a line, they should be preserved
- does not by default change the case of keywords or user-invented names
- handles unknown constructs friendly
- does not break long lines: every decent compiler can handle long lines, and breaking lines by hand is not that difficult or time consuming
- is capable to process 'tabbed input' (i.e. a tab is used in the first 6 characters of a fixed-format Fortran line)
- indents correctly from Fortran-4 to Fortran-2018 or later
- works on a line-per-line basis, so that the indenting can start and end at any line in the source
- not necessary but nice: be able to relabel on request
The indenter does not have to parse a Fortran statement completely, but it should not be easily fooled by constructs like:
do 10 i=1.10 ! this is not a do statement, but an assignment ! to the variable 'do10i' done = 20 ! this is an assignment to the variable 'done' subroutine(x) = 20 ! not a subroutine statement realfunctioncalc(x) ! must be recognized as a function statement do 10 i=1,n do 10 j=1,m ... 10 continue ! this must be recognized as ending two loops #ifdef one ! the indenter should be capable to see that this is only one do statement, ! and not indent twice do i =1,1 #else do i=1,n #endif
And it would be nice if the program runs in Linux, BSD, Windows and MacOS.
I decided to try to write a Fortran indenter, using the requirements above. It took me more time than I thought, but in the end I am very happy with the result, especially because the easy interoperability with vim. I did my best to fulfil all requirements above. The program is developed using Linux (Ubuntu), g++, flex and bison.
Using findent in vim, gedit and emacs
Findent optionally outputs configuration files for usage
with vim or gedit and emacs, see
Using findent in eclipse
I was not able to find out how to incorporate findent in eclipse and would really appreciate it if somebody could help me out.
Using findent to create dependencies for 'make'
The creation of dependencies in a Fortran project using modules is kind of a problem, see also the f90dep entry in this web site. Since findent has the ability to recognize definitions of (sub)modules and the usages thereof, it was tempting to let findent optionally list these dependencies. See the man page and look for 'Dependencies'. Findent is able to produce a shell script that can be used as a starting point for usage in your large f90 project.
MacOS, openBSD and freeBSD
There are some issues with the script wfindent:
- getopt(1) is different from gnu-getopt: for example, it does not facilitate long flags. Getopt is used in wfindent. The problem is resolved as follows: If wfindent cannot find a suitable getopt (gnu-getopt returns 4 with the flag -T) it returns with a message.
- MacOS and BSD users can easily install a working getopt, for example via (macOS:) Homebrew or (openBSD:) 'pkg_add gnugetopt' or (freeBSD:) 'pkg install getopt'. If the environment variable WFINDENT_GETOPT is set to the location of a gnu-getopt, it will use that.
The Windows executable of findent is made in Linux using the mingw package, with i686-w64-mingw32-g++ as compiler, and statically linked. Wfindent.bat is written in the old-fashioned Dos batch language.
- I would be happy when someone send me a version of wfindent.bat written in a more up-to-date language.
If you want to compile findent yourself on Windows, consult the script simplemake.sh in the tarball for inspiration how to do it. Another possibility would be to install Cygwin or maybe WSL and run the 'configure;make;make install' suite.
UTF-8 and other encodings
Findent is completely negligent of UTF-8 or other encodings. The encoding could be important when handling strings. But fortunately, all encodings have the same code for single quote (',0x27) and double quote (",0x22), and these codes unambiguously denote single quote and double quote respectively. For example: in UTF-8, 0x27 cannot be part of a multi-character symbol: in a multi-character symbol, all first bits of the characters are set to 1.
Other Fortran indenters
Good free Fortran indenters to be used on the command line are 'not easy to find'. Searching the Internet, I was not able to find good working free available Fortran indenters, with the exception of f90ppr. F90ppr is written in Fortran and does a nice and quick job, but lacks a number of the requirements.
fpt aims at analysis of Fortran programs, and produces indented sources. It is not open source, and a (gratis, valid for one year) license is required. Unfortunately, usage is somewhat clumsy and the program gives unpredictable results when faced with unknown constructs (I tested version 4.1). There are also problems when fpt is confronted with code that is not complete. Furthermore a number of requirements is lacking.
A more recent development is fprettify, written in Python. It aims at indenting 'modern Fortran', so it cannot be used for your old dusty decks, and other requirements are also not met. IMHO the software is not mature enough for use in serious projects.
Other Fortran relabelers
These are even more difficult to find. Floppy, written in Fortran is an example, but works only for old style Fortran.
fpt can also relabel, but read the comments above about the program.