Redirecting unit * to a file

I would like to have a program read from standard in by default or from a file if a specified. I have thought about using unit 5 for input, which I can redirect to a file in an open statement, but I understand 5 isn’t designated as standard input by the Fortran standard. Is that really a problem? Am I likely to run in to users where unit 5 is not standard in? I mean, someone with a Linux, WIndows or Mac machine. I don’t care about anything older than f2c. The program is used by random unsophisticated users, I’d like to put the redirection in the program rather than rely on a shell script I would have to explain.

As it is, the best I can think of to do that fits the standard is to replace each read statement with 2 read statements, one with a * and one with a unit number. Is that the best I can do?

I notice that some compilers such as
Oracle Fortran allow a * in the open statement:

[UNIT=] u

  • u is an integer expression or an asterisk (*) that specifies the unit number. u is required

but does that modify read or write statements? I suppose it doesn’t matter, since so few compilers support this. Still, it seems odd if there is no way to redirect unit *.

1 Like

Why not use input_unit from module ISO_FORTRAN_ENV of Fortran 2003?

1 Like

If you have not used INPUT_UNIT before, here is an example that reads one line from stdin
and echoes it unless a filename is given on the command line, in which case that file is read from instead. This assumes your input file is a text file; reading binary files from stdin is problematic.

program readfrom
use,intrinsic :: iso_fortran_env, only : &
 & stdin=>input_unit, &
 & stdout=>output_unit,&
 & stderr=>error_unit
implicit none
integer                      :: count, argument_length, lun, ios
character(len=:),allocatable :: filename
character(len=256)           :: line, msg
   ! get number of arguments
   count = command_argument_count()
   if(count.ne.0)then
       call get_command_argument(number=1,length=argument_length)
       ! allocate string array big enough to hold command line argument 
       allocate(character(len=argument_length) :: filename)
       call get_command_argument(1, filename)
       open(file=filename,newunit=lun)
   else
       lun=stdin
   endif
   read(lun,'(a)',iostat=ios,iomsg=msg)line
   if(ios.eq.0)then
      write(*,*)'READ  :',trim(line)
   else
      write(*,*)'<ERROR>',trim(msg)
   endif

end program readfrom`

so if you entered “readfrom myfile” it would read the first line of file “myfile”; otherwise it would
read a line from stdin. You do not have to rename the variables, but I prefer the names stdin, stdout, and stderr myself.

Thanks. Another demonstration that there is no problem in computer science that can not be solved with an additional level of indirection.

If you are using Intel Fortran and the ISO_FORTRAN_ENV constants, be sure to compile with -standard-semantics. If you don’t, the compiler will use various negative unit numbers for unit * (or PRINT).

1 Like

Would that make any difference in a program like above @urbanjost’s sample?

No - my comment related to @feenberg 's mention of unit *, which is part of the standard language. Specifically, if you expected to open unit INPUT_UNIT and then do READ(*) and have that be the unit you opened, it would not work in Intel Fortran without the standard-semantics option (or -assume noold_unit_star)