# Findent

## What does it do?

Indent and relabel Fortran sources. <br>Findent can also be used to convert from fixed format to free format and vice versa.

<a href="#highlights">Highlights</a> | 
<a href="#creating">Creating</a> | 
<a href="#otherindenters">Other indenters</a> | 
<a href="#otherlabellers">Other labellers</a>

See also: [Design, building and usage](design_and_usage/index.html)

***

<a id="highlights"></a>

## Highlights

 * 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](http://www.daniellnagle.com/coco.html) **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](downloads) and on 
   [sourceforge](https://sourceforge.net/projects/findent/)
 * findent is able to **replicate it's source code**

### Examples

 * 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:

         wfindent prog.f90

 * 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:

         findent -h


<a id="creating"></a>

## Creating findent
I decided to try to write a Fortran indenter, using the requirements below. 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 below.
The program is developed using Linux (Ubuntu), g++, flex and bison.
A detailed description of the design is available [here (pdf)](YYYdZZZ/findent/findent.pdf).

### Desirable requirements of a Fortran indenter

* 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.

### Using findent in vim, gedit and emacs
Findent optionally outputs configuration files for usage with vim or gedit and emacs, see `findent --help`.

### 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](https://brew.sh) 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.

### Windows

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](https://www.cygwin.com/) or maybe [WSL](https://learn.microsoft.com/en-us/windows/wsl/about) 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.

<a id="otherindenters"></a>

## 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](http://fortranwiki.org/fortran/show/f90ppr). 
F90ppr is written in Fortran and does a nice and quick job, but lacks a number of the requirements.

The editors [vim](https://www.vim.org/scripts/script.php?script_id=4959) and 
[emacs](https://www.gnu.org/software/emacs/manual/html_node/emacs/Fortran.html),
and probably more, have options to indent Fortran sources.
It is possible to convert these for use on the command line, but they lack some of
the requirements. 

[fpt](http://www.simconglobal.com/index.html) aims at analysis of Fortran programs, and produces 
indented sources. It is not open source, and a (free, 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](https://github.com/pseewald/fprettify), written in Python.
It aims at indenting 'modern Fortran', so it cannot be used for your old dusty decks.
It seems that development has been halted since circa 2023.
IMHO the software is not mature enough for use in serious projects. 

An recent star in the firmament of Fortran indenters is 
[fortify](https://github.com/louoberto/fortify). 
Fortify is written in Python, seems to handle labelled do-loops well and treats fixed and free format.
Time will learn how this project will develop.

<a id="otherlabellers"></a>

## Other Fortran relabelers
These are even more difficult to find. [Floppy](https://www.netlib.org/floppy/contents.html), written in Fortran
is an example, but works only for old style Fortran.

[fpt](http://www.simconglobal.com/index.html) can also relabel, but read the comments above about 
the program.
