Clarification: should namelist-group-name start in column one or column two on output?

When NAMELIST group outputs from various platforms is compared to section (13.11.4.3) of the standard it seems that many begin the namelist-group-name in column two. Lines 7-9 imply the namelist-group-name should start in column 1 but lines 11-12 seem contradictory because taken by themselves they unconditionally state output should begin past column one, unless 7-9 supercedes 11-12.

So for clarification does 11-12 only refer to subsequent lines following the line containing the namelist-group-name (see gfortran output) or does 11-12 apply to all output lines?

There are a lot of other issues with NAMELIST output on many platforms I would like to get to reporting but this seems like an easy one to conform to if clarified.

     13.11.4.3  Namelist output records

      2      If two or more successive values for the same namelist-group-object in an output record produced have identical
      3      values, the processor has the option of producing a repeated constant of the form r*c instead of the sequence of
      4      identical values.

      5      The name of each namelist-group-object is placed in the output record followed by an equals and a list of values
      6      of that namelist-group-object.

      7      An ampersand character followed immediately by a namelist-group-name is placed at the start of the first output
      8      record to indicate which particular group of data objects is being output. A slash is placed in the output record
      9      to indicate the end of the namelist formatting.

     10      A null value is not produced by namelist formatting.

     11      Except for new records created by explicit formatting within a defined output procedure or by continuation of
     12      delimited character sequences, each output record begins with a blank character.

Before NAMELIST was standardized several implementations required &NAME to begin in column 1 on input, so that seemed like the likely interpretation but the standardized version seems quite liberal about whitespace on input, so the requirement that the output of intrinsics except for character variables (when DELIM=‘NONE’) be readable as input does not clarify whether column 1 must always be clear on output or not.

Split strings appear to unconditionally use column 1 and defined output for user types appears to be able to optionally use it so it does not appear there was an attempt to keep column 1 completely clear, which makes it even less clear what the requirement is in my mind.

&NAMELIST-GROUP-NAME ...
 NAME=VALUE
 NAME=VALUE
 /

or

 &NAMELIST-GROUP-NAME ...
 NAME=VALUE
 NAME=VALUE
 /

Fortran source

click to see more...
program nml_quotes_bug
use, intrinsic :: iso_fortran_env, only : stderr=>ERROR_UNIT, stdout=>OUTPUT_UNIT
implicit none
integer,parameter  :: unit = 10
character(len=256) :: iomsg
character(len=20)  :: msg
integer            :: iostat
integer            :: i
integer            :: ints(100)
namelist /nums/ msg, ints
character(len=*),parameter :: g='(*(g0))'
character(len=80)  :: delim
integer            :: recl
character(len=*),parameter :: file(*)=[ character(len=132) :: &
'  step                                                    ', &
'&nums msg="step",ints=8*0,ints(1:8:2)=1,3,5,7 /           ', &
'  negative step                                           ', &
'&nums msg="negative step",ints=8*0,ints(8:1:-2)=1,3,5,7 / ', &
' ' ]

   inquire(unit=stdout,delim=delim,recl=recl)
   write(stdout,g)'DELIM:',trim(delim),':RECL:',recl

   !open (unit=stdout ,delim="quote" ) ! APOSTROPHE, QUOTE, or NONE
   !inquire(unit=stdout,delim=delim,recl=recl)
   !write(stdout,g)'DELIM:',trim(delim),':RECL:',recl

   open (unit ,file="tst.nml" )
   write(unit,'(a)')(trim(file(i)),i=1,size(file))
   rewind(unit)

   do i=1,huge(0)-1
      write(stdout,g)repeat('1234567890',10)
      write(stdout,g)'case',i,' ',repeat('=',79)
      ints=(-1)-huge(0)
      read (unit ,nml=nums,end=999,iomsg=iomsg,iostat=iostat)
      if(iostat.ne.0)then
         write(stdout,g)'<ERROR>',trim(iomsg)
      else
         write(stdout,nml=nums)
         msg='delimiter: '''
         write(stdout,nml=nums,delim='apostrophe')
         msg='delimiter: "'
         write(stdout,nml=nums,delim='quote')
         msg='delimiter: none'
         write(stdout,nml=nums,delim='none')
      endif
   enddo
   999 continue
   close(unit ,status="delete")
   stop 'That''s all Folks!'
end program nml_quotes_bug

compiler aoccflang520

  • NAMELIST-GROUP_OBJECT STARTS IN COLUMN 2
  • DOES NOT ALLOW NEGATIVE SUBSCRIPTS
  • ERROR MESSAGE IS PADDED WITH NULLS
click to see output...
++ cexpl -c aoccflang520 --skip-asm '--cflags=-cpp -DCOMPILER_=aoccflang520' -e simple.f90
aoccflang520         :     1	STDOUT:
aoccflang520         :     2	DELIM:NONE:RECL:0
aoccflang520         :     3	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
aoccflang520         :     4	case1 ===============================================================================
aoccflang520         :     5	 &NUMS
aoccflang520         :     6	 MSG = step                ,
aoccflang520         :     7	 INTS =            1,
aoccflang520         :     8	                   0,
aoccflang520         :     9	                   3,
aoccflang520         :    10	                   0,
aoccflang520         :    11	                   5,
aoccflang520         :    12	                   0,
aoccflang520         :    13	                   7,
aoccflang520         :    14	                   0,
aoccflang520         :    15	         -2147483648,
aoccflang520         :    16	         -2147483648,
aoccflang520         :    17	         -2147483648,
aoccflang520         :    18	         -2147483648,
aoccflang520         :    19	         -2147483648,
                                   :
                                   :
aoccflang520         :   105	         -2147483648,
aoccflang520         :   106	         -2147483648
aoccflang520         :   107	 /
aoccflang520         :   108	 &NUMS
aoccflang520         :   109	 MSG = 'delimiter: ''        ',
aoccflang520         :   110	 INTS =            1,
aoccflang520         :   111	                   0,
aoccflang520         :   112	                   3,
aoccflang520         :   113	                   0,
aoccflang520         :   114	                   5,
aoccflang520         :   115	                   0,
aoccflang520         :   116	                   7,
aoccflang520         :   117	                   0,
aoccflang520         :   118	         -2147483648,
aoccflang520         :   119	         -2147483648,
                                   :
                                   :
aoccflang520         :   208	         -2147483648,
aoccflang520         :   209	         -2147483648
aoccflang520         :   210	 /
aoccflang520         :   211	 &NUMS
aoccflang520         :   212	 MSG = "delimiter: ""        ",
aoccflang520         :   213	 INTS =            1,
aoccflang520         :   214	                   0,
aoccflang520         :   215	                   3,
aoccflang520         :   216	                   0,
aoccflang520         :   217	                   5,
aoccflang520         :   218	                   0,
aoccflang520         :   219	                   7,
aoccflang520         :   220	                   0,
aoccflang520         :   221	         -2147483648,
aoccflang520         :   222	         -2147483648,
aoccflang520         :   223	         -2147483648,
                                   :
                                   :
