Compiler Support for the Fortran 2003 Standard

The table below documents features from the Fortran 2003 standard that are supported by several available compilers. A similar table is also availble for Fortran 2008 status.

Note that the versions described below may be out of date and that the development versions of some compilers support many support additional features. Please check with the compiler vendor for the most up-to-date information on support for specific features. See Compiler Support for Modern Fortran for a summary, caveats, and links to compiler-specific status pages and see Fortran 2003 status discussion for a discussion of the merits of maintaining this page.

(32) These user-defined functions are not to be confused with a type’s structure constructor, which is generated automatically. Structure constructors have also changed in Fortran 2003, e.g. by treating components with default initialization as optional arguments.

(33) Implemented as specified in the Fortran 2003 standard, not as in ISO TR 15581.

(34) Kind type parameters for derived types only.

Changes

Changes between December 2015 and August 2016:

Updated table based on latest results from the August 2016 Fortran Forum article (Revision 19).

Updated table based on latest results from the April 2016 Fortran Forum article (Revision 18).

Changes between April 2011 and December 2015:

Updated table based on latest results from the December 2015 Fortran Forum article (Revision 17).

Compiler Support for the Fortran 2008 Standard

The table below documents features from the Fortran 2008 standard that are supported by recent versions of several available compilers. Of course, development versions of some compilers support may additional features. See Compiler Support for Modern Fortran for a summary, caveats, and links to compiler-specific status pages. A similar table is also available for Fortran 2003 status.

reading an arbitrary number of values from a line

I have often seen questions on how to read an arbitrary number of numeric values from an input line. I have a collection of parsing routines I have used for this task, but decided to revisit the problem using list-directed input, internal reads, and Fortran 2003. It ends up it is relatively straight-forward to read a line with an arbitrary number of values, to use repeat counts, to allow for inline comments (using the fact that the slash seperator is really not a seperator on list-directed input but an input terminator).

Lines with single and double quotes in the input could cause some surprises, but this ends up being a very flexible way to read a list of numeric values. Complex numbers can be supported too. Add some allocatable arrays and a routine for reading a line of arbitrary length and this could be made even more generic.

Note that if you want to do something like this you should look at NAMELIST input too; which can now also read from an internal file.

After a careful read of the definition of list-directed input I am convinced this is standard f2003. If I’m wrong let me know. Enjoy …

NAME

getvals(3f) - [M_getvals] read arbitrary number of values from a character variable up to size of VALUES() array

Module Source

!-----------------------------------------------------------------------------------------------------------------------------------module M_getvalsprivatepublicgetvalscontains!-----------------------------------------------------------------------------------------------------------------------------------subroutine getvals(line,values,icount,ierr)implicitnonecharacter(len=*),parameter::ident='@(#)getvals: read arbitrary number of values from a character variable up to size of values'! JSU 20170831character(len=*),intent(in)::linereal::values(:)integer,intent(out)::icountinteger,intent(out),optional::ierrcharacter(len=:),allocatable::buffercharacter(len=len(line))::words(size(values))integer::ios,i,ierr_localierr_local=0words=' '! make sure words() is initialized to null+blanksbuffer=trim(line)//"/"! add a slash to the end so how the read behaves with missing values is clearly definedread(buffer,*,iostat=ios)words! undelimited strings are read into an arrayicount=0doi=1,size(values)! loop thru array and convert non-blank words to numbersif(words(i)(1:1).eq.' ')exitread(words(i),*,iostat=ios)values(icount+1)if(ios.eq.0)thenicount=icount+1elseierr_local=ioswrite(*,*)'*getvals* WARNING:['//trim(words(i))//'] is not a number'endifenddoif(present(ierr))thenierr=ierr_localelseif(ierr_local.ne.0)then! error occurred and not returning error to main program to print message and stop programwrite(*,*)'*getval* error reading line ['//trim(line)//']'stop2endifendsubroutine getvalsendmodule M_getvals!-----------------------------------------------------------------------------------------------------------------------------------

Allowing ARRAYS() to be of various types

This is a variant that allows the ARRAYS() value to be of type INTEGER, REAL, or DOUBLEPRECISION …

module M_getvalsprivatepublicgetvalscontainssubroutine getvals(line,values,icount,ierr)implicitnonecharacter(len=*),parameter::ident='@(#)getvals: read arbitrary number of values from a character variable up to size of values'! JSU 20170831character(len=*),intent(in)::lineclass(*),intent(in)::values(:)integer,intent(out)::icountinteger,intent(out),optional::ierrcharacter(len=:),allocatable::buffercharacter(len=len(line))::words(size(values))integer::ios,i,ierr_local,isizeselecttype(values)typeis(integer);isize=size(values)typeis(real);isize=size(values)typeis(doubleprecision);isize=size(values)typeis(character(len=*));isize=size(values)endselectierr_local=0words=' '! make sure words() is initialized to null+blanksbuffer=trim(line)//"/"! add a slash to the end so how the read behaves with missing values is clearly definedread(buffer,*,iostat=ios)words! undelimited strings are read into an arrayicount=0doi=1,isize! loop thru array and convert non-blank words to numbersif(words(i).eq.' ')cycleselecttype(values)typeis(integer);read(words(i),*,iostat=ios)values(icount+1)typeis(real);read(words(i),*,iostat=ios)values(icount+1)typeis(doubleprecision);read(words(i),*,iostat=ios)values(icount+1)typeis(character(len=*));values(icount+1)=words(i)endselectif(ios.eq.0)thenicount=icount+1elseierr_local=ioswrite(*,*)'*getvals* WARNING:['//trim(words(i))//'] is not a number of specified type'endifenddoif(present(ierr))thenierr=ierr_localelseif(ierr_local.ne.0)then! error occurred and not returning error to main program to print message and stop programwrite(*,*)'*getval* error reading line ['//trim(line)//']'stop2endifendsubroutine getvals!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================endmodule M_getvals

Reading a file of integers

Here is a slightly different method that solves the most frequently asked question I saw – how to read a file of integers into an array without knowing how many values are on a line or how many values are in the file.

Not sure why this is asked about so often. I hope I am not doing a frequently assigned homework problem.

This is a self-contained example. It requires Fortran 2003+.

