Skip to content

Advanced Features

This page covers the more specialised argument types and CLI features.

Positional arguments

Positional arguments are matched by their position on the command line rather than by a switch name. They are defined with positional=.true. and a position index.

fortran
! first positional: required input file
call cli%add(positional=.true., position=1,    &
             help='Input data file',           &
             required=.true., act='store', error=error)

! second positional: optional scale factor
call cli%add(positional=.true., position=2,    &
             help='Scale factor',              &
             required=.false., act='store', def='1.0', error=error)

Retrieving positional values uses position= in get:

fortran
character(256) :: infile
real           :: scale

call cli%get(position=1, val=infile, error=error)
call cli%get(position=2, val=scale,  error=error)

Mixed usage (named + positional):

shell
$ ./myapp input.dat --output result.dat
$ ./myapp 2.5 --output result.dat      ! positional scale factor first

Restrictions: positional arguments cannot use exclude, envvar, or any action other than store.


Environment variable fallback

Any named, non-list, act='store' argument can fall back to an environment variable:

fortran
call cli%add(switch='--api-url', switch_ab='-u',               &
             help='API endpoint (or set MYAPP_URL env var)',    &
             required=.false., act='store', def='http://localhost', &
             envvar='MYAPP_URL', error=error)

Resolution order (highest priority first):

  1. Value supplied explicitly on the command line
  2. Value of the named environment variable
  3. Default value (def=)

This pattern is useful for configuration that belongs in CI secrets or shell profiles rather than command line flags.


Mutually exclusive argument pairs

Use exclude in add to declare two named arguments mutually exclusive. Either argument can name the other by its full or abbreviated switch:

fortran
call cli%add(switch='--json',  switch_ab='-j', &
             help='Output JSON format',        &
             required=.false., act='store_true', def='.false.', &
             exclude='--csv', error=error)

call cli%add(switch='--csv',   switch_ab='-c', &
             help='Output CSV format',         &
             required=.false., act='store_true', def='.false.', &
             exclude='--json', error=error)

If both are passed, FLAP prints an error before your code runs:

shell
$ ./myapp --json --csv
myapp: error: switches "--json" and "--csv" are mutually exclusive!

For mutually exclusive subcommands (groups), use set_mutually_exclusive_groups — see the Subcommands page.


Optional-value arguments (act='store*')

store* (note the asterisk) is a middle ground between store and store_true: the switch can appear with or without a value.

  • Present with a value → stores that value
  • Present without a value → stores the default
  • Absent → stores the default
fortran
call cli%add(switch='--format',                              &
             help='Output format; omit value for "text"',   &
             required=.false., act='store*', def='text', error=error)
shell
$ ./myapp --format json    ! stores 'json'
$ ./myapp --format        ! stores 'text' (default)
$ ./myapp                 ! stores 'text' (default)

Restrictions: store* cannot be used with nargs, envvar, or positional arguments. A default is mandatory.


Hidden arguments

Hidden arguments participate in parsing normally but are invisible in help and usage:

fortran
call cli%add(switch='--dump-internals',                       &
             help='Dump internal state to stderr (debug)',    &
             required=.false., act='store_true', def='.false.', &
             hidden=.true., error=error)

This keeps expert or debugging flags out of user-visible help without disabling them.


Choices constraint

fortran
call cli%add(switch='--solver', switch_ab='-s',                   &
             help='Linear solver',                                &
             required=.false., act='store', def='cg',             &
             choices='cg,gmres,bicgstab', error=error)

The check happens at get time:

shell
$ ./myapp --solver lu
myapp: error: the value "lu" is not in the choices list (cg,gmres,bicgstab)

Note: choices is not supported for get_varying (runtime-sized lists).


Runtime-sized list arguments

For lists whose length is not known at compile time, combine nargs='+' or nargs='*' with get_varying:

fortran
! one or more input files
call cli%add(switch='--inputs', switch_ab='-i',   &
             help='One or more input files',       &
             required=.false., act='store',        &
             nargs='+', def='', error=error)

! zero or more filter strings
call cli%add(switch='--filters', switch_ab='-f',  &
             help='Zero or more filters to apply', &
             required=.false., act='store',        &
             nargs='*', def='', error=error)

Retrieval:

fortran
character(256), allocatable :: inputs(:), filters(:)

call cli%get_varying(switch='--inputs',  val=inputs,  error=error)
call cli%get_varying(switch='--filters', val=filters, error=error)

do i = 1, size(inputs)
  print '(A)', 'Processing: ' // trim(inputs(i))
end do

Disabling automatic --help / --version

If your program already defines -h or -v for other purposes:

fortran
call cli%init(disable_hv=.true., ...)

FLAP will not add its default help/version switches. You remain responsible for printing help and version information yourself.


Fake command-line input (args)

Pass a string to parse or get to test your CLI without modifying argv:

fortran
! simulate: ./myprogram --solver gmres --niter 200
call cli%parse(args='--solver gmres --niter 200', error=error)

This is particularly useful in unit tests and doctests.