aoccflang520         :   311	         -2147483648,
aoccflang520         :   312	         -2147483648
aoccflang520         :   313	 /
aoccflang520         :   314	 &NUMS
aoccflang520         :   315	 MSG = delimiter: none     ,
aoccflang520         :   316	 INTS =            1,
aoccflang520         :   317	                   0,
aoccflang520         :   318	                   3,
aoccflang520         :   319	                   0,
aoccflang520         :   320	                   5,
aoccflang520         :   321	                   0,
aoccflang520         :   322	                   7,
aoccflang520         :   323	                   0,
aoccflang520         :   324	         -2147483648,
aoccflang520         :   325	         -2147483648,
                                   :
                                   :
aoccflang520         :   415	         -2147483648
aoccflang520         :   416	 /
aoccflang520         :   417	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
aoccflang520         :   418	case2 ===============================================================================
aoccflang520         :   419	<ERROR>illegal subscript or substring specification^@^@^@^@^@^@^@^@^@^@^@^@^@^
aoccflang520         :   420	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
aoccflang520         :   421	case3 ===============================================================================
aoccflang520         :   422	STDERR:
aoccflang520         :   423	That's all Folks!

compiler flangtrunk

  • NAMELIST-GROUP_OBJECT STARTS IN COLUMN 2
click to see output...
++ cexpl -c flangtrunk --skip-asm --cflags= -e simple.f90
flangtrunk           :     1	STDOUT:
flangtrunk           :     2	DELIM:NONE:RECL:2147483647
flangtrunk           :     3	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
flangtrunk           :     4	case1 ===============================================================================
flangtrunk           :     5	 &NUMS MSG= step                ,INTS= 1 0 3 0 5 0 7 0 -2147483648 -2147483648
flangtrunk           :     6	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
                                   :
                                   :
flangtrunk           :    19	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    20	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648/
flangtrunk           :    21	 &NUMS MSG= 'delimiter: ''        ',INTS= 1 0 3 0 5 0 7 0 -2147483648
flangtrunk           :    22	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
                                   :
                                   :
flangtrunk           :    36	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    37	 -2147483648/
flangtrunk           :    38	 &NUMS MSG= "delimiter: ""        ",INTS= 1 0 3 0 5 0 7 0 -2147483648
flangtrunk           :    39	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    40	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
                                   :
                                   :
flangtrunk           :    53	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    54	 -2147483648/
flangtrunk           :    55	 &NUMS MSG= delimiter: none     ,INTS= 1 0 3 0 5 0 7 0 -2147483648 -2147483648
flangtrunk           :    56	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    57	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
                                   :
                                   :
flangtrunk           :    69	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    70	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648/
flangtrunk           :    71	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
flangtrunk           :    72	case2 ===============================================================================
flangtrunk           :    73	 &NUMS MSG= negative step       ,INTS= 0 7 0 5 0 3 0 1 -2147483648 -2147483648
flangtrunk           :    74	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    75	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
                                   :
                                   :
flangtrunk           :    87	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    88	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648/
flangtrunk           :    89	 &NUMS MSG= 'delimiter: ''        ',INTS= 0 7 0 5 0 3 0 1 -2147483648
flangtrunk           :    90	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :    91	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
                                   :
                                   :
flangtrunk           :   104	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :   105	 -2147483648/
flangtrunk           :   106	 &NUMS MSG= "delimiter: ""        ",INTS= 0 7 0 5 0 3 0 1 -2147483648
flangtrunk           :   107	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :   108	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
                                   :
                                   :
flangtrunk           :   121	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :   122	 -2147483648/
flangtrunk           :   123	 &NUMS MSG= delimiter: none     ,INTS= 0 7 0 5 0 3 0 1 -2147483648 -2147483648
flangtrunk           :   124	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :   125	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
                                   :
                                   :
flangtrunk           :   137	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648
flangtrunk           :   138	 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648 -2147483648/
flangtrunk           :   139	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
flangtrunk           :   140	case3 ===============================================================================
flangtrunk           :   141	STDERR:
flangtrunk           :   142	Fortran STOP: That's all Folks!

compiler fppc64g9

click to see output...
++ cexpl -c fppc64g9 --skip-asm '--cflags=-cpp -DCOMPILER_=fppc64g9' -e simple.f90

compiler fppc64leg9

click to see output...
++ cexpl -c fppc64leg9 --skip-asm '--cflags=-cpp -DCOMPILER_=fppc64leg9' -e simple.f90

compiler ifxlatest

  • NAMELIST-GROUP_OBJECT STARTS IN COLUMN 2
click to see output...
++ cexpl -c ifxlatest --skip-asm '--cflags=-fpp -warn all -check all,nouninit -error-limit 1 -O0 -g -assume byterecl -traceback -DCOMPILER_=ifxlatest' -e simple.f90
ifxlatest            :     1	STDOUT:
ifxlatest            :     2	DELIM:NONE:RECL:132
ifxlatest            :     3	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
ifxlatest            :     4	case1 ===============================================================================
ifxlatest            :     5	 &NUMS
ifxlatest            :     6	 MSG     = step                ,
ifxlatest            :     7	 INTS    =           1,           0,           3,           0,           5,           0,           7,           0,
ifxlatest            :     8	  92*-2147483648
ifxlatest            :     9	 /
ifxlatest            :    10	 &NUMS
ifxlatest            :    11	 MSG     = 'delimiter: ''        ',
ifxlatest            :    12	 INTS    =           1,           0,           3,           0,           5,           0,           7,           0,
ifxlatest            :    13	  92*-2147483648
ifxlatest            :    14	 /
ifxlatest            :    15	 &NUMS
ifxlatest            :    16	 MSG     = "delimiter: ""        ",
ifxlatest            :    17	 INTS    =           1,           0,           3,           0,           5,           0,           7,           0,
ifxlatest            :    18	  92*-2147483648
ifxlatest            :    19	 /
ifxlatest            :    20	 &NUMS
ifxlatest            :    21	 MSG     = delimiter: none     ,
ifxlatest            :    22	 INTS    =           1,           0,           3,           0,           5,           0,           7,           0,
ifxlatest            :    23	  92*-2147483648
ifxlatest            :    24	 /
ifxlatest            :    25	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
ifxlatest            :    26	case2 ===============================================================================
ifxlatest            :    27	 &NUMS
ifxlatest            :    28	 MSG     = negative step       ,
ifxlatest            :    29	 INTS    =           0,           7,           0,           5,           0,           3,           0,           1,
ifxlatest            :    30	  92*-2147483648
ifxlatest            :    31	 /
ifxlatest            :    32	 &NUMS
ifxlatest            :    33	 MSG     = 'delimiter: ''        ',
ifxlatest            :    34	 INTS    =           0,           7,           0,           5,           0,           3,           0,           1,
ifxlatest            :    35	  92*-2147483648
ifxlatest            :    36	 /
ifxlatest            :    37	 &NUMS
ifxlatest            :    38	 MSG     = "delimiter: ""        ",
ifxlatest            :    39	 INTS    =           0,           7,           0,           5,           0,           3,           0,           1,
ifxlatest            :    40	  92*-2147483648
ifxlatest            :    41	 /
ifxlatest            :    42	 &NUMS
ifxlatest            :    43	 MSG     = delimiter: none     ,
ifxlatest            :    44	 INTS    =           0,           7,           0,           5,           0,           3,           0,           1,
ifxlatest            :    45	  92*-2147483648
ifxlatest            :    46	 /
ifxlatest            :    47	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
ifxlatest            :    48	case3 ===============================================================================
ifxlatest            :    49	STDERR:
ifxlatest            :    50	That's all Folks!