There is quite a bit of re-allocation used, which means this might be slow on large files (hundreds of thousands of values) in some programming environments.

program readfileimplicitnoneinteger,parameter::line_length=80character(len=line_length)::linecharacter(len=line_length)::wordinteger::a(line_length/2+1)integer::i,io,icountinteger,allocatable::total(:)allocate(total(0))open(100,file='data')FILEREAD:doread(100,'(a)',IOSTAT=io)line! read a line into character variableif(io.ne.0)exitFILEREADwrite(*,*)'new line=',trim(line)doi=1,len(line)! replace comma and semicolon delimiters with spacesselectcase(line(i:i))case(',',';');line(i:i)=' 'endselectenddoicount=0! initialize count of values found on linedoline=adjustl(line)! remove leading spacesread(line,*,IOSTAT=io)word! read next token from lineif(io.ne.0)exitread(word,*,IOSTAT=io)a(icount+1)! convert token to a numberif(io.ne.0)exiticount=icount+1line=line(len_trim(word)+1:)! remove token just readenddowrite(*,'(1x,a,i0,a,*(i0:,","))')' read ',icount,' values=',a(:icount)total=[total,a(:icount)]enddoFILEREADwrite(*,'(a,i0)')'total values read=',size(total)write(*,'(*(i0:,","))')totalendprogram readfile

Source Code on the Fortran Wiki

When contributing code, please specify a license so that others know the extent to which they may use and modify your code. All code on the Fortran Wiki shall be in the public domain unless otherwise noted. Other common licenses are the BSD, MIT, and GPL licenses.

To contribute Fortran source code, add a link here to the filename, program, or module name, and create the new page by pasting the code, wrapping it in a fenced code block with a language keyword. See the HowTo and existing pages such as hello for examples.

Quine in fortran 90 While Fortran has been thought to develop scientific applications, it can also be used for programmer amusement, here is a nice quine written in Fortran. A quine is a computer program which takes no input and produces a copy of its own source code as its only output.

Let It Snow in Fortran Inspired by google’s let it snow, this is let it snow animation in fortran using pgplot graphics library.

M_TIME() MODULE

Manipulating and Presenting Dates and Times

The DATE_AND_TIME(3f) Fortran intrinsic provides a portable way to ask for the current time. This module (M_TIME) uses the same representation of a date as provided by DATE_AND_TIME(3f) to add other basic date manipulation functions and representations.

Ordinal days of the year, days of the week, Unix Epoch Dates, Julian Dates, month names, execution times and CPU usage and a Fortran-callable sleep(3c) procedure are provided for, for example.

This module assumes you are manipulating dates in the recent era and does not internally take into account leap seconds; as is typical of basic date-time libraries. The current time zone is determined by using DATE_AND_TIME(3f); which is frequently controlled by the TZ environment variable.

In this library

A “date and time” array “DAT” has the same format as the array of values generated by the Fortran intrinsic DATE_AND_TIME(3f). That is, it is an 8-element integer array containing year, month, day, Time zone difference from UTC in minutes, hour, minutes, seconds, and milliseconds of the second. It is assumed it represents a date on the Proleptic Gregorian Calendar.

The Proleptic Gregorian Calendar assumes the Gregorian Calendar existed back to the beginning of the Julian date (4713 BC). This means historic dates will often be confused, as the Julian Calendar was used in the USA until 1752-09-03, for example. The Gregorian Calendar was formally decreed in 1582-10-15 but was not adapted at that time in many countries. The Julian Calendar was first used around 44 to 46 BC.

Unix Epoch Time is defined as the number of seconds since 00:00:00 on 1 Jan. 1970.

A JED is defined as a Julian Ephemeris Date. JED days start at noon (not at midnight). 4713-01-01 BC at noon is defined as JED 0.0,

If you are not familar with them, in this context the Julian Day dates and Unix Epoch Times are scalar numbers that allow for easy computations using dates (to go back one day just subtract one from a Julian date, for example). Since these values are generally not considered intelligible, routines are included to convert between the scalar values and the date array so human-readable results can be obtained.

Formatting Options in fmtdate()

The fmtdate() procedure lets you reformat a DAT array using a format string containing the following macros:

Names

abbreviated month name %l Dec
full month name %L December
first three characters of weekday %w Sat
weekday name %W Saturday

Literals

a literal % %% %
tab character %t
blank character %b

Program timing

CPU_TIME(3f) output %c .31250000000000000E-001
number of times this routine is used %C 1
time in seconds from SYSTEM_CLOCK(3f) %k 46728.0000

Alternatives

If you are looking for a high-precision Fortran library that is well tested for manipulating dates I would suggest looking at the NASA SPICElib library. Other extensive libraries exist. A sampling includes

And there are (of course) the C/C++ intrinsics which provide much of the same functionality that should be bindable to Fortran via the ISO_C_BINDING module.

There is absolutely no warranty on this library. The link to M_TIME above is to my personal version of this module, which I fiddle with at will but which does include additional functionality. If you fix any bugs feel free to correct this example; and indicate the change (and change the version number).

Example Program

program sampleuseM_time,only:jd,dj,ud,du,fmtdate,sys_sleep,nowinteger::dat(8)doubleprecision::julian,unixtimecharacter(len=:),parameter::iso_fmt='%Y-%M-%DT%h:%m:%s.%x%z'character(len=:),allocatable::friendlyfriendly='%W, %L %d, %Y %H:%m:%s %N'! a nice friendly formatcalldate_and_time(values=dat)! current time is placed in arraywrite(*,*)'Today'write(*,*)'ISO ',fmtdate(dat,iso_fmt)write(*,*)'Friendly ',fmtdate(dat,friendly)write(*,*)'ISO week ',fmtdate(dat,'%I')julian=dj(dat)unixtime=du(dat)write(*,*)'Yesterday'! subtract a day from scalar time and printwrite(*,*)' ',fmtdate(ud(unixtime-86400),iso_fmt)! using Unix Epoch Timewrite(*,*)' ',fmtdate(jd(julian-1.0),friendly)! using Julian Datewrite(*,*)' ',fmtdate(jd(julian-1.0),'%I')! week examplewrite(*,*)'Tomorrow'! add a day to scalar time and printwrite(*,*)' ',fmtdate(ud(unixtime+86400),iso_fmt)write(*,*)' ',fmtdate(jd(julian+1.0),friendly)write(*,*)' ',fmtdate(jd(julian+1.0),'%I')write(*,*)'Next Week'! add a week to scalar time and printwrite(*,*)' ',fmtdate(ud(unixtime+7*86400),iso_fmt)write(*,*)' ',fmtdate(jd(julian+7.0),friendly)write(*,*)' ',fmtdate(jd(julian+7.0),'%I')write(*,*)now('')write(*,*)'pausing around four seconds'callsys_sleep(4)write(*,*)now('')write(*,*)fmtdate(dat,'The CPU time used by this program was %c seconds')sum=0.0doi=1,10000000sum=sum+sqrt(real(i))enddowrite(*,*)'sum of busy work is ',sumwrite(*,*)fmtdate(dat,'The CPU time used by this program is now %c seconds')endprogram sample

