Modern Fortran command line parser, implemented with OOP.
program test
use iso_fortran_env, only: stdout => output_unit
use argparse
implicit none
character(len=10), parameter :: program_name = "qcalc"
type(argparser) :: args
args = argparser("A quantum physics calculation program.")
call args%set_program_name(program_name)
call args%add_help_option()
call args%add_sc_option("-v", "--version", "show version info", show_version_info)
call args%add_option_logical("-o", "--openmp", "use openmp or not") ! logical option has no default
call args%add_option_logical("-m", "--mpi", "use mpi or not")
call args%add_option_integer("-t", "--thread", "thread number,\nit is valid only if openmp is set", 1)
call args%add_option_integer("-p", "--process", "process number,\nit is valid only if mpi is set", 1)
call args%add_option_string("", "--chemical", "chemical formula", "H2O") ! short name can be empty
call args%add_named_argument_string("input", "initialize file")
call args%add_named_argument_string("output", "output file")
call args%parse()
if (args%has_option("--openmp")) then
print '(A,I2,A)', "openmp is used, and we use ", args%get_option_integer("-t"), " threads"
end if
if (args%has_option("--mpi")) then
print '(A,I2,A)', "mpi is used, and we use ", args%get_option_integer("-p"), " processes"
end if
print '(A,A)', "the calculated chemical is ", trim(args%get_option_string("--chemical"))
print '(A,A)', "the input file is ", trim(args%get_argument_string("input"))
print '(A,A)', "the output file is ", trim(args%get_argument_string("output"))
! you can also print the cached `args` into INI file
! print '(/,A)', "All of the options and arguments are shown below"
! call args%print_as_ini(stdout, .true.)
contains
subroutine show_version_info
print "(A)", trim(program_name)//" version 0.1.0"
end subroutine show_version_info
end program testCompile it as qclac, and use it like:
> qclac -?
usage: qcalc [options] [=input] [=output]
A quantum physics calculation program.
options:
-?, --help show this help message
-v, --version show version info
-o, --openmp use openmp or not
-m, --mpi use mpi or not
-t, --thread (integer [=1]) thread number,
it is valid only if openmp is set
-p, --process (integer [=1]) process number,
it is valid only if mpi is set
--chemical (string [=H2O]) chemical formula
named arguments:
input (string) initialize file
output (string) output file
> qclac -om -t 16 input=input.txt output=out.bin
openmp is used, and we use 16 threads
mpi is used, and we use 1 processes
the calculated chemical is H2O
the input file is input.txt
the output file is out.binThe simple way to use this package is copy the file src/argparse-f.f90 into your project. Or you can use fpm
[dependencies]
argparse-f = { git="https://github.com/0382/argparse-f.git" }In addition, argparse-f also supports the Meson build system.
In this package, command line arguments are classified into two kinds: option and argument.
As the name suggests, option is optional. It cantains two types: normal option and short curcuit option.
You can add normal options like this
call args%add_option_integer("-t", "--thread", "thread number", 1)The first dummy argument means short_name of the option, and it can be empty. If it is not empty, then it must be - followed by single character. The second dummy argument means long_name of the option, and it cannot be empty, it must start with --. The third dummy argument means help message, and the last one is the default value of the option.
In this version, normal option support five data types: logical, integer, real, real(kind=8), character(len=*) (add real(8) option method is add_option_double, and add character(len=*) option method is add_option_string).
add_option_logical function does not need the default value. Because, if you set the option in command line, the value is .true., otherwise the value is .false., for example:
ls -lthem -l option is set to .true.. To add the other four data types' options, you must give the default value, in case if one do not set the option, it use the default value. In command line, you should set the option like this:
greet --name Alice --age 24then the --name option is set to Alice and --age option is set to 24.
You can add short circuit options like this:
call args%add_sc_option("-v", "--version", "show version info", show_version_info)
contains
subroutine show_version_info
print "(A)", trim(program_name)//" version 0.1.0"
end subroutine show_version_infoA short circuit option must be logical type, and you should give a callback subroutine. The callback subroutine cannot have dummy arguments. Short circuit options are searched first, for example
git --help
gcc -vThe corresponding callback subroutine is called immediately as long as the program searched the first short circuit option, and then the program stop.
argument is opposited to option. You must set its value in command line. If not, the program will stop with error. argument also contains two types: position argument and named argument.
In this version, argument supports integer, real, real(kind=8), character(len=*) data types. It does not support logical type, you should use option instead.
Position argument is got with position, for exmple
ffplay video.mp4The video.mp4 is the first (and only) position argument. If you do not give the argument, the ffplay will exit with error.
Add position argument like this:
call args%add_argument_string("input", "initialize file")The first dummy argument is name of the argumet, and the second is the help message.
The named argument is defined by myself, it is designed for my work. It is used like this:
greet name=Alice age=24It is tedious comparing with position argument, so it should not be used in a common command line program. But it is useful in a big project, and you run program with a shell script. In this case, the named argument make the script more readable.
Add named argument like this:
call args%add_named_argument_string("input", "initialize file")Use functions like args%get_option_logical(name) to get option results. You can use both short_name and long_name. For logical data type, you can also use args%has_option(name) for short.
Use functions like args%get_argument_logical(name) to get argument results. Named argument and position argument cannot have duplicate name. So you can use this function to get either named argument or position argument.
Options cannot have same short_name or long_name, including normal options and short circuit options. Arguments also cannot have same name, including named arguments and position arguments.
In some linux command line programs, there are options I call them aggregate short name options. For example
ls -lahIt set three logical options -l, -a, -h at the same time. This package also support this feature. Remind that only logical type options are supported to be set in this way.
That's why options'
short_nameonly contians single character.
You can add default help option with args%add_help_option, it's short_name and long_name are -? and --help. If you dislike the names, you can add custom help option like this
call args%add_sc_option("-h", "--help", "show this help message", print_help)
contains
subroutine print_help
call args%print_help()
end subroutineUsing
-?is to save character space for other options'short_name. Not every one like it. Luckily it is simple to define your custom help option.
Some times, help message may be very long. You can use \n to as line break marker. Of course, Fortran does not have escape characters. I just use some character split technique to realize this feature.
You can print the argparser into INI file format. If the second dummy argument is set to .true., then print help message as comments.
call args%print_as_ini(stdout, .true.)If you give none command line argument and if it needs at least one argument, the program will call print_usage and exit. It is just the first line of print_help. set_program_name only affects program name in print_usage, if you does not set it, it will use argv[0].
This package works like my c++ package argparse. They are imspired by c++ package cmdline and python's standard library package argparse.