compiler lfortran0590

  • RUNTIME ERROR (NAMELIST probably not supported yet?)
click to see output...
++ cexpl -c lfortran0590 --skip-asm '--cflags=--no-style-suggestions --cpp -DCOMPILER_=lfortran0590' -e simple.f90
lfortran0590         :     1	STDOUT:
lfortran0590         :     2	DELIM:
lfortran0590         :     3	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
lfortran0590         :     4	case1 ===============================================================================
lfortran0590         :     5	STDERR:
lfortran0590         :     6	warning: `--generate-object-code` is deprecated and will be removed in a future release; use `--separate-compilation` instead.
lfortran0590         :     7	warning: `--generate-object-code` is deprecated and will be removed in a future release; use `--separate-compilation` instead.
lfortran0590         :     8	Runtime Error: Format mismatch between OPEN statement and WRITE statement on unit 6.

compiler nvfortran_x86_26_3

  • NAMELIST-GROUP_OBJECT STARTS IN COLUMN 2
  • DOES NOT ALLOW NEGATIVE SUBSCRIPTS
  • ERROR MESSAGE IS PADDED WITH NULLS
click to see output...
++ cexpl -c nvfortran_x86_26_3 --skip-asm '--cflags=-Mbackslash -Mpreprocess -DCOMPILER_=nvfortran_x86_26_3' -e simple.f90
nvfortran_x86_26_3   :     1	STDOUT:
nvfortran_x86_26_3   :     2	DELIM:NONE:RECL:-1438808240
nvfortran_x86_26_3   :     3	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
nvfortran_x86_26_3   :     4	case1 ===============================================================================
nvfortran_x86_26_3   :     5	 &NUMS
nvfortran_x86_26_3   :     6	 MSG = step                ,
nvfortran_x86_26_3   :     7	 INTS =            1,
nvfortran_x86_26_3   :     8	                   0,
nvfortran_x86_26_3   :     9	                   3,
nvfortran_x86_26_3   :    10	                   0,
nvfortran_x86_26_3   :    11	                   5,
nvfortran_x86_26_3   :    12	                   0,
nvfortran_x86_26_3   :    13	                   7,
nvfortran_x86_26_3   :    14	                   0,
nvfortran_x86_26_3   :    15	         -2147483648,
nvfortran_x86_26_3   :    16	         -2147483648,
                                   :
                                   :
nvfortran_x86_26_3   :   105	         -2147483648,
nvfortran_x86_26_3   :   106	         -2147483648
nvfortran_x86_26_3   :   107	 /
nvfortran_x86_26_3   :   108	 &NUMS
nvfortran_x86_26_3   :   109	 MSG = 'delimiter: ''        ',
nvfortran_x86_26_3   :   110	 INTS =            1,
nvfortran_x86_26_3   :   111	                   0,
nvfortran_x86_26_3   :   112	                   3,
nvfortran_x86_26_3   :   113	                   0,
nvfortran_x86_26_3   :   114	                   5,
nvfortran_x86_26_3   :   115	                   0,
nvfortran_x86_26_3   :   116	                   7,
nvfortran_x86_26_3   :   117	                   0,
nvfortran_x86_26_3   :   118	         -2147483648,
nvfortran_x86_26_3   :   119	         -2147483648,
nvfortran_x86_26_3   :   120	         -2147483648,
nvfortran_x86_26_3   :   121	         -2147483648,
                                   :
                                   :
nvfortran_x86_26_3   :   208	         -2147483648,
nvfortran_x86_26_3   :   209	         -2147483648
nvfortran_x86_26_3   :   210	 /
nvfortran_x86_26_3   :   211	 &NUMS
nvfortran_x86_26_3   :   212	 MSG = "delimiter: ""        ",
nvfortran_x86_26_3   :   213	 INTS =            1,
nvfortran_x86_26_3   :   214	                   0,
nvfortran_x86_26_3   :   215	                   3,
nvfortran_x86_26_3   :   216	                   0,
nvfortran_x86_26_3   :   217	                   5,
nvfortran_x86_26_3   :   218	                   0,
nvfortran_x86_26_3   :   219	                   7,
nvfortran_x86_26_3   :   220	                   0,
nvfortran_x86_26_3   :   221	         -2147483648,
nvfortran_x86_26_3   :   222	         -2147483648,
nvfortran_x86_26_3   :   223	         -2147483648,
                                   :
                                   :
nvfortran_x86_26_3   :   311	         -2147483648,
nvfortran_x86_26_3   :   312	         -2147483648
nvfortran_x86_26_3   :   313	 /
nvfortran_x86_26_3   :   314	 &NUMS
nvfortran_x86_26_3   :   315	 MSG = delimiter: none     ,
nvfortran_x86_26_3   :   316	 INTS =            1,
nvfortran_x86_26_3   :   317	                   0,
nvfortran_x86_26_3   :   318	                   3,
nvfortran_x86_26_3   :   319	                   0,
nvfortran_x86_26_3   :   320	                   5,
nvfortran_x86_26_3   :   321	                   0,
nvfortran_x86_26_3   :   322	                   7,
nvfortran_x86_26_3   :   323	                   0,
nvfortran_x86_26_3   :   324	         -2147483648,
nvfortran_x86_26_3   :   325	         -2147483648,
nvfortran_x86_26_3   :   326	         -2147483648,
                                   :
                                   :
