[UP]


Manual Reference Pages  - get_namelist (3)

NAME

get_namelist(3f) - [ARGUMENTS:M_args] NAMELIST-based command line argument parsing (LICENSE:PD)

CONTENTS

Synopsis
Description
Options
Returns
Author
License

SYNOPSIS

function get_namelist(definition,all) result(string)

   character(len=*),intent(in),optional  :: definition
   logical,intent(in),optional  :: all
   character(len=:),allocatable :: string

DESCRIPTION

This routine leverages NAMELIST groups to do the conversion from strings to numeric values required by other command line parsers.

Several of the following example programs simply need an initialized variable added to the NAMELIST and it automatically is available as a command line argument. Hard to imagine it getting much simpler.

To use the routine define a NAMELIST group called ARGS.

The routine provides three modes
o keyword=value(s) pairs on the command line.

     Typical program usage:

cmd x=1 point=-1,-2,-3 help=T

This requires nothing but a call to the get_namelist(3f) procedure with no arguments and is very suitable if you just need to pass in a few numeric values. the syntax used on the command line is the syntax required for a NAMELIST input string which is very good for numeric values but does not follow the common syntax rules found in routines like getopts(3c) or IEEE Std 1003.1-2001, for example.
o Unix-like command usage when provided a NAMELIST group string.
     Typical program usage:

cmd -x 1 --point -1,-2,-3 --title ’my string’ --help file1 file2

You can use an internal write to generate the input string (which means to add a new parameter you need to do nothing but initialize the variable and add the name to the ARGS NAMELIST group and it automatically becomes a new command line argument).
o Unix-like command usage when provided a Unix-like prototype.
     Typical program usage:

cmd -x 1 --point -1,-2,-3 --title ’my string’ --help file1 file2

If you are not familiar with NAMELIST input and output you can declare all the members of the namelist and their default values much like you were calling the program with a command prototype string.

For all three modes there is no need to convert from strings to numeric values in the source code. Even arrays and user-defined types can be used, complex values can be input ... just define the variable and add it to the NAMELIST definition.

Note that since all the arguments are defined in a NAMELIST group that config files can easily be used for the same options. Just create a NAMELIST input file and read it.

NAMELIST syntax can vary between different programming environments. Currently, this routine has only been tested using gfortran 7.0.4; and requires at least Fortran 2003.

    NO DEFINITION

If the routine is called with no definition string arguments are passed in on the command line using NAMELIST syntax (ie. KEYWORD=VALUE). This is particularly suited for passing a few numeric values.

For example:

    program nooptions
    use M_args, only : get_namelist
    implicit none
    character(len=255)           :: message ! use for I/O error messages
    character(len=:),allocatable :: readme  ! stores command line
    integer                      :: ios     ! I/O error number

! declare and initialize a namelist that defines all ! the command keywords integer :: i=1, j=2, k=3 real :: s=111.1, t=222.2, r=333.3 real :: point(3)=[10.0,20.0,30.0] logical :: help=.false.,version=.false.

! just add a variable here and it is a new parameter namelist /args/ i,j,k,s,t,r,point,help,version

! return command line arguments as NAMELIST input readme=get_namelist() ! internal read of namelist read(readme,nml=args,iostat=ios,iomsg=message) if(ios.ne.0)then write(*,’("ERROR:",i0,1x,a)’)ios, trim(message) write(*,*)’OPTIONS:’ write(*,nml=args) stop 1 endif ! all done cracking the command line

! use the values in your program. write(*,nml=args)

end program nooptions

You can call the example program with syntax like:

      cmd  r=200e3 i=200
      cmd  K=33333,J=22222,I=11111
      cmd  point = 1, 2, 3 s= -3.0e4 t = 405.5

If you do pass in strings nested quotes or escaped double-quote characters are typically required. How to do that can vary with what shell and OS you are running in. Typically the following will work ...

      # just quote the entire argument list with single quotes ...
      cmd ’c="my character string" S=10,T=20.30,R=3e-2’

# or nest the quotes ... cmd c=’"string"’ S=20.30