Sample Output of Example Program

Today
ISO 2015-12-22T16:45:35.816-0300
Friendly Tuesday, December 22nd, 2015 04:45:35 PM
ISO week 2015-W52-2
Yesterday
2015-12-21T16:45:35.816-0300
Monday, December 21st, 2015 04:45:35 PM
2015-W52-1
Tomorrow
2015-12-23T16:45:35.816-0300
Wednesday, December 23rd, 2015 04:45:35 PM
2015-W52-3
Next Week
2015-12-29T16:45:35.816-0300
Tuesday, December 29th, 2015 04:45:35 PM
2015-W53-2
2015-12-22 16:45:35 -0300
pausing around four seconds
2015-12-22 16:45:39 -0300
The CPU time used by this program was .15625000000000000E-001 seconds
sum of busy work is 2.10864374E+10
The CPU time used by this program is now .10937500000000000 seconds

Module Source Code

module m_time! * Version: 1.0 2015-12-22implicitnoneprivate!-----------------------------------------------------------------------------------------------------------------------------------!EPOCH TIME (UT starts at 0000 on 1 Jan. 1970)publicd2u!(dat,UNIXTIME,IERR) ! Convert date array to Unix Timepublicu2d!(DAT,unixtime,IERR) ! Convert Unix Time to date arraypublicdu!(dat) result (UNIXTIME) ! Convert date array to Unix Timepublicud!(unixtime) result (DAT) ! Convert Unix Time to date array!JULIANpublicj2d!(DAT,julian,IERR) ! Convert Julian date to date arraypublicd2j!(dat,JULIAN,IERR) ! Convert date array to Julian datepublicdj!(dat) result (JULIAN) ! Convert date array to Julian Daypublicjd!(julian) result (DAT) ! Convert Julian Day to date array!DAY OF WEEKpublicdow!(dat,[WEEKDAY],[DAY],IERR) ! Convert date array to day of the week as number(Sun=1) and name!WEEK OF YEARpublicwoy!(dat,ISO_YEAR,ISO_WEEK,ISO_WEEKDAY,ISO_NAME) ! Calculate iso-8601 Week-numbering year date yyyy-Www-d!ORDINAL DAYpublicd2o!(dat) result(ORDINAL) ! given date array return ordinal day of year, Jan 1st=1!PRINTING DATESpublicfmtdate!(dat,format) result (TIMESTRING) ! Convert date array to string using formatpublicfmtdate_usage!() ! display macros recognized by fmtdate(3f)publicnow!(format) result (NOW) ! return string representing current time given format!MONTH NAMEpublicv2mo!(month_number) result (MONTH_NAME) ! given month number return month name!C INTERFACEpublicsys_sleep!(wait_seconds) ! Call sleep(3c)!-----------------------------------------------------------------------------------------------------------------------------------!INTERNALinteger,parameter,private::dp=kind(0.0d0)real(kind=dp)::secday=86400.0d0! 24:00:00 hours as seconds!-----------------------------------------------------------------------------------------------------------------------------------!C INTERFACEcontains!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================subroutine d2j(dat,julian,ierr)!-----------------------------------------------------------------------------------------------------------------------------------! * Author: John S. Urban! * Version: 1.0 2015-12-21! * Reference: From Wikipedia, the free encyclopedia 2015-12-19! * There is no year zero! * Julian Day must be non-negative! * Julian Day starts at noon; while Civil Calendar date starts at midnight!-----------------------------------------------------------------------------------------------------------------------------------character(len=:),parameter::ident="@(#)d2j(3f): Converts proleptic Gregorian date array to Julian Day -JSU 2015-12-21"integer,intent(in)::dat(8)! array like returned by DATE_AND_TIME(3f)real(kind=dp),intent(out)::julian! Julian Day (non-negative, but may be non-integer)integer,intent(out)::ierr! Error return, 0 for successful execution,-1=invalid year,-2=invalid month,-3=invalid day,! -4=invalid date (29th Feb, non leap-year)integer::year,month,day,utc,hour,minutereal(kind=dp)::secondinteger::A,Y,M,JDN!-----------------------------------------------------------------------------------------------------------------------------------year=dat(1)! Yearmonth=dat(2)! Monthday=dat(3)! Dayutc=dat(4)*60! Delta from UTC, convert from minutes to secondshour=dat(5)! Hourminute=dat(6)! Minutesecond=dat(7)-utc+dat(8)/1000.0d0! Second ! correction for time zone and milliseconds!-----------------------------------------------------------------------------------------------------------------------------------julian=-HUGE(99999)! this is the date if an error occurs and IERR is < 0!-----------------------------------------------------------------------------------------------------------------------------------if(year==0 .or.year .lt.-4713)thenierr=-1returnendif!-----------------------------------------------------------------------------------------------------------------------------------! You must compute first the number of years (Y) and months (M) since March 1st -4800 (March 1, 4801 BC)A=(14-month)/12! A will be 1 for January or Febuary, and 0 for other months, with integer truncationY=year+4800-AM=month+12*A-3! M will be 0 for March and 11 for Febuary! All years in the BC era must be converted to astronomical years, so that 1BC is year 0, 2 BC is year "-1", etc.! Convert to a negative number, then increment towards zero! Staring from a Gregorian calendar dateJDN=day+(153*M+2)/5+365*Y+Y/4-Y/100+Y/400-32045! with integer truncation! Finding the Julian date given the JDN (Julian day number) and time of dayjulian=JDN+dble(hour-12)/24.0d0+dble(minute)/1440.0d0+second/86400.0d0!-----------------------------------------------------------------------------------------------------------------------------------if(julian.lt.0.d0)then! Julian Day must be non-negativeierr=1elseierr=0endif!-----------------------------------------------------------------------------------------------------------------------------------endsubroutine d2j!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================subroutine j2d(dat,julian,ierr)character(len=:),parameter::ident="@(#)j2d(3f): Converts Julian Day to date array"integer,intent(out)::dat(8)integer::timezone(8),tzreal(kind=dp),intent(in)::julian! Julian Day (non-negative)integer,intent(out)::ierr! 0 for successful execution, otherwise 1real(kind=dp)::secondinteger::yearinteger::monthinteger::dayinteger::hourinteger::minuteinteger::jalpha,ja,jb,jc,jd,je,ijulif(julian.lt.0.d0)then! Negative Julian Day not allowedierr=1returnelseierr=0endifcalldate_and_time(values=timezone)tz=timezone(4)ijul=idint(julian)! Integral Julian Daysecond=sngl((julian-dble(ijul))*secday)! Seconds from beginning of Jul. Daysecond=second+(tz*60)if(second.ge.(secday/2.0d0))then! In next calendar dayijul=ijul+1second=second-(secday/2.0d0)! Adjust from noon to midnightelse! In same calendar daysecond=second+(secday/2.0d0)! Adjust from noon to midnightendifif(second.ge.secday)then! Final check to prevent time 24:00:00ijul=ijul+1second=second-secdayendifminute=int(second/60.0)! Integral minutes from beginning of daysecond=second-float(minute*60)! Seconds from beginning of minutehour=minute/60! Integral hours from beginning of dayminute=minute-hour*60! Integral minutes from beginning of hour!---------------------------------------------jalpha=idint((dble(ijul-1867216)-0.25d0)/36524.25d0)! Correction for Gregorian Calendarja=ijul+1+jalpha-idint(0.25d0*dble(jalpha))!---------------------------------------------jb=ja+1524jc=idint(6680.d0+(dble(jb-2439870)-122.1d0)/365.25d0)jd=365*jc+idint(0.25d0*dble(jc))je=idint(dble(jb-jd)/30.6001d0)day=jb-jd-idint(30.6001d0*dble(je))month=je-1if(month.gt.12)thenmonth=month-12endifyear=jc-4715if(month.gt.2)thenyear=year-1endifif(year.le.0)thenyear=year-1endifdat(1)=yeardat(2)=monthdat(3)=daydat(4)=tzdat(5)=hourdat(6)=minutedat(7)=int(second)dat(8)=int((second-int(second))*1000.0)ierr=0endsubroutine j2d!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================subroutine d2u(dat,unixtime,ierr)character(len=:),parameter::ident="@(#)d2u(3f): Converts date array to Unix Time (UT starts at 0000 on 1 Jan. 1970)"integer,intent(in)::dat(8)! date time array similar to that returned by DATE_AND_TIMEreal(kind=dp),intent(out)::unixtime! Unix time (seconds)integer,intent(out)::ierr! return 0 on successful, otherwise 1real(kind=dp)::julianreal(kind=dp),save::julian_at_epochlogical,save::first=.true.!-----------------------------------------------------------------------------------------------------------------------------------if(first)then! Compute zero of Unix Time in Julian days and savecalld2j([1970,1,1,0,0,0,0,0],julian_at_epoch,ierr)if(ierr.ne.0)return! Errorfirst=.false.endif!-----------------------------------------------------------------------------------------------------------------------------------calld2j(dat,julian,ierr)if(ierr.ne.0)return! Errorunixtime=(julian-julian_at_epoch)*secdayendsubroutine d2u!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================subroutine u2d(dat,unixtime,ierr)! REF:JRH:1991-05-23! REF:JSU:2015-12-12!-----------------------------------------------------------------------------------------------------------------------------------character(len=:),parameter::ident="@(#)u2d(3f): Converts Unix Time to date array"integer,intent(out)::dat(8)! date and time arrayreal(kind=dp),intent(in)::unixtime! Unix time (seconds)integer,intent(out)::ierr! 0 for successful execution, otherwise 1real(kind=dp)::julian! Unix time converted to a Julian datereal(kind=dp),save::Unix_Origin_as_Julian! start of Unix Time as Julian datelogical,save::first=.TRUE.integer::v(8)! date and time array used to get time zone!-----------------------------------------------------------------------------------------------------------------------------------if(first)then! Initialize calculated constants on first callcalld2j([1970,1,1,0,0,0,0,0],Unix_Origin_as_Julian,ierr)! Compute start of Unix Time in Julian daysif(ierr.ne.0)return! Errorfirst=.FALSE.endif!-----------------------------------------------------------------------------------------------------------------------------------calldate_and_time(values=v)! need to get time zonejulian=(unixtime/secday)+Unix_Origin_as_Julian! convert seconds from Unix Epoch to Julian dayscallj2d(dat,julian,ierr)! calculate date array from Julian datedat(4)=v(4)endsubroutine u2d!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================FUNCTIONd2o(dat)RESULT(ordinal)CHARACTER(LEN=:),PARAMETER::ident="@(#)d2o(3f): Converts date-time array to Ordinal day -JSU 2015-12-13"INTEGER,INTENT(IN)::dat(8)! date time array similar to that returned by DATE_AND_TIMEINTEGER::ordinal! the returned number of daysREAL(KIND=dp)::unixtime! Unix time (seconds)REAL(KIND=dp)::unix_first_dayINTEGER::ierr! return 0 on successful, otherwise 1 from d2u(3f)CALLd2u(dat,unixtime,ierr)! convert date to Unix Epoch TimeIF(ierr.NE.0)THENwrite(*,*)'*d2o* bad date array'ordinal=-1! initialize to bad valueELSECALLd2u([dat(1),1,1,dat(4),0,0,0,0],unix_first_day,ierr)ordinal=int((unixtime-unix_first_day)/secday)+1ENDIFENDFUNCTIONd2o!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================FUNCTIONv2mo(imonth)RESULT(month_name)CHARACTER(LEN=:),PARAMETER::ident="@(#)v2mo(3f): returns the month name of a Common month -JSU 2015-12-13"CHARACTER(LEN=:),ALLOCATABLE::month_name! string containing month name or abbreviation.INTEGER,INTENT(IN)::imonth! the number of the month(1-12)CHARACTER(LEN=:),PARAMETER::names(12)=[&&'January ','February ','March ','April ','May ','June ',&&'July ','August ','September','October ','November ','December ']SELECTCASE(imonth)CASE(1:12);month_name=TRIM(names(imonth))CASEDEFAULT;month_name='UNKNOWN'ENDSELECTENDFUNCTIONv2mo!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================FUNCTIONnow(format)CHARACTER(LEN=:),PARAMETER::ident="@(#)now(3f): return string representing current time given format - JSU 2015-10-24"CHARACTER(LEN=*),INTENT(IN),OPTIONAL::formatCHARACTER(LEN=:),ALLOCATABLE::nowINTEGER::values(8)!-----------------------------------------------------------------------------------------------------------------------------------CALLDATE_AND_TIME(VALUES=values)IF(PRESENT(format))THENIF(format.NE.' ')THENnow=fmtdate(values,format)ELSEnow=fmtdate(values,'%Y-%M-%D %h:%m:%s %z')ENDIFELSENOW=fmtdate(values,'%Y-%M-%D %h:%m:%s %z Julian date is %J Epoch time is %E ')ENDIFENDFUNCTIONnow!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================FUNCTIONfmtdate(values,format)RESULT(timestring)! Read the FORMAT string and replace the "%" strings per the following rules:!-----------------------------------------------------------------------------------------------------------------------------------CHARACTER(LEN=:),PARAMETER::ident="@(#)fmtdate(3f): given date array return date as string using format -JSU 2015-10-24 "CHARACTER(LEN=*),INTENT(IN)::format! input format stringINTEGER,DIMENSION(8),INTENT(IN)::values! numeric time values as DATE_AND_TIME(3f) intrinsic returnsCHARACTER(LEN=:),ALLOCATABLE::timestring!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -INTEGER::i10LOGICAL::keyword! flag that previous character was a % characterCHARACTER(LEN=9)::day! day of weekCHARACTER(LEN=1)::chara! character being looked at in format stringCHARACTER(LEN=4096)::text! character arrayINTEGER::ioutINTEGER::weekdayINTEGER::ierrINTEGER,SAVE::called=0LOGICAL,SAVE::since=.FALSE.REAL(KIND=dp)::julianREAL(KIND=dp)::cputimeINTEGER::iiREAL(KIND=dp)::unixtimeREAL(KIND=dp),save::unixtime_lastINTEGER::systemclock,countrateINTEGER::iso_year,iso_week,iso_weekdayCHARACTER(LEN=10)::iso_nameCHARACTER(LEN=2)::dayendtext=' '! write string, when encounter a percent character do a substitutionkeyword=.FALSE.iout=1DOi10=1,LEN(format)chara=format(i10:i10)IF(chara.eq.'%'.and..not.keyword)THENkeyword=.TRUE.CYCLEENDIFIF(keyword)THENkeyword=.FALSE.SELECTCASE(chara)!=====================================================================================CASE('%');WRITE(text(iout:),'(A1)')chara! literal percent character!=====================================================================================CASE('b');WRITE(text(iout:),'(A1)')' '! space character!=====================================================================================CASE('c');CALLcpu_time(cputime)! CPU_TIME()WRITE(text(iout:),'(G0)')cputime!=====================================================================================CASE('C');called=called+1! number of times this routine calledWRITE(text(iout:),'(I0)')called!=====================================================================================CASE('d');! the day of the month 1st..31stdayend=' 'selectcase(values(3))case(1,21,31);dayend='st'case(2,22);dayend='nd'case(3,23);dayend='rd'case(4:20,24:30);dayend='th'casedefaultendselectWRITE(text(iout:),'(I2,a)')values(3),dayend!=====================================================================================CASE('D');WRITE(text(iout:),'(I2.2)')values(3)! the day of the month 1..31!=====================================================================================CASE('e');CALLd2u(values,unixtime,ierr)! integer Unix Epoch time in secondsWRITE(text(iout:),'(G0)')int(unixtime)!=====================================================================================CASE('E');CALLd2u(values,unixtime,ierr)! Unix Epoch time in secondsWRITE(text(iout:),'(G0)')unixtime!=====================================================================================CASE('h');WRITE(text(iout:),'(I2.2)')values(5)! the hour of the day, in the range of 0 to 23!=====================================================================================CASE('H');ii=mod(values(5),12)! hour of day in range 1..12if(ii.eq.0)thenii=12endifWRITE(text(iout:),'(I2.2)')ii!=====================================================================================CASE('i');CALLwoy(values,iso_year,iso_week,iso_weekday,iso_name)! ISO week of yearWRITE(text(iout:),'(I0)')iso_week!=====================================================================================CASE('I');CALLwoy(values,iso_year,iso_week,iso_weekday,iso_name)! iso-8601 Week-numbering year dateWRITE(text(iout:),'(a)')iso_name!=====================================================================================CASE('j');CALLd2j(values,julian,ierr)! integer Julian date (truncated to integer)WRITE(text(iout:),'(I0)')int(julian)!=====================================================================================CASE('J');CALLd2j(values,julian,ierr)! Julian date to millisecondsWRITE(text(iout:),'(I0,".",i3.3)')int(julian),int((julian-int(julian))*1000.0)!=====================================================================================CASE('k');callsystem_clock(count=systemclock,count_rate=countrate)! systemclock/countrateWRITE(text(iout:),'(G0)')real(systemclock)/countrate!=====================================================================================CASE('l');WRITE(text(iout:),'(A3)')v2mo(values(2))! three characters of the name of the month of the year!=====================================================================================CASE('L');WRITE(text(iout:),'(A)')v2mo(values(2))! name of the month of the year!=====================================================================================CASE('m');WRITE(text(iout:),'(I2.2)')values(6)! the minutes of the hour, in the range 0 to 59!=====================================================================================CASE('M');WRITE(text(iout:),'(I2.2)')values(2)! month of year (1..12)!=====================================================================================CASE('N');if(values(5).ge.12)then! AM||PMWRITE(text(iout:),'("PM")')elseWRITE(text(iout:),'("AM")')endif!=====================================================================================CASE('O');WRITE(text(iout:),'(I3.3)')d2o(values)! Ordinal day of year!=====================================================================================CASE('s');WRITE(text(iout:),'(I2.2)')values(7)! the seconds of the minute, in the range 0 to 60!=====================================================================================CASE('S');IF(.NOT.since)THEN! seconds since last calledsince=.TRUE.CALLd2u(values,unixtime_last,ierr)ENDIFCALLd2u(values,unixtime,ierr)WRITE(text(iout:),'(G0)')unixtime-unixtime_lastunixtime_last=unixtime!=====================================================================================CASE('t');WRITE(text(iout:),'(A1)')CHAR(9)! tab character!=====================================================================================CASE('U');CALLdow(values,weekday,day,ierr)! Return the day of the week, 1..7 Sunday=1WRITE(text(iout:),'(I1)')weekday!=====================================================================================CASE('u');CALLdow(values,weekday,day,ierr)! Return the day of the week, 1..7 Monday=1WRITE(text(iout:),'(I1)')mod(weekday+5,7)+1!=====================================================================================CASE('W');CALLdow(values,weekday,day,ierr)! Return the name of the day of the weekWRITE(text(iout:),'(a)')day!=====================================================================================CASE('w');CALLdow(values,weekday,day,ierr)! Return the first three characters of the day of the weekWRITE(text(iout:),'(A3)')day(1:3)!=====================================================================================CASE('x');WRITE(text(iout:),'(I3.3)')values(8)! the milliseconds of the second, in the range 0 to 999!=====================================================================================CASE('Y');WRITE(text(iout:),'(I4.4)')values(1)! the year, including the century (for example, 1990)!=====================================================================================CASE('Z');WRITE(text(iout:),'(SP,I5.4)')values(4)! time difference with respect to UTC in minutes!=====================================================================================CASE('z');WRITE(text(iout:),'(I3.2,":",I2.2)')int(values(4)/60),abs(mod(values(4),60))! time from UTC as +-hh:mm!=====================================================================================CASEDEFAULTWRITE(text(iout:),'(A1)')chara!=====================================================================================ENDSELECT!=====================================================================================iout=len_trim(text)+1ELSEWRITE(text(iout:),'(A1)')chara;iout=iout+1ENDIFENDDOtimestring=trim(text)ENDFUNCTIONfmtdate!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================subroutine fmtdate_usage(ii)character(len=:),parameter::ident="@(#)fmtdate_usage(3f): display macros recognized by fmtdate(3f) - JSU 2015-10-24"character(len=51),allocatable::usage(:)integer::i,iicharacter(len=ii)::blanksusage=[&!date(1) COMMAND&' Base time array: ',&&' (1) %Y -- year, yyyy ',&&' (2) %M -- month of year, 01 to 12 ',&&' (3) %D -- day of month, 01 to 31 ',&&' %d -- day of month, with suffix (1st, 2nd,...)',&&' (4) %Z -- minutes from UTC ',&&' %z -- -+hh:mm from UTC ',&&' (5) %h -- hours, 00 to 23 ',&&' %H -- hour (1 to 12, or twelve-hour clock) ',&&' %N -- AM (before noon) PM (>=after noon) ',&&' (6) %m -- minutes, 00 to 59 ',&&' (7) %s -- sec, 00 to 60 ',&&' (8) %x -- milliseconds 000 to 999 ',&&'Conversions ',&&' %E -- Unix Epoch time ',&&' %e -- integer value of Unix Epoch time ',&&' %J -- Julian date ',&&' %j -- integer value of Julian date ',&&' %O -- Ordinal day (day of year) ',&&' %U -- day of week, 1..7 Sunday=1 ',&&' %u -- day of week, 1..7 Monday=1 ',&&' %i -- ISO week of year 1..53 ',&&' %I -- iso-8601 week-numbering date(yyyy-Www-d)',&&' Names ',&&' %l -- abbreviated month name ',&&' %L -- full month name ',&&' %w -- first three characters of weekday ',&&' %W -- weekday name ',&&' Literals ',&&' %% -- a literal %% ',&&' %t -- tab character ',&&' %b -- blank character ',&&' Program timing: ',&&' %c -- CPU_TIME(3f) output ',&&' %C -- number of times this routine is used ',&&' %k -- time in seconds from SYSTEM_CLOCK(3f) ',&&' ']blanks=' 'WRITE(*,'(a,a)')(blanks(:ii),usage(i),i=1,size(usage))endsubroutine fmtdate_usage!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================subroutine dow(values,weekday,day,ierr)character(len=:),parameter::ident="@(#)dow(3f): Return the day of the week"real(kind=dp)::julian! the julian day for which the weekday is required,integer,intent(in)::values(8)! date and time array used to get time zoneinteger,intent(out),optional::weekday! The day of the week, 1 = Sundaycharacter*(*),intent(out),optional::day! The name of the day of the week, e.g. 'Sunday'. Minimum length = 9integer,intent(out)::ierr! Error return,0=correct,-1=invalid Julian day,-2=neither day nor weekday specifiedinteger::iweekdaycalld2j(values,julian,ierr)! need julian date to calculate day of week for first day of monthierr=0if(julian<0)thenierr=-1returnendifif(.not.present(day).and. .not.present(weekday))thenierr=-2returnendif! julian day starts at noon so add 1/2 day! add time zoneiweekday=mod(int((julian+dble(values(4)/60.0d0/24.0d0)+0.5d0)+1.0d0),7)iweekday=iweekday+1if(present(day))thenselectcase(iweekday)case(1);day='Sunday'case(2);day='Monday'case(3);day='Tuesday'case(4);day='Wednesday'case(5);day='Thursday'case(6);day='Friday'case(7);day='Saturday'casedefault;day='E-R-R-O-R'endselectendifif(present(weekday))thenweekday=iweekdayendifendsubroutine dow!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================subroutine woy(dat,iso_year,iso_week,iso_weekday,iso_name)!-----------------------------------------------------------------------------------------------------------------------------------! The ISO-8601 date and time standard was issued by the International Organization for Standardization (ISO).! It is used (mainly) in government and business for fiscal years, as well as in timekeeping.! The system specifies a week year atop the Gregorian calendar by defining a notation for ordinal weeks of the year.!! An ISO week-numbering year (also called ISO year informally) has 52 or 53 full weeks.! That is 364 or 371 days instead of the usual 365 or 366 days.! The extra week is referred to here as a leap week, although ISO 8601 does not use this term.! Weeks start with Monday.! The first week of a year is the week that contains the first Thursday of the year (and, hence, always contains 4 January).! ISO week year numbering therefore slightly deviates from the Gregorian for some days close to 1 January.!-----------------------------------------------------------------------------------------------------------------------------------!CALCULATION:! The ISO-8601 week number of any date can be calculated, given its ordinal date (i.e. position within the year)! and its day of the week.!METHOD:! Using ISO weekday numbers (running from 1 for Monday to 7 for Sunday),! subtract the weekday from the ordinal date, then add 10. Divide the result! by 7. Ignore the remainder; the quotient equals the week number. If! the week number thus obtained equals 0, it means that the given date! belongs to the preceding (week-based) year. If a week number of 53 is! obtained, one must check that the date is not actually in week 1 of the! following year.! These two statements are assumed true when correcting the dates around January 1st ...! o The number of weeks in a given year is equal to the corresponding week number of 28 December.! o January 4th is always in the first week.!!ISO_NAME:! Week date representations are in the format YYYYWww-D.! o [YYYY] indicates the ISO week-numbering year which is slightly different from the traditional Gregorian calendar year.! o [Www] is the week number prefixed by the letter W, from W01 through W53.! o [D] is the weekday number, from 1 through 7, beginning with Monday and ending with Sunday.!! For example, the Gregorian date 31 December 2006 corresponds to the Sunday of the 52nd week of 2006, and is written! 2006-W52-7 (extended form)! or 2006W527 (compact form).!!REFERENCE:! From Wikipedia, the free encyclopedia 2015-12-19!AUTHOR:! John S. Urban, 2015-12-19!-----------------------------------------------------------------------------------------------------------------------------------character(len=:),parameter::ident="@(#)woy(3f): Calculate iso-8601 Week-numbering year date yyyy-Www-d"integer,parameter::dp=kind(0.0d0)integer,intent(in)::dat(8)! input date arrayinteger,intent(out)::iso_year,iso_week,iso_weekdaycharacter(len=10),intent(out)::iso_nameinteger::shared_weekdayinteger::last_week_this_yearinteger::dec28_lastyear(8)! December 28th is always in last weekinteger::dec28_thisyear(8)! December 28th is always in last weekcharacter(len=9)::dayinteger::ierriso_year=dat(1)! initially assume the iso_year is the same as the data array yeariso_week=uncorrected_week_of_year(dat)! this is the week number unless around January 1stiso_weekday=shared_weekday! this is the number of the day of the week assuming Monday=1dec28_thisyear=[dat(1),12,28,dat(4),0,0,0,0]! Dec 28th is always in last week; use this to get number of weekslast_week_this_year=uncorrected_week_of_year(dec28_thisyear)! get the number of the last week of the year (52 or 53)! correct dates around January 1stif(iso_week<1)then! if week < 1 then week = lastWeek(year -1)dec28_lastyear=[dat(1)-1,12,28,dat(4),0,0,0,0]! Dec 28th is always in last week, we want its week numberiso_week=uncorrected_week_of_year(dec28_lastyear)! got the week number for the last week of last year (52 or 53)iso_year=dat(1)-1! our date belongs to last yearelseif(iso_week>last_week_this_year)then! if week > lastweek(year) then week = 1iso_week=iso_week-last_week_this_year! our date belongs to next yeariso_year=dat(1)+1endifwrite(iso_name,'(i4.4,"-W",i2.2,"-",i1)')iso_year,iso_week,iso_weekday! create ISO string designation for our datecontainsfunction uncorrected_week_of_year(datin)implicitnoneinteger::uncorrected_week_of_yearinteger,intent(in)::datin(8)integer::ordinalcalldow(datin,shared_weekday,day,ierr)! formula needs day of week 1..7 where Monday=1shared_weekday=mod(shared_weekday+5,7)+1! change from Sunday=1 to Monday=1ordinal=d2o(datin)! formula needs ordinal day of year where Jan 1st=1uncorrected_week_of_year=(ordinal-shared_weekday+10)/7endfunction uncorrected_week_of_yearendsubroutine woy!-----------------------------------------------------------------------------------------------------------------------------------!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================function dj(dat)result(julian)character(len=:),parameter::ident="@(#)dj(3f): Given date array returns Julian Day"real(kind=dp)::julianinteger,intent(in)::dat(8)integer::ierrcalld2j(dat,julian,ierr)endfunction djfunction jd(julian)result(dat)character(len=:),parameter::ident="@(#)jd(3f): Given Julian Day returns date array"real(kind=dp),intent(in)::julianinteger::dat(8)integer::ierrcallj2d(dat,julian,ierr)endfunction jdfunction du(dat)result(unixtime)character(len=:),parameter::ident="@(#)du(3f): Given date array returns Unix Epoch time "real(kind=dp)::unixtimeinteger,intent(in)::dat(8)integer::ierrcalld2u(dat,unixtime,ierr)endfunction dufunction ud(unixtime)result(dat)character(len=:),parameter::ident="@(#)ud(3f): Given Unix Epoch Time returns date array"real(kind=dp),intent(in)::unixtimeinteger::dat(8)integer::ierrcallu2d(dat,unixtime,ierr)endfunction ud!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================!! XXXX! X X! X! X! X! X! X! X X! XXXX!subroutine sys_sleep(wait_seconds)use,intrinsic::iso_c_binding,only:c_intcharacter(len=:),parameter::ident="@(#)sys_sleep(3f): call sleep(3c)"integer(c_int)::wait_seconds,how_longinterfacefunction c_sleep(seconds)bind(C,name="sleep")importinteger(c_int)::c_sleep! should be unsigned int (not available in Fortran). OK until highest bit gets set.integer(c_int),intent(in),VALUE::secondsendfunction c_sleependinterfaceif(wait_seconds.gt.0)thenhow_long=c_sleep(wait_seconds)endifendsubroutine sys_sleep!===================================================================================================================================!()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()!!===================================================================================================================================endmodule m_time

