Enter Home Page

Exploring NAMELIST

Fortran 2003 interactive editing of variable values via NAMELIST groups

A common extension for NAMELIST is to allow for interactive NAMELIST group input, including listing the NAMELIST group. This can also be done portably, as shown in the following example.

Using a NAMELIST group to create an interactive prompt for variables by name

NAMELIST input has some underutilized uses. Unlike similar file formats it is built into the standard, allows multiple sets in a single file which it searches sequentially for by name, and ignores lines in the file not in a NAMELIST group format. One perhaps unexpected use is to let you simulate exposing variables in the program for the user to change interactively.

Taking advantage of NAMELIST not requiring all values to be specified on a READ, it takes very little code to make an interactive prompt for values of the form

    NAME=VALUE(S)

For example, the following relatively short program shows placing a number of variables into a NAMELIST and then letting you interactively change them with a session looking something like:

! args>>show ! args>>f='courier' t='new title' ! args>>view=1,2,3 ! args>>a=456.789 ! args>>! run with new values ! args>> . ! args>>h=t ! args>>! run again ! args>> . ! args>>stop program namelist_prompter implicit none ! create a NAMELIST group with lots of options ! this is just a sample real :: a=0.0 real :: view(3)=[0.0,0.0,0.0] character(len=80) :: t='title' character(len=80) :: f='roman' logical :: h=.false. namelist /args/ a,view,t,h,f character(len=:),allocatable :: status do call readargs(status) ! interactively change NAMELIST group if(status.eq.'stop')exit call dosomething() ! use the NAMELIST values enddo contains subroutine readargs(status) character(len=:),intent(out),allocatable :: status character(len=256) :: line character(len=256) :: answer integer :: lun integer :: ios status='' write(*,'(a)')'args>> "." to run, "stop" to end, "show" to show keywords, "read","write","sh"' do write(*,'(a)',advance='no')'args>>' read(*,'(a)')line if(line(1:1).eq.'!')cycle select case(line) case('.') exit case('show') write(*,*)'SO FAR' write(*,nml=args) !! something where you could restrict nml output to just listed names would be nice !!write(*,nml=args)['A','H'] !!write(*,nml=*NML)args['A','H'] case('stop') status='stop' exit case('sh') call execute_command_line('bash') case('read') write(*,'(a)',advance='no')'filename:' read(*,'(a)',iostat=ios)answer if(ios.ne.0)exit open(file=answer,iostat=ios,newunit=lun) if(ios.ne.0)exit read(lun,args,iostat=ios) close(unit=lun,iostat=ios) case('write') write(*,'(a)',advance='no')'filename:' read(*,'(a)',iostat=ios)answer if(ios.ne.0)exit open(file=answer,iostat=ios,newunit=lun) if(ios.ne.0)exit write(lun,args,iostat=ios) close(unit=lun,iostat=ios) case default UPDATE: block character(len=:),allocatable :: intmp character(len=256) :: message integer :: ios intmp='&ARGS '//trim(line)//'/' read(intmp,nml=args,iostat=ios,iomsg=message) if(ios.ne.0)then write(*,*)'ERROR:',trim(message) endif endblock UPDATE end select enddo end subroutine readargs subroutine dosomething() ! placeholder write(*,*)'USE ALL THOSE VALUES' end subroutine dosomething ! would be nice if could do partial NAMELIST (write(*,nml=args) a,view end program namelist_prompter