# or escape the quotes ... cmd c=\"string\"

    PASS IN A NAMELIST STRING

If you want to pass in options using syntax similar to that provided by the C getopts(3c) procedure pass in a NAMELIST string. Typically, you would generate the input string by writing the NAMELIST group to an internal file.

The following program can be called using commands like

     cmd -A ’string Value’ -l -V --help -p 3.4,5.6 -- *

Typical program skeleton:

    program demo_get_namelist
    use M_args,  only : unnamed
    implicit none
    integer :: i

! declare and initialize a namelist ! letter_ denotes an uppercase short command keyword ! all values should be allocated before calling get_args(3f) real :: x=111.1, y=222.2, z=333.3 real :: point(3)=[10.0,20.0,30.0] character(len=80) :: title=" " logical :: help=.false., version=.false. logical :: l=.false., l_=.false., v=.false., h=.false. ! you can equivalence short and long options equivalence (help,h),(version,v) ! just add a variable here and it is a new parameter !! namelist /args/ x,y,z,point,title,help,h,version,v,l,l_ ! call get_args() ! crack command line options ! do stuff with your variables write(*,*)’VALUES ARE NOW’ write(*,nml=args) if(size(unnamed).gt.0)then write(*,’(a)’)’UNNAMED:’ write(*,’(i6.6,3a)’)(i,’[’,unnamed(i),’]’,i=1,size(unnamed)) endif contains subroutine get_args() ! The NAMELIST cannot be passed as an option to a routine so this ! routine must be in a contained routine or directly in the body of ! the routine that declares the NAMELIST. get_args(3f) should not ! need changed except for possibly the length of HOLD_NAMELIST use M_args, only : get_namelist, print_dictionary, oneline ! integer :: ios, i character(len=255) :: message ! use for I/O error messages character(len=:),allocatable :: readme ! stores updated namelist ! make big enough for all of namelist character(len=10000) :: hold_namelist(60) ! the routine needs a copy of the options to determine what values ! are character and logical versus numeric write(hold_namelist,nml=args,iostat=ios,iomsg=message) if(ios.eq.0)then ! pass in the namelist and get an updated copy that includes ! values specified on the command line readme=get_namelist(oneline(hold_namelist)) ! read the updated namelist to update the values ! in the namelist group read(readme,nml=args,iostat=ios,iomsg=message) endif if(ios.ne.0)then write(*,’("ERROR:",i0,1x,a)’)ios, trim(message) call print_dictionary() stop 1 endif ! all done cracking the command line end subroutine get_args end program demo_get_namelist

Instead of writing the NAMELIST group into a string you can compose the string yourself. only defined names will be able to be specified on the command line. For example:

    call get_namelist(’&ARGS A_="A value",B_=" ",C_=11 22 33, help=F/’)