Photran is an IDE and refactoring tool for Fortran based on Eclipse. Photran supports Fortran 77-2008 and is actively maintained with annual releases. It includes 39 refactorings (including Rename, Extract Procedure, and loop transformations), as well as the many IDE features.

Code::Blocks IDE for Fortran http://cbfortran.sourceforge.net/: Recommended! Originally developed for C++, this advanced IDE has many features of eclipse and supports most features of Fortran 2003 and 2008. The environment is quite user friendly and easy to use. It is one of the few true IDEs for Fortran. I think the support of the Fortran community will help this IDE to become a very powerful general purpose and fast Fortran programming tool.

Jedit - written in Java - when opening more than one file this has no tabs but a drop-down list at the top, which I find less convenient. But it has good Fortran90 aware syntax highlighting (I had to make a small change to the configuration file to prevent every line starting with C being treated as a comment, but that was not difficult). But the print system is a Java-special, not using the regular Windows print menu, so you can’t alter your printer defaults, e.g. to print 2 pages per sheet of paper. This is an annoyance.

Gedit - there is a windows binary to download which worked with no trouble, but there is no manual and no help (missing file). The syntax highlighting did work for Fortran90, but it did not understand the .f90 or .f95 file extension, and had to be set each time, which was very tedious. I could not find the relevant file on the website, nor when I untarred a regular gedit distribution. Looking at the help on a Linux box there did not seem to be a way of associating file extensions with language highlighting.

