| / UCI ESS / Zender Group / SNG / | [G95] [Gfortran] |
SNG is a portable fortran9X/2K command line parser and
string manipulation library.
SNG comprises subroutines for parsing GNU/POSIX-style long
command-line options a la the GNU getopt_long() package.
SNG is written in pure Fortran9X/200X so that your modern fortran
codes can kick the namelist habit.
License:
The core library, sng_mdl.F90, has a free, non-restrictive,
non-copyleft, GPL-compatible, X11-style license.
The demo front end program, sng.F90, and a supporting
utility, dbg_mdl.F90, which are both cleanly segregable
from the core library, are in the public domain.
The nascent SNG documentation is a simple text format file:
zender@lanina:~/f$ pgf90 -o dbg_mdl.o -c dbg_mdl.F90
zender@lanina:~/f$ pgf90 -o sng_mdl.o -c sng_mdl.F90
zender@lanina:~/f$ pgf90 -o sng sng_mdl.o dbg_mdl.o sng.F90
zender@lanina:~/f$ sng --dbg=0 --dbl=1.234e234 --flt=-5.67e-37 --int=12345678 --lgc=T --sng="GNU's Not UNIX" --drc_out=${HOME}/output/directory
Before command line parsing and string manipulation:
main() reports cmd_ln =
main() reports dbl_foo = 0.0000000000000000E+000
main() reports flt_foo = 0.0000000E+00
main() reports int_foo = 1
main() reports lgc_foo = F
main() reports sng_foo = Default value
main() reports fl_in = in.nc
main() reports fl_out = foo.nc
main() reports drc_in = /home/user/input/dir
main() reports drc_out =
After command line parsing and string manipulation:
main() reports cmd_ln =
sng --dbg=0 --dbl=1.234e234 --flt=-5.67e-37 --int=12345678 --lgc=T --sng=GNU's Not UNIX --drc_out=/home/zender/output/directory
main() reports dbl_foo = 1.2339999999999977E+234
main() reports flt_foo = -5.6700002E-37
main() reports int_foo = 12345678
main() reports lgc_foo = T
main() reports sng_foo = GNU's Not UNIX
main() reports fl_in = /home/user/input/dir/in.nc
main() reports fl_out = /home/zender/output/directory/foo.nc
main() reports drc_in = /home/user/input/dir
main() reports drc_out = /home/zender/output/directory
The Fortran variables have their type-specific default values until
SNG and parses the command line options.
How much code overhead does it take to implement this getopt_long()-like capability in the front end program? Certainly not more than a namelist parsing routine! The above command line parser was implemented with
arg_nbr=command_argument_count() ! [nbr] Number of command line arguments
arg_idx=1 ! [idx] Counting index
do while (arg_idx <= arg_nbr)
call ftn_getarg_wrp(arg_idx,arg_val) ! [sbr] Call getarg, increment arg_idx
dsh_key=arg_val(1:2) ! [sng] First two characters of option
if (dsh_key == "--") then
opt_lng=ftn_opt_lng_get(arg_val) ! [nbr] Length of option
if (opt_lng <= 0) stop "Long option has no name"
opt_sng=arg_val(3:2+opt_lng) ! [sng] Option string
if (dbg_lvl >= dbg_io) write (6,"(5a,i3)") prg_nm(1:ftn_strlen(prg_nm)), &
": DEBUG Double hyphen indicates multi-character option: ", &
"opt_sng = ",opt_sng(1:ftn_strlen(opt_sng)),", opt_lng = ",opt_lng
if (opt_sng == "dbg" .or. opt_sng == "dbg_lvl" ) then
call ftn_arg_get(arg_idx,arg_val,dbg_lvl) ! [enm] Debugging level
else if (opt_sng == "dbl" .or. opt_sng == "dbl_foo" ) then
call ftn_arg_get(arg_idx,arg_val,dbl_foo) ! [frc] Double
else if (opt_sng == "drc_in") then
call ftn_arg_get(arg_idx,arg_val,drc_in) ! [sng] Input directory
else if (opt_sng == "drc_out") then
call ftn_arg_get(arg_idx,arg_val,drc_out) ! [sng] Output directory
else if (opt_sng == "fl_in") then
call ftn_arg_get(arg_idx,arg_val,fl_in) ! [sng] Input file
else if (opt_sng == "fl_out") then
call ftn_arg_get(arg_idx,arg_val,fl_out) ! [sng] Output file
else if (opt_sng == "flt" .or. opt_sng == "flt_foo" ) then
call ftn_arg_get(arg_idx,arg_val,flt_foo) ! [frc] Float
else if (opt_sng == "int" .or. opt_sng == "int_foo" ) then
call ftn_arg_get(arg_idx,arg_val,int_foo) ! [nbr] Integer
else if (opt_sng == "lgc" .or. opt_sng == "lgc_foo" ) then
call ftn_arg_get(arg_idx,arg_val,lgc_foo) ! [lgc] Logical
else if (opt_sng == "sng" .or. opt_sng == "sng_foo") then
call ftn_arg_get(arg_idx,arg_val,sng_foo) ! [sng] String
else ! Option not recognized
arg_idx=arg_idx-1 ! [idx] Counting index
call ftn_getarg_err(arg_idx,arg_val) ! [sbr] Error handler for getarg()
endif ! endif option is recognized
! Jump to top of while loop
cycle ! C, F77, and F90 use "continue", "goto", and "cycle"
endif ! endif long option
! Handle short options
if (dsh_key == "-D") then
call ftn_arg_get(arg_idx,arg_val,dbg_lvl) ! [enm] Debugging level
else if (dsh_key == "-f") then
call ftn_arg_get(arg_idx,arg_val,flt_foo) ! [frc] Float
else if (dsh_key == "-i") then
call ftn_arg_get(arg_idx,arg_val,fl_in) ! [sng] Input file
else if (dsh_key == "-l") then
call ftn_arg_get(arg_idx,arg_val,int_foo)
else if (dsh_key == "-p") then
lgc_foo=.not.lgc_foo
else if (dsh_key == "-o") then
call ftn_arg_get(arg_idx,arg_val,fl_out) ! [sng] Output file
else if (dsh_key == "-s") then
call ftn_arg_get(arg_idx,arg_val,sng_foo) ! [sng] String
else if (dsh_key == "-v") then
goto 1000 ! Goto exit with error status
else ! Option not recognized
arg_idx=arg_idx-1 ! [idx] Counting index
call ftn_getarg_err(arg_idx,arg_val) ! [sbr] Error handler for getarg()
endif ! endif arg_val
end do ! end while (arg_idx <= arg_nbr)
! Compute any quantities that might depend on command line input
! Prepend user-specified path, if any, to input data file names
if (ftn_strlen(drc_in) > 0) call ftn_drcpfx(drc_in,fl_in) ! [sng] Input file
! Prepend user-specified path, if any, to output data file names
if (ftn_strlen(drc_out) > 0) call ftn_drcpfx(drc_out,fl_out) ! [sng] Output file
which is admittedly overkill in that it includes comments, debugging
code, and short option equivalents to certain long options.
ftn_arg_get(), which is overloaded for all data types,
implements the bulk of the work so SNG has the same interface
for all data types.
The distribution includes the complete SNG source code necessary to build and run SNG on your own machine.
CVS access to SNG will come soon if someone asks me for it