Format string corresponding to list-directed I/O

I suggest that Fortran add a format string that is equivalent to list-directed I/O. Sometimes I pass a format string, often an optional argument, to a subroutine to use in write statements within it. It would be convenient if there were a format string corresponding to list-directed output or input, so that the following two lines were equivalent:

write (*,"*") a,b
write (*,*) a,b

Currently I need to write

if (fmt == "*") then
   write (*,*) a,b
else
   write (*,fmt) a,b
end if

which is more verbose than just a line

write (*,fmt) a,b

which handles the case of fmt="*". In a program, sometimes the format string is wrong, because it does not match the types of the variables written, or inappropriate, because it does not fit the magnitudes of the data written (for example f5.2 for a float such as 100000.00). Being able to replace the format string, which may read from an input file, with * to get list-directed output would ease debugging.

Why use F5.2 if there is is risk of overflow we have F0.2 or G formats? ‘*’ format is a but wishy washy as it is “processor dependant”

I use f0.2 for a CSV file, but for output written to the screen or to a file that I will open in a text editor, a format such as f0.2 results in columns of data that are not aligned, since the output width depends on the magnitude of the number printed. Is there a way to write a number with the format f8.2 but to switch to e8.2 if f8.2 is not large enough (other than coding this logic explicitly)? This would be preferable to just seeing ********.

Well I have a few utility functions that take a real input and some optional args and returns an allocatable string. I often then concatenate strings in output lists and thus encapsulate all the formatting logic in my function(s). Thus I can add the annoyingly missing zero in 0.123 and other such things as needed. +0 and -0 is another such annoyance.

I would say this is what G format is for - it can handle all intrinsic types. You can use “(*(G0.2),1X)” and handle just about anything.

Thanks. The g format, which I am not in the habit of using, does what I want for CSV files, but for data written to the screen, decimal points for floating point numbers are not aligned, so I need to use the f format. With gfortran and Intel Fortran the program

write (*,"(*(g0.4,','))")       10,1.2345,"dog",.true.
write (*,"(*(g0,','))")         10,1.2345,"dog",.true.
write (*,"(*(a10))") "int","real","char","logical"
write (*,"(*(g10.4))")          10,1.2345,"dog",.true.
write (*,"(*(g10.4))")          1000,123.2345,"canine",.true.
write (*,"(i10,f10.4,a10,l10)") 10,1.2345,"dog",.true.
write (*,"(i10,f10.4,a10,l10)") 1000,123.2345,"canine",.true.
end

gives output

10,1.235,dog,T,
10,1.23450005,dog,T,
       int      real      char   logical
        10 1.235           dog         T
      1000 123.2        canine         T
        10    1.2345       dog         T
      1000  123.2345    canine         T

If alignment and specific values of w and d are what you need, then a list-directed format isn’t going to be appropriate. As you are aware, each implementation gets wide latitude on formatting there.

write (,"((g0.4,:,‘,’))") 10,1.2345,“dog”,.true.
The magic “:” in the format gets rid of that trailing comma that hurts my eyes.

2 Likes

I would second two of Steve’s comments - G format is pretty powerful, and list-directed output will not necessarily look the same from one vendor to the next.

I you want to propose a new syntax and corresponding semantics, I would avoid * as that already has use in formats and overloading it could be confusing. Perhaps a new edit descriptor, LD, would work. So “(LD)” as the format would behave the same as list-directed.

1 Like

I have long wanted this capability too, going back even to f77 days. My main use is for data files that are written in the general form

cfmt
…data list…
cfmt
…data list…

I would like to simply read the format string and then use that format string to read the following data block.

read(nin,’(a)’) cfmt
read(nin,cfmt) …data list…

If the data are written in fixed columns, then a fixed width format is appropriate, especially when the data items are not separated with spaces or commas. Otherwise, list directed input is appropriate, but the above simple approach does not work because there is no cfmt format string that naturally triggers ldio. So instead, the above if-else-endif block is required to select the appropriate read statement. The last I checked, there was no g0/i0/f0 type format that would work either, although I have not kept up with the latest fortran standard revisions, so maybe this had been recently addressed? The annoyance is exacerbated because different combinations of data types require separate if-else-endif blocks, it cannot be localized within a single subroutine.

1 Like

Thanks @RonShepard for explaining how a list-directed format string could be used for READ. The idea has been submitted to the Fortran proposals github repository with the “(LD)” syntax.