Notepad++ - has tabbed browsing, and uses regular Windows printing, but the syntax highlighting was set for Fortran77, and was really not useful. After being annoyed by it for some time, I found it best to disable the highlighting entirely. In principle one could define one’s own Fortran90 syntax file, but I couldn’t be bothered to do this. Apart from this it’s a fairly good editor.

Notetab light - the free version of a commercial editor notetab. This is another adequate editor: regular Windows printing, no tabbed file opening, no syntax highlighting. It seems to have no particular features that at least one of the others has.

Geany(http://www.geany.org/): This is a free open source editor with many capabilities which also supports programming in Fortran. There are several plugins to deal with project management, debugging etc. The editor lets you for extensive customization for a programming language and even adding new one! It is available for both Windows and Linux.

Simply Fortran(http://simplyfortran.com/): lightweight IDE for MS Windows and compatible operating systems. Made with GNU Fortran in mind, but configurable with most compilers, it comes with an intergrated development environment, a graphical debugger, and a collection of other development accessories. In early stages of development as of now, has some bugs, but the author’s working on them.

Programmer’s Notepad - A general source code editor for MS Windows. It can be configured to build Fortran files with arbitrary command lines, or to invoke make in a particular directory. Like many editors, it is C-centric, but the Fortran support is adequate.

Absoft Pro Fortran - A IDE developed by Absoft specially for Fortran. http://www.absoft.com/

FTranProjectBuilder - Fortran specific development environment for the Mac with built-in source code editor, makefile generator, and lab notebook. It’s Mac-native, self configuring and works with any Fortran compiler, including mpiXX for parallel computations. Fortran 2003+ features include variable and type bound procedure auto-completions. http://www.NocturnalAviationSoftware.com

UltraEdit - General source code editor for multiple languages with syntax checking. http://www.ultraedit.com. Runs on Mac, Linux and Windows 32 and 64 bit. There is a companion product called UltraCompare which allows one to compare files. Syntax checking is acheived through what the vendor calls word files. The vendor has a fairly good size library of wordfiles, but you can create your own if you wish. The Product also allows the developer to organize their work in a project fashion. Support for ftp,sftp, etc. Also allows column editing mode. I have been developing for decades and find this tool to be the best on the market when it comes to editors. Not a free product.

An enhanced Vim syntax file that includes Fortran 2003 keywords is available here:

findent indents fortran source, both fixed and free format. Conversion from fixed to free is also possible. Available for Linux and Windows. Plugins for vim and gedit are contained in the tarball at findent.sourceforge.net

This page is for linking to available Fortran libraries and source code repositories. See Software repositories for collections of libraries and see Library distribution? for methods for packaging and distributing Fortran libraries.

Libraries linked here are classified as follows:

(PD) public domain (e.g., software written by the U.S. government)

(OS) free and open source software (GPL, LGPL, BSD, and similar licenses)

qContainers is a container library for Fortran language. It enables to store any internal Fortran data type and any derived data type to the container. It implements containers for key/value pairs: tree table and hash table, and containers for objects: list and vector. (OS: BSD)

FMLIB, David M. Smith’s libraries for multiple precision computation. The package performs multiple-precision real, complex, and integer arithmetic, providing the intrinsic Fortran numerical functions, as well as many special functions. An existing Fortran program can be checked by converting it from double precision to FM arithmetic. (NC)

g2 is an easy to use, portable and powerful 2D graphics library. Currently supported devices: PostScript, X11, PNG and JPEG (using gd) and Win32 (xfig in development). g2 is written in C (ANSI) and has a Fortran interface. (OS: LGPL)

Lib_VTK_IO a pure Fortran library to write and read data conforming the VTK standard. This library is not a porting or a wrapper of the VTK code, but it is only an exporter/importer of VTK data format written in pure Fortran language (standard Fortran 2003). (OS: GPL)

C-library Interfaces

System

fortranposix - An implementation of some POSIX functions in Fortran 90/95. (OS: LGPL)

fortyxima/filesys - Modern Fortran wrappers around the file system interface of libc as part of the Fortyxima library: rename and remove files, recursively create and remove directories, obtain filenames in a directory, check whether a given file exists and if a directory or a symbolic link, obtain the current working directory and change to a directory, create hard links and symbolic links, resolve the target of symbolic links, canonize path names. Fortyxima/filesys replaces the old modfilesys library. (OS: BSD)

write a program in OO Fortran that uses two classes I.e class_circle and class_rectangle. each class must have its own data types and specifications to define the objects and functionalities to compute their respective areas