Sample with manual definition of NAMELIST string

    program show_get_namelist_manual
    use M_args,  only : unnamed, get_namelist, print_dictionary
    implicit none
    integer            :: i, ios
    character(len=255) :: message
    ! define namelist
    real               :: x, y, z
    logical            :: help, h, version, v
    namelist /args/ x,y,z,help,h,version,v
    ! equivalence short and long version and help options
    equivalence           (help,h),(version,v)
    ! define NAMELIST string that defines all NAMELIST
    ! group variables
    character(len=:),allocatable :: cmd
       cmd=’&ARGS X=1 Y=2 Z=3 HELP=F H=F VERSION=F V=F/’
       ! initialize all values in NAMELIST by reading string
       read(cmd,nml=args,iostat=ios,iomsg=message)
       if(ios.eq.0)then
          ! reduce NAMELIST string to just values on command line
          cmd=get_namelist(cmd)
          ! update NAMELIST group with values from command line
          read(cmd,nml=args,iostat=ios,iomsg=message)
       endif
       if(ios.ne.0)then
          call print_dictionary(’ERROR: ’//message)
          stop 1
       endif
       ! all done. use values in program
       write(*,nml=args)
       if(size(unnamed).gt.0)then
          write(*,’(i6.6,3a)’)(i,’[’,unnamed(i),’]’,i=1,size(unnamed))
       endif
    end program show_get_namelist_manual

    UNIX PROTOTYPE

Instead of passing in a NAMELIST string a Unix-like command prototype string can be used. Something like:

      call get_namelist(’-A " " -l -x -30.34e2 --help -version ’)

typical usage:

      program show_get_namelist_unix_prototype
         use M_args,  only : unnamed, get_namelist, print_dictionary
         implicit none
         integer                      :: i
         character(len=255) :: message ! use for I/O error messages
         character(len=:),allocatable :: readme ! stores updated namelist
         integer                      :: ios

! declare a namelist real :: x, y, z, point(3) character(len=80) :: title logical :: help, version, l, l_, v, h equivalence (help,h),(version,v) namelist /args/ x,y,z,point,title,help,h,version,v,l,l_

! Define the prototype ! o All parameters must be listed with a default value ! o string values must be double-quoted ! o numeric lists must be comma-delimited. No spaces are allowed character(len=*),parameter :: cmd=’& & -x 1 -y 2 -z 3 & & --point -1,-2,-3 & & --title "my title" & & -h --help & & -v --version & & -l -L’ ! reading in a NAMELIST definition defining the entire NAMELIST readme=get_namelist(cmd,all=.true.) read(readme,nml=args,iostat=ios,iomsg=message) if(ios.ne.0)then write(*,’("ERROR:",i0,1x,a)’)ios, trim(message) call print_dictionary(’OPTIONS:’) stop 1 endif ! all done cracking the command line

! use the values in your program. write(*,nml=args) ! the optional unnamed values on the command line are ! accumulated in the character array "UNNAMED" if(size(unnamed).gt.0)then write(*,’(a)’)’files:’ write(*,’(i6.6,3a)’)(i,’[’,unnamed(i),’]’,i=1,size(unnamed)) endif end program show_get_namelist_unix_prototype

OPTIONS

DESCRIPTION
  null or composed of all command arguments concatenated into a string prepared for reading as a NAMELIST group or a Unix-line command prototype string.

When creating a Unix-like prototype
o all values except logicals get a value.
o long names (--keyword) should be all lowercase
o short names (-letter) that are uppercase map to a NAMELIST variable called "letter_", but lowercase short names map to NAMELIST name "letter".
o strings MUST be delimited with double-quotes and must be at least one space and internal double-quotes are represented with two double-quotes
o lists of numbers should be comma-delimited. No spaces are allowed in lists of numbers.
o the values follow the rules for NAMELIST values, so "-p 2*0" for example would define two values.

ALL By default the output NAMELIST string only contains keywords and values for names that were specified on the command line. If ALL is .TRUE. a full NAMELIST string is returned containing all the variables from the input string.

RETURNS

STRING The output is a NAMELIST string than can be read to update the NAMELIST "ARGS" with the keywords that were supplied on the command line.
When using one of the Unix-like command line forms note that (subject to change) the following variations from other common command-line parsers:
 
o duplicate keywords are replaced by the rightmost entry
o numeric keywords are not allowed; but this allows negative numbers to be used as values.
o specifying both names of an equivalenced keyword will have undefined results (currently, their alphabetical order will define what the Fortran variable values become).
o there is currently no mapping of short names to long names except via an EQUIVALENCE.
o short keywords cannot be combined. -a -b -c is required, not -abc even for Boolean keys.
o shuffling is not supported. Values must follow their keywords.
o if a parameter value of just "-" is supplied it is converted to the string "stdin".
o if the keyword "--" is encountered the rest of the command arguments go into the character array "UNUSED".
o values not matching a keyword go into the character array "UNUSED".
o long names do not take the --KEY=VALUE form, just --KEY VALUE; and long names should be all lowercase and always more than one character.
o short-name parameters of the form -LETTER VALUE map to a NAMELIST name of LETTER_ if uppercase

AUTHOR

John S. Urban, 2019

LICENSE

Public Domain


get_namelist (3) March 11, 2021
Generated by manServer 1.08 from ab149478-f99c-48e0-a817-3b0779341d1b using man macros.