nvfortran_x86_26_3   :   413	         -2147483648,
nvfortran_x86_26_3   :   414	         -2147483648,
nvfortran_x86_26_3   :   415	         -2147483648
nvfortran_x86_26_3   :   416	 /
nvfortran_x86_26_3   :   417	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
nvfortran_x86_26_3   :   418	case2 ===============================================================================
nvfortran_x86_26_3   :   419	<ERROR>illegal subscript or substring specification^@^@^@^@^@^@^@^@^@
nvfortran_x86_26_3   :   420	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
nvfortran_x86_26_3   :   421	case3 ===============================================================================
nvfortran_x86_26_3   :   422	STDERR:
nvfortran_x86_26_3   :   423	That's all Folks!

compiler gfortran161

  • OUTPUT QUOTED WHEN DELIM=‘NONE’
  • NULL VALUE WHEN DELIM=‘NONE’
click to see output...
++ cexpl -c gfortran161 --skip-asm '--cflags=-cpp -Wall -Wextra -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -DCOMPILER_=gfortran161' -e simple.f90
gfortran161          :     1	STDOUT:
gfortran161          :     2	DELIM:NONE:RECL:2147483647
gfortran161          :     3	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
gfortran161          :     4	case1 ===============================================================================
gfortran161          :     5	&NUMS
gfortran161          :     6	 MSG="step                ",
gfortran161          :     7	 INTS=1          ,0          ,3          ,0          ,5          ,
gfortran161          :     8	 0          ,7          ,0          , 92*-2147483648,
gfortran161          :     9	 /
gfortran161          :    10	&NUMS
gfortran161          :    11	 MSG='delimiter: ''        ',
gfortran161          :    12	 INTS=1          ,0          ,3          ,0          ,5          ,
gfortran161          :    13	 0          ,7          ,0          , 92*-2147483648,
gfortran161          :    14	 /
gfortran161          :    15	&NUMS
gfortran161          :    16	 MSG="delimiter: ""        ",
gfortran161          :    17	 INTS=1          ,0          ,3          ,0          ,5          ,
gfortran161          :    18	 0          ,7          ,0          , 92*-2147483648,
gfortran161          :    19	 /
gfortran161          :    20	&NUMS
gfortran161          :    21	 MSG=delimiter: none     
gfortran161          :    22	 INTS=1          ,0          ,3          ,0          ,5          ,,
gfortran161          :    23	 0          ,7          ,0          , 92*-2147483648,
gfortran161          :    24	 /
gfortran161          :    25	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
gfortran161          :    26	case2 ===============================================================================
gfortran161          :    27	&NUMS
gfortran161          :    28	 MSG="negative step       ",
gfortran161          :    29	 INTS=0          ,7          ,0          ,5          ,0          ,
gfortran161          :    30	 3          ,0          ,1          , 92*-2147483648,
gfortran161          :    31	 /
gfortran161          :    32	&NUMS
gfortran161          :    33	 MSG='delimiter: ''        ',
gfortran161          :    34	 INTS=0          ,7          ,0          ,5          ,0          ,
gfortran161          :    35	 3          ,0          ,1          , 92*-2147483648,
gfortran161          :    36	 /
gfortran161          :    37	&NUMS
gfortran161          :    38	 MSG="delimiter: ""        ",
gfortran161          :    39	 INTS=0          ,7          ,0          ,5          ,0          ,
gfortran161          :    40	 3          ,0          ,1          , 92*-2147483648,
gfortran161          :    41	 /
gfortran161          :    42	&NUMS
gfortran161          :    43	 MSG=delimiter: none     
gfortran161          :    44	 INTS=0          ,7          ,0          ,5          ,0          ,,
gfortran161          :    45	 3          ,0          ,1          , 92*-2147483648,
gfortran161          :    46	 /
gfortran161          :    47	1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
gfortran161          :    48	case3 ===============================================================================
gfortran161          :    49	STDERR:
gfortran161          :    50	STOP That's all Folks!

Maybe my memory is off about this, but I think most namelist extensions I used (prior to standardization in f90) started both the &input and the &end statement in column 2. Of course being nonstandard, there was some variation. Some compilers allow the $ character instead of the & character. F90 eliminated the &end and replaced it with just a / character.

In both of your examples, you use the \ character. I think the / character is required here. Maybe some compilers allow \ as an extension?

I do not know the answer to your question regarding blanks. Line 12 does say that each output records begins with a blank, but Line 7 says that the & character should be placed at the start of the first output record. Aside from the verb/noun difference in this usage, in normal English those two words are synonyms. I don’t know how that conflict should be resolved. Maybe someone else knows if there has been a formal interpretation about this over the last 35 years. It might be good if an example of standard conforming output could be given here in the standard, as it did for input in Section 13.11.3.6.

When comparing outputs during development/debugging, I have found that practically speaking you should avoid both list-directed and namelist output. The compiler has too much freedom in the spacing, line breaks, and other issues to easily compare outputs. It is not just whitespace that can differ, but also sometimes leading zeros, exponent field widths, optional signs, and so on. These ambiguities could have all been eliminated decades ago (even in f77 I’d say), but the standard committee has always chosen to not do that, so millions of programmers must adapt instead of dozens of compilers. If the programmer puts in the effort, then you can get identical output from different compilers. Use the es descriptor rather than the e or g descriptors, specify the exponent field widths, and so on – but all that takes some effort, especially for legacy codes.

1 Like

This deviates from your main topic about leading with a blank (which is news to me), but since you reported on delimiter behavior:

GCC has this discussion about their reason for breaking delimiter compliance.

I tried out their suggestion of using -std to force the standards-compliant default behavior of DELIM='NONE', but it kept giving me quotes :person_shrugging: .

But maybe you’ll see different behavior with -std or -pedantic flags?

I have a few old fortran manuals from the 1980s, so I checked on this in one of them. This is from the Fortran Reference Manual for a Stardent Titan from 1989. This was one of a dozen or so scientific workstations based on a unix OS and a RISC cpu in the late 1980s. In fact, the STARDENT name itself was a combination of STELLAR and ARDENT, the two parent companies that merged about the time this fortran manual was published. There was an earlier edition of this manual, but I think it was also dated 1989. So this is mostly a f77 fortran with extensions (typical of that era), but it was during the long fortran 8x public comment and revision period. The Namelist I/O section contains the text:

NAMELIST-directed input is specified by the following statements:
READ nml
or
READ (unit,nml,…optional keywords)
[…]
Reading always starts at the beginning of a new record. Records are read until a “$” or “&” is found in column 2, immediately followed by a NAMELIST group name matching the one specified in the READ statement.

The example they give uses the f90-style read statement

READ (UNIT=5,NML=N1)

so it looks like the compiler was in transition from f77 to f8x, but the manual had not quite fully caught up.

There is also a section about namelist output. Here the &nml, the output data, and the final &end all start in column 2 of each output record.

This data format is pretty much how I remember namelist working for all the compilers I used in the 1970s and 1980s. The differences I remember were mostly in the syntax of the read and write statements. Conditional compilation (not part of the standard, of course) was required to have portable source code that worked for all compilers, but there were I think only two or three branches necessary to cover all the compilers that provided the namelist extension.

I also remember avoiding character data in namelist i/o, but I think that dated mostly from the early 1980s when compilers were making the transition to f77 which first introduced the character type. I think by the late 1980s, it was probably safe to use character variables in namelist.

I sympathize with how non-intuitive it is to have NAMELIST output default to quoted strings because one option i.e. (DELIM=) controls both list-directed and NAMELIST output. I remember being confused about it at some time in the past (and discovering I could add it to the WRITE() statement to make sure the desired mode was obtained) but I think this gfortran extension just makes things even more confusing in the end even though the heart was in the right place.

The extension leads to this unfortunate result shown in the following example, where an inquire of DELIM
initially shows a value of NONE but if you explicitly set it to NONE
you then get standard behavior with no way I see documented of returning
to the original behavior. Since an explicit setting could occur in a
subroutine this means you cannot easily guarantee the initial behavior
will occur elsewhere in the program.

Using -std=f2023 did not change the behavior or cause a warning to be produced.
I too think it is odd to have to specify delim=“quote” on the WRITE() or on an OPEN()
for namelist output, but I would recommend gfortran dropping the extension at least
when -std=f* is specified, and alternatively that as part of the extension the value of
DELIM be “default” or perhaps “mixed”, and that to return to the initial
behavior using the value on an OPEN() would work, and that it not work
when -std=f* is specified itself. Quoting the text by default is more intuitive, but
there are other non-intuitive things about Fortran output like how quotes are
handled in quoted strings and so on anyway so in this case I think I would like the compiler to switch
to just standard behavior and show an example using “write(*,delim=‘quotes’)”
and/or specifying the default on an OPEN().

program nml_quotes_bug
use, intrinsic :: iso_fortran_env, only : stderr=>ERROR_UNIT, stdout=>OUTPUT_UNIT
implicit none
character(len=256)         :: iomsg,msg*(20)='12345678901234567890',delim*(80)
character(len=*),parameter :: g='(*(g0))'
integer                    :: iostat, i
namelist /nums/msg
   call printit()
   open (unit=stdout ,delim="quote" ) ! APOSTROPHE, QUOTE, or NONE
   call printit()
   open (unit=stdout ,delim="none" ) ! APOSTROPHE, QUOTE, or NONE
   call printit()
contains
subroutine printit()
   inquire(unit=stdout,delim=delim)
   write(stdout,g)'DELIM:',trim(delim)
   write(stdout,nml=nums)
end subroutine printit
end program nml_quotes_bug
DELIM:NONE
&NUMS
 MSG="12345678901234567890",
 /
DELIM:QUOTE
&NUMS
 MSG="12345678901234567890",
 /
DELIM:NONE
&NUMS
 MSG=12345678901234567890
 /

If the standard had taken the stance that NAMELIST output should always be readable by NAMELIST input and just declared that DELIM= had no effect on NAMELIST output and that it always used quotes things would have been a lot more intuitive but it is probably too late to correct that.

I’m just guessing, but when programmers use list-directed output, they probably want no quotes 99.9% of the time and they want quotes maybe 0.1% of the time. Namelist i/o is a little more subtle. If the string has no embedded quotes, then the programmer probably doesn’t care if the output has quotes or not. It can be read as input either way. But if the string has embedded quotes, then he probably wants the output to have quotes 99.9% of the time and to for it to have no quotes 0.1% of the time. That is because he most likely wants the output to behave “as if” it will be read later as input.

Maybe there should be an “automatic” option that writes strings without quotes if there are no embedded quote characters and writes strings with quotes if there are embedded quote characters?

Regarding gfortran, it appears that the default delim='none' setting is ignored by namelist output but not by list-directed output. If that value is explicitly set, then it applies to both as expected.

The gfortran extensions starts off quoting namelist output but if you inquire the delim says it is ‘none’ but if you set it to ‘none’ then it quits quoting. That is, you cannot restore the initial behavior it you explicitly set the value, even to the value it initially appeared to have. That is why I am saying if the extension stands as-is it should have a setting like ‘automatic’ that you can actually set. I think it was a minor design flaw in retrospect to use the same option for both NAMELIST and list-directed output but I do not think the current extension is a good idea unless there is a specific way to return to the initial behavior of the extension. And technically the standard does not require unquoted strings to be readable even if a single word. That is expected with list-directed output but the way I read it it is explicitly prohibited with NAMELIST without an extension. So at least if using -std=f* you should not even be able to read an unquoted string using NAMELIST.

You are right about this. I had thought that namelist followed the same rules as list-directed input of characters, which in section 13.10.3.1 does allow for undelimited character strings, but section 13.11.3.3 only allows for delimited character strings for namelist input. I wonder why the difference?

Mixed bag on that one too. flangtrunk and ifxlatest have an extension
to allow reading unquoted words using list-directed rules, the
others tested did not. But if supported it is an extension. I did mention
there were several issues :> .

click to see more...
!```fortran
program nml_quotes_bug
use, intrinsic :: iso_fortran_env, only : stderr=>ERROR_UNIT, stdout=>OUTPUT_UNIT
implicit none
character(len=256)         :: iomsg,msg*(20)='12345678901234567890',delim*(80)
character(len=*),parameter :: g='(*(g0))'
integer                    :: iostat, i
integer,parameter          :: lun=10
namelist /nums/msg
   open (unit=lun    ,delim="none" ) ! APOSTROPHE, QUOTE, or NONE
   open (unit=stdout ,delim="none" ) ! APOSTROPHE, QUOTE, or NONE
   call printit(stdout)
   call printit(lun)
   rewind(lun)
   msg='x0x0x0x0x0x0x0x0x0x0'
   read(lun,nml=nums)
   call printit(stdout)
contains
subroutine printit(lun)
integer,intent(in) :: lun
   inquire(unit=lun,delim=delim)
   write(lun,g)'DELIM:',trim(delim)
   write(lun,nml=nums)
end subroutine printit
end program nml_quotes_bug

compiler aoccflang520

click to see output...
++ cexpl -c aoccflang520 --skip-asm '--cflags=-cpp -DCOMPILER_=aoccflang520' -e noquotes.f90
aoccflang520         :     1	STDERR:
aoccflang520         :     2	FIO-F-231/namelist read/unit=10/error on data conversion.
aoccflang520         :     3	 File name = 'fort.10',    formatted, sequential access   record = 3
aoccflang520         :     4	 In source file /app/example.f90, at line number 16

compiler flangtrunk

click to see output...
++ cexpl -c flangtrunk --skip-asm --cflags= -e noquotes.f90
flangtrunk           :     1	STDOUT:
flangtrunk           :     2	DELIM:NONE
flangtrunk           :     3	 &NUMS MSG= 12345678901234567890/
flangtrunk           :     4	DELIM:NONE
flangtrunk           :     5	 &NUMS MSG= 12345678901234567890/

compiler ifxlatest

click to see output...
++ cexpl -c ifxlatest --skip-asm '--cflags=-fpp -warn all -check all,nouninit -error-limit 1 -O0 -g -assume byterecl -traceback -DCOMPILER_=ifxlatest' -e noquotes.f90
ifxlatest            :     1	STDOUT:
ifxlatest            :     2	DELIM:NONE
ifxlatest            :     3	 &NUMS
ifxlatest            :     4	 MSG     = 12345678901234567890
ifxlatest            :     5	 /
ifxlatest            :     6	DELIM:NONE
ifxlatest            :     7	 &NUMS
ifxlatest            :     8	 MSG     = 12345678901234567890
ifxlatest            :     9	 /

compiler lfortran0590

click to see output...
++ cexpl -c lfortran0590 --skip-asm '--cflags=--no-style-suggestions --cpp -DCOMPILER_=lfortran0590' -e noquotes.f90
lfortran0590         :     1	STDOUT:
lfortran0590         :     2	DELIM:
lfortran0590         :     3	STDERR:
lfortran0590         :     6	Runtime Error: Format mismatch between OPEN statement and WRITE statement on unit 6.

compiler nvfortran_x86_26_3

click to see output...
++ cexpl -c nvfortran_x86_26_3 --skip-asm '--cflags=-Mbackslash -Mpreprocess -DCOMPILER_=nvfortran_x86_26_3' -e noquotes.f90
nvfortran_x86_26_3   :     1	STDERR:
nvfortran_x86_26_3   :     2	FIO-F-231/namelist read/unit=10/error on data conversion.
nvfortran_x86_26_3   :     3	 File name = 'fort.10',    formatted, sequential access   record = 3
nvfortran_x86_26_3   :     4	 In source file /app/example.f90, at line number 16

compiler gfortran161

click to see output...
++ cexpl -c gfortran161 --skip-asm '--cflags=-cpp -Wall -Wextra -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -DCOMPILER_=gfortran161' -e noquotes.f90
gfortran161          :     1	STDOUT:
gfortran161          :     1	DELIM:NONE
gfortran161          :     2	&NUMS
gfortran161          :     3	 MSG=12345678901234567890
gfortran161          :     4	 /
gfortran161          :     5	At line 16 of file app/noquotes.f90 (unit = 10, file = 'fort.10')
gfortran161          :     6	Fortran runtime error: Missing quote while reading item 1
gfortran161          :     7	
gfortran161          :     8	Error termination. Backtrace:
gfortran161          :     9	#0  0x5cc4cd255 in ???
gfortran161          :    10	#1  0x5cc448321 in ???
gfortran161          :    11	#2  0x5cc31703b in ???
gfortran161          :    12	#3  0x5cc5f74b1 in ???
gfortran161          :    13	#4  0x5cc5f350b in ???
gfortran161          :    14	#5  0x5cc4c43df in ???
gfortran161          :    15	#6  0x5cc4e5d6a in ???
gfortran161          :    16	#7  0x5cc4d1eaf in ???
gfortran161          :    17	#8  0x10040143f in nml_quotes_bug
gfortran161          :    18		at app/noquotes.f90:16
gfortran161          :    19	#9  0x10040149d in main
gfortran161          :    20		at app/noquotes.f90:17

By my interpretation the standard is quite flexible about where comments and non namelist-group data and whitespace ca be so if you just always add delim=“quotes” on the WRITE statements in practice it works more portably than you would think. I think everyone supports forward searching for the next group description with a given name, which has been a feature at least in some versions long before the standard adopted NAMELIST but I do not think that behavior is particularly well described anywhere either. repeat specifiers, null values, and oth

By my interpretation the standard is quite flexible about where comments and non namelist-group data and whitespace ca be so if you just always add delim=“quotes” on the WRITE statements in practice it works more portably than you would think. I think everyone supports forward searching for the next group description with a given name, which has been a feature at least in some versions long before the standard adopted NAMELIST but I do not think that behavior is particularly well described anywhere either. repeat specifiers, null values, and other fancier features work rather reliably too, at least where I commonly use NAMELIST files. At one time some platforms required at least a three-line input but One-liners work with everything I have access to. Unclear whether RECL= is supposed to be obeyed and whether you can always write to a single line on an internal file. Would be nice if a write to an allocatable string allocated sufficient bytes. Not sure if the latest standard proposals support that like in other places line GET_COMMAND_ARGUMENT and such.

One of my pet peeves is that if you only print the data values and commas you get a common form of CSV files. List-directed and NAMELIST output are likely the origin of CSV files although some might differ with that. Regardless, it is frustrating Fortran does not have a standard-conforming way of writing CSV given how close it is to it except for possibly using a backslash to escape an internal quote instead of a pair of quotes.

Good news, there is!

print '(*(g0, :, ", "))', array

1.1, 2.2, 3.3, 4.4, 5.5

  • * is unlimited repeat count
  • : stops the formatting if there’s no further output

Supported by everything on Godbolt (although LFortran’s handling of g0 is very funky)

1 Like

I am a bit more familiar with that than my comment implies I suppose; going back to fortran.lang.comp. There are a few related threads here in Discourse as well, such as Why are parens required around format strings? - #3 by Carltoffel. I agree with you that is a good way to write CSV for many simple cases. Reading the line back and maintaining the read and write arguments on the I/O statements and automatically generating a CSV title line are all issues that remain; which is why modules such as GitHub - jacobwilliams/csv-fortran: Read and Write CSV Files Using Modern Fortran · GitHub exist. But you are right; for a good number of simple cases that WRITE statement will get you a far ways writing CSV although I would suggest it does not handle the issue of quoted strings on output. Between non-advancing I/O and field descriptors and list-directed and NAMELIST I/O and stream I/O , etc Fortran has a very extensive number of I/O capabilities. I think it mostly has a negative image regarding its I/O capabilities not because of a lack of capabilities but because of a lack of simple-to-use dedicated features that do nothing but some of the simple common tasks like writing a JSON/YAML/TOML/CSV file from a NAMELIST group.

Since DELIM= only effects NAMELIST and list-directed output you have to typically quote the strings yourself when using g0 format descriptors to make CSV files or files you can read back in with list-directed I/O when they are not simple single-word alphameric strings. I have some functions for quoting and unquoting strings but now that Fortran can write list-directed I/O to internal files this makes your example slightly more generic.

Only broke two compilers I tried it with!

Fortran source

program nml_quotes_bug
use, intrinsic :: iso_fortran_env, only : stdout=>OUTPUT_UNIT
implicit none
character(len=*),parameter :: comma='(*(g0:,","))'
character(len=*),parameter :: braces='(*("[",g0,"]":,","))'
character(len=*),parameter :: msg='  12345  "6789""012345"67890   '
integer                    :: lun

   write(stdout,comma)10,20,q(msg),40

  writeandreadback: block
   integer :: ii,jj,kk
   character(len=256) :: cc
   write(stdout,'(a)')'write and read back'
   open(newunit=lun,status='scratch')
   write(lun,comma)10,20,q(msg),40
   rewind(lun)
   read(lun,*)ii,jj,cc,kk
   write(stdout,braces)ii,jj,trim(cc),kk
  endblock writeandreadback

contains

function q(string) result(output)
! use list-directed I/O to quote the string using list-directed I/O rules
character(len=*),intent(in) :: string
character(len=:),allocatable :: output
   allocate(character(len=2*len(string)+2) :: output)
   write(output,*,delim='quote')string
   output=trim(output(2:))
end function q

end program nml_quotes_bug

Godbolt output:

aoccflang520         :     2	10,20,"  12345  ""6789""""012345""67890   ",40
aoccflang520         :     3	write and read back
aoccflang520         :     4	[10],[20],[  12345  "6789""012345"67890],[40]

flangtrunk           :     2	10,20,"  12345  ""6789""""012345""67890   ",40
flangtrunk           :     3	write and read back
flangtrunk           :     4	[10],[20],[  12345  "6789""012345"67890],[40]

nvfortran_x86_26_3   :     2	10,20,"  12345  ""6789""""012345""67890   ",40
nvfortran_x86_26_3   :     3	write and read back
nvfortran_x86_26_3   :     4	[10],[20],[  12345  "6789""012345"67890],[40]

gfortran161          :     2	10,20,"  12345  ""6789""""012345""67890   ",40
gfortran161          :     3	write and read back
gfortran161          :     4	[10],[20],[  12345  "6789""012345"67890],[40]

ifxlatest            :     2	10,20,  12345  "6789""012345"67890,40
ifxlatest            :     3	write and read back
ifxlatest            :     4	STDERR:
ifxlatest            :     5	forrtl: severe (64): input conversion error, unit -129, file /app/fortoL5OxO
ifxlatest            :     6	Image              PC                Routine            Line        Source             
ifxlatest            :     7	output.s           000000000041814F  Unknown               Unknown  Unknown
ifxlatest            :     8	output.s           0000000000405A1F  nml_quotes_bug             19  example.f90
ifxlatest            :     9	output.s           000000000040520D  Unknown               Unknown  Unknown
ifxlatest            :    10	libc.so.6          000072884022A1CA  Unknown               Unknown  Unknown
ifxlatest            :    11	libc.so.6          000072884022A28B  __libc_start_main     Unknown  Unknown
ifxlatest            :    12	output.s           0000000000405125  Unknown               Unknown  Unknown

lfortran0590         :     2	10,20, 12345  "6789""012345"67890,40
lfortran0590         :     3	write and read back
lfortran0590         :     4	STDERR:
lfortran0590         :     7	Error: Invalid input for int32_t from file.

The quote and unquote functions make it work on ifx instead of using the q() function shown here

As an aside, when using inquire with gfortran, there have been some recent fixes. A few months ago I submitted PR 124543 which noted a number of dubious inquire results - including with delim=. Jerry fixed things up right away. But the fixes are only present in recent (e.g., since early April) builds of v16.

I have 20260613 release on the machine I was using but the results are from godbolt site and 16.1.0 was the newest I saw. Trying to cut back on installing compilers. Will be nice as more run directly in browsers. Time limit on godbolt is too short to compile all but the shortest of codes but handy for trying many compilers so trying things there first

Luckily a lot of things I tried to use INQUIRE() for are now easier to do by calling C procedures

I often tried using INQUIRE to do things like tell a directory from a file or tell if stdin and stdout were attached to a tty or not and to get real full pathnames of files and learned the hard way that even if it worked on a particular platform it was not even close to being a portable technique.

I have had a lot of tickets on INQUIRE(). but aside from the bugs there
is a lot of room for disagreements as well, like on is a directory a
file? Fortran is not much good at distinguishing between special files and
files and links and so on, so just about every platform gives different
results. The first two I tried gave four different responses out of six
platforms tested :>. A query of preconnected units to stdin, stdout,
stderr are always interesting. Do they have a name? Some return a blank,
some a pathname, some a generic string like “stdin” and “stdout” and so
on. And of course stdin and stdout will behave differently depending on
the OS and whether a batch or or interactive and attached to a tty or
a pipe or redirected to a file.

Four responses for six platforms for just the first two inquires …

aoccflang520        : YES                                      T
nvfortran_x86_26_3  : YES                                      T
ifxlatest           : YES                                      F
flangtrunk          : UNDEFINED                                T
gfortran161         : UNDEFINED                                T
lfortran0590        : ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ F

you can argue over what is right or wrong on some of these, but lfortran
probably does not want to return nulls like that.

samples of names associated with stdin and stdout …

                stdin                    stdout           
flangtrunk   :  NAME=UNDEFINED  NAMED=F  :  NAME=              NAMED=F
ifxlatest    :  NAME=           NAMED=F  :  NAME=/proc/1/fd/1  NAMED=T
gfortran161  :  NAME=           NAMED=F  :  NAME=stdout        NAMED=T

I used to use this print_inquire procedure and then whittle it down o show just a single
problem for a bug report when dealing with INQUIRE(). It can be educational to see how
different each platform is. Are pathnames returned full pathnames or relative pathnames, for example.
Remember if you play with print_inquire that it queries everything and some combinations are not
allowed for some files, so make sure some of the odder returns are not just because those values
are not defined for a particular filetype.

program testit
use, intrinsic :: iso_fortran_env, only : stderr=>ERROR_UNIT, stdout=>OUTPUT_UNIT, stdin=>INPUT_UNIT
character*20 :: pad
logical      :: is_file

! Result of INQUIRE on a closed unit
close(5)
inquire(5,pad=pad)

! Result of INQUIRE on a directory
inquire(file=".", exist=is_file)

print *, ' PAD OF CLOSED FILE ',trim(pad), ' IS_FILE?  ',is_file
call print_inquire(stdin)
call print_inquire(stdout)
contains
subroutine print_inquire(lun_in,namein_in) ! Version: JSU-1997-12-31, 2020-01-11

! ident_4="@(#) M_io print_inquire(3f) Do INQUIRE on file by name/number and print results"

integer,intent(in),optional             :: lun_in        ! if unit >= 0 then query by unit number, else by name
character(len=*),intent(in),optional    :: namein_in
integer                        :: ios
character(len=256)             :: message
character(len=:),allocatable   :: namein
integer                        :: lun
!==============================================================================================
!  ACCESS    =  SEQUENTIAL  |  DIRECT       |  STREAM
!  ACTION    =  READ        | WRITE         |  READWRITE
!  FORM      =  FORMATTED   |  UNFORMATTED
!  POSITION  =  ASIS        |  REWIND       |  APPEND
!  STATUS    =  NEW         |  REPLACE      |  OLD     |  SCRATCH   | UNKNOWN
character(len=20)             :: access         ; namelist/inquire/access
character(len=20)             :: asynchronous   ; namelist/inquire/asynchronous
character(len=20)             :: blank          ; namelist/inquire/blank
character(len=20)             :: decimal        ; namelist/inquire/decimal
character(len=20)             :: delim          ; namelist/inquire/delim
character(len=20)             :: direct         ; namelist/inquire/direct
character(len=20)             :: encoding       ; namelist/inquire/encoding
logical                       :: exist          ; namelist/inquire/exist

character(len=20)             :: form           ; namelist/inquire/form
character(len=20)             :: formatted      ; namelist/inquire/formatted
character(len=20)             :: unformatted    ; namelist/inquire/unformatted

integer                       :: id             ; namelist/inquire/id
character(len=20)             :: name           ; namelist/inquire/name
logical                       :: named          ; namelist/inquire/named
integer                       :: nextrec        ; namelist/inquire/nextrec
integer                       :: number         ; namelist/inquire/number
logical                       :: opened         ; namelist/inquire/opened
character(len=20)             :: pad            ; namelist/inquire/pad
logical                       :: pending        ; namelist/inquire/pending
integer                       :: pos            ; namelist/inquire/pos
character(len=20)             :: position       ; namelist/inquire/position

character(len=20)             :: action         ; namelist/inquire/action
character(len=20)             :: read           ; namelist/inquire/read
character(len=20)             :: readwrite      ; namelist/inquire/readwrite
character(len=20)             :: write          ; namelist/inquire/write

integer                       :: recl           ; namelist/inquire/recl
character(len=20)             :: round          ; namelist/inquire/round
character(len=20)             :: sequential     ; namelist/inquire/sequential
character(len=20)             :: sign           ; namelist/inquire/sign
integer                       :: size           ; namelist/inquire/size
character(len=20)             :: stream         ; namelist/inquire/stream
!==============================================================================================
   namein=merge_str(namein_in,'',present(namein_in))
   if(present(lun_in))then
      lun=lun_in
   else
      lun=-1
   endif
   ! exist, opened, and named always become defined unless an error condition occurs.
   !!write(*,*)'LUN=',lun,' FILENAME=',namein
   !-----------------------------------------------------------------------------------------------------------------------------------
   name=''
   if(namein == ''.and.lun /= -1)then
         print *,'*print_inquire* checking unit',lun
         inquire(unit=lun,                                                                               &
     &   recl=recl,nextrec=nextrec,pos=pos,size=size,                                                    &
     &   position=position,                                                                              &
     &   name=name,                                                                                      &
     &   form=form,formatted=formatted,unformatted=unformatted,                                          &
     &   access=access,sequential=sequential,direct=direct,stream=stream,                                &
     &   action=action,read=read,write=write,readwrite=readwrite,                                        &
     &   sign=sign,                                                                                      &
     &   round=round,                                                                                    &
     &   blank=blank,decimal=decimal,delim=delim,encoding=encoding,pad=pad,                              &
     &   named=named,opened=opened,exist=exist,number=number,pending=pending,asynchronous=asynchronous,  &
     &   iostat=ios,err=999,iomsg=message)
    elseif(namein /= '')then
         print *,'*print_inquire* checking file:'//namein
         inquire(file=namein,                                                                            &
     &   recl=recl,nextrec=nextrec,pos=pos,size=size,                                                    &
     &   position=position,                                                                              &
     &   name=name,                                                                                      &
     &   form=form,formatted=formatted,unformatted=unformatted,                                          &
     &   access=access,sequential=sequential,direct=direct,stream=stream,                                &
     &   action=action,read=read,write=write,readwrite=readwrite,                                        &
     &   sign=sign,                                                                                      &
     &   round=round,                                                                                    &
     &   blank=blank,decimal=decimal,delim=delim,encoding=encoding,pad=pad,                              &
     &   named=named,opened=opened,exist=exist,number=number,pending=pending,asynchronous=asynchronous,  &
     &   iostat=ios,err=999,iomsg=message)
     if(name == '')name=namein
    else
       print *,'*print_inquire* must specify either filename or unit number'
    endif
!-----------------------------------------------------------------------------------------------------------------------------------
   write(*,nml=inquire,delim='none')
   return
!-----------------------------------------------------------------------------------------------------------------------------------
999   continue
   print *,'*print_inquire* bad inquire'
!  If an error condition occurs during execution of an INQUIRE  statement,
!  all of the inquiry identifiers except ios become undefined.
   print *,'*print_inquire* inquire call failed,iostat=',ios,'message=',trim(message)
end subroutine print_inquire
function merge_str(str1,str2,expr) result(strout)
! for some reason the MERGE(3f) intrinsic requires the strings it compares to be of equal length
! make an alias for MERGE(3f) that makes the lengths the same before doing the comparison by padding the shorter one with spaces

!character(len=*),parameter::ident_37="@(#)M_strings::merge_str(3f): pads first and second arguments to MERGE(3f) to same length"

character(len=*),intent(in)     :: str1
character(len=*),intent(in)     :: str2
logical,intent(in)              :: expr
character(len=:),allocatable    :: strout
integer                         :: big
   big=max(len(str1),len(str2))
   strout=trim(merge(lenset(str1,big),lenset(str2,big),expr))
end function merge_str
function lenset(line,length) result(strout)

!character(len=*),parameter::ident_36="@(#)M_strings::lenset(3f): return string trimmed or padded to specified length"

character(len=*),intent(in)  ::  line
integer,intent(in)           ::  length
character(len=length)        ::  strout
   strout=line
end function lenset
end program testit
end
1 Like

When I filed the inquire PR against gfortran, I also submitted one against lfortran (#10677). @certik’s minions also fixed things up pretty quickly. But no doubt issues may remain.

1 Like