Skip to content

Defining Arguments ​

A FLAP program first describes its command line: init sets up the CLI (program name, help texts, behaviour), add declares each argument. Every code sample on this page is part of a program in docs/examples/src that is built and run to produce the outputs shown.

Initialising the CLI — cli%init ​

fortran
call cli%init(progname, version, help, description, license, authors, examples, epilog, disable_hv,        &
              usage_lun, error_lun, version_lun, error_color, error_style, ignore_unknown_clas, standalone, &
              error_hint, no_args_is_help, ignore_env, auto_envvar_prefix, case_insensitive,               &
              completion_options, usage_on_error, man_option, man_file, markdown_file)

Every argument is optional; pass them by keyword. Call init before add: it resets the CLI, and some settings (case_insensitive, auto_envvar_prefix) apply to the arguments added after it.

Texts

ArgumentTypeDefaultPurpose
prognamecharacter(*)the name the program was invoked with (argv[0]), else 'program'Program name in the usage line and in the messages
versioncharacter(*)'unknown'Printed by --version
helpcharacter(*)'usage: 'Text before the usage line
descriptioncharacter(*)''Shown below the usage line
licensecharacter(*)''License note (cli%license)
authorscharacter(*)''Authors (cli%authors)
examplescharacter(*), dimension(:)noneUsage examples, shown at the end of the help
epilogcharacter(*)''Printed after the help

Behaviour

ArgumentTypeDefaultPurpose
standalonelogical.true.After --help, --version, --markdown, ... end the program (exit status 0); .false.: parse returns a status instead (see Error Codes)
disable_hvlogical.false.Do not add the builtins --help, --version, --markdown
no_args_is_helplogical.false.With no arguments, print the help instead of parsing (STATUS_NO_ARGS; exit status 2 in standalone mode)
error_hintlogical.true.After a failed parse, print Try 'prog --help' for help. (see Error Codes)
usage_on_errorcharacter(*)'full'What a missing required option prints after its message: the whole help ('full'), the usage line ('usage') or nothing ('none'); see Errors
ignore_unknown_claslogical.false.Unknown arguments are not an error: nothing is printed, parse returns ERROR_UNKNOWN_CLAS_IGNORED (1004) and goes on, with the message of one of them in cli%error_message; also unknown configuration keys
case_insensitivelogical.false.Match switches (abbreviations and negations included) and command names in any case: --MESH is --mesh. Values and choices keep their case; two switches differing only by case are a consistency error (100)
ignore_envlogical.false.Turn every environment lookup off (see Advanced)
auto_envvar_prefixcharacter(*)noneGive every option an environment variable PREFIX[_COMMAND]_NAME (see Advanced)

Builtins and outputs

ArgumentTypeDefaultPurpose
completion_optionslogical.false.Add --show-completion [SHELL] and --install-completion [SHELL] (see Output)
man_optionlogical.false.Add --man: save the man page and stop (see Output)
man_filecharacter(*)<progname>.1File written by --man
markdown_filecharacter(*)<progname>.mdFile written by --markdown
usage_lun, error_lun, version_lunintegerstandard error, standard error, standard outputUnits of the help, of the errors and of the version (and of --show-completion)
error_color, error_stylecharacter(*)noneColour of the error/warning labels (see Output)

The examples of a character array constructor must all have the same length: pad the shorter ones with blanks.

f90
call cli%init(progname    = 'myapp',                         &
              version     = 'v1.0',                          &
              description = 'Demonstration program',         &
              examples    = ['myapp -i a.dat -o b.dat      ', &
                             'myapp -i a.dat -n 100 --tol 1'])
call cli%add(switch='--input',   switch_ab='-i', help='Input file',     required=.true.,  act='store', error=error)
call cli%add(switch='--output',  switch_ab='-o', help='Output file',    required=.false., act='store', def='out.dat', &
             error=error)
call cli%add(switch='--niter',   switch_ab='-n', help='Iterations',     required=.false., act='store', def='100', &
             error=error)
call cli%add(switch='--tol',     switch_ab='-t', help='Tolerance',      required=.false., act='store', def='1.0e-6', &
             error=error)
call cli%add(switch='--verbose',                 help='Verbose output', required=.false., act='store_true', &
             def='.false.', error=error)

Public attributes ​

The texts are public components of the CLI: cli%progname, cli%version, cli%description, cli%license, cli%authors, cli%epilog, and the examples cli%examples(i)%s; cli%error and cli%error_message hold the last error.

The builtin switches ​

FLAP adds to every CLI (the top level and each command):

SwitchAction
--help, -hPrint the help (STATUS_PRINT_H)
--version, -vPrint the version (STATUS_PRINT_V)
--markdown, -mdSave the help as Markdown, <progname>.md (STATUS_PRINT_M)
--Hidden: the arguments after it are not parsed, but collected in its own list (see Parsing)

and, when asked by init, the top-level --man (man_option), --show-completion and --install-completion (completion_options). Your own switches take precedence: if you define --version, the builtin is not added; if you take only its abbreviation (-v for verbosity), the builtin keeps just --version. disable_hv=.true. removes the three of them.


Adding arguments — cli%add ​

fortran
call cli%add(pref, group, group_index, switch, switch_ab, switch_neg, help, help_markdown, help_color, help_style, &
             required, val_required, positional, position, hidden, act, def, nargs, choices, exclude, envvar,    &
             must_exist, readable, writable, allow_dash, deprecated, min, max, min_open, max_open, clamp,         &
             case_sensitive, map, map_keys, metavar, error)

A named argument needs switch; a positional one positional=.true. and position. Every other argument is optional.

Core parameters ​

ArgumentTypeDefaultPurpose
switchcharacter(*)—Long switch name, e.g. '--output'
switch_abcharacter(*)switchAbbreviated switch, e.g. '-o'
switch_negcharacter(*)noneNegation of a flag, e.g. '--no-restart' (see Flag pairs)
helpcharacter(*)'Undocumented argument'Description in the help
requiredlogical.false.The argument must be given (on the command line, or by the environment or a configuration file)
actcharacter(*)'store'Action, see below (any case)
defcharacter(*)noneDefault value, as a string; blank separated for a list
metavarcharacter(*)'value'Placeholder of the value in the usage, help, man page and Markdown (see Metavar)
groupcharacter(*)top levelThe command the argument belongs to (see Subcommands)
hiddenlogical.false.Parsed, but not shown in the help, the usage and the completion
help_markdowncharacter(*)''Longer help, used by the Markdown output
help_color, help_stylecharacter(*)noneColour of the switch names in the help (see Output)
errorinteger—Error code of the definition (0 = success)

An optional argument (required=.false.) must have a default (def=..., even def=''): otherwise add returns ERROR_OPTIONAL_NO_DEF (1). Only count ('0') and alternate (.false.) have an implicit default: a flag needs def='.false.' (or '.true.').

The validation keywords (choices, min/max, the path checks, exclude, deprecated) and the value sources (envvar, configuration files) have their own sections below and in Advanced Features.

Actions (act) ​

ActionEffect
'store'Stores the value(s) passed after the switch
'store*'The value is optional: the switch alone gives the default
'store_true'A flag: .true. when passed, otherwise its def
'store_false'A flag: .false. when passed, otherwise its def
'count'Counts the occurrences (-v -v, -vv, --verbose -v give 2); read into an integer; def defaults to '0'
'append'One value per occurrence (-I src --include=lib gives [src, lib]); read with get_varying. Passed values replace the default
'alternate'An auxiliary action (--list-models): parse returns STATUS_ALTERNATE and skips the value checks (see Advanced)
'config'Names the configuration file (see Advanced)
'print_help', 'print_version'Print the help, the version (the actions of the builtins)
f90
! count: -v -v, -vv or --verbose --verbose give 2
call cli%add(switch='--verbose', switch_ab='-v', help='Verbosity (repeatable)', required=.false., act='count')
! append: one value per occurrence
call cli%add(switch='--include', switch_ab='-I', help='Include directory (repeatable)', required=.false., &
             act='append', def='.')
! store*: the value is optional, the switch alone gives the default
call cli%add(switch='--format', help='Output format', required=.false., act='store*', def='text')
! a flag with its negation: the last one passed wins
call cli%add(switch='--restart', switch_neg='--no-restart', help='Restart from the checkpoint', required=.false., &
             act='store_true', def='.true.')
! a hidden flag: parsed, but not shown in the help
call cli%add(switch='--debug-internal', help='Internal debug flag', required=.false., act='store_true', def='.false.', &
             hidden=.true.)
f90
call cli%get(switch='--verbose', val=verbosity, error=error)
call cli%get_varying(switch='--include', val=include, error=error)
call cli%get(switch='--format', val=format, error=error)
call cli%get(switch='--restart', val=restart, error=error)
$ actions -vv -I src --include=lib --format --no-restart
verbosity = 2
include   = src, lib
format    = text
restart   = F
$ actions
verbosity = 0
include   = .
format    = text
restart   = T

-vv is two -v; --format=json gives a value inline (see Parsing); the hidden --debug-internal does not appear in the help:

$ actions --help
usage: actions [--verbose]... [--include value]... [--format [value]] [--restart/--no-restart] [--help] [--markdown] [--version]

The actions of FLAP

Optional switches:
  --verbose, -v
      default value 0
      Verbosity (repeatable)
  --include, -I
      default value .
      Include directory (repeatable)
  --format [value]
      default value text
      Output format
  --restart/--no-restart
      default value .true.
      Restart from the checkpoint
  --help, -h
      Print this help message
  --markdown, -md
      Save this help message in a Markdown file
  --version
      Print version

Metavar ​

metavar names the value in the usage, the help, the man page and the Markdown output, instead of the generic value. A list numbers it (NAME#1 ...); for a map it replaces KEY=VALUE; a flag ignores it (it takes no value); a positional shows it alone. The shell completion never shows placeholders.

f90
call cli%add(switch='--mesh', help='Mesh file', required=.true., act='store', metavar='FILE')
! exactly 3 values
call cli%add(switch='--coords', help='X Y Z of the probe', required=.false., act='store', nargs='3', def='0 0 0')
! zero or more values: the switch alone is an empty list
call cli%add(switch='--fields', help='Fields to save', required=.false., act='store', nargs='*', def='u', &
             metavar='NAME')
! one or more values
call cli%add(switch='--weights', help='Weights', required=.false., act='store', nargs='+', def='1.0')
$ lists --help
usage: lists --mesh FILE [--coords value#1 value#2 value#3] [--fields [NAME#1 NAME#2...]] [--weights value#1 [value#2...]] [--help] [--markdown] [--version]

Required switches:
  --mesh FILE
      Mesh file

Optional switches:
  --coords value#1 value#2 value#3
      default value 0 0 0
      X Y Z of the probe
  --fields [NAME#1 NAME#2...]
      default value u
      Fields to save
  --weights value#1 [value#2...]
      default value 1.0
      Weights
  --help, -h
      Print this help message
  --markdown, -md
      Save this help message in a Markdown file
  --version, -v
      Print version

Flag pairs (switch_neg) ​

A store_true or store_false flag can have a negation, which sets the opposite value (--restart/--no-restart in the example above):

Command linerestart
(absent)the default, or the environment or configuration value
--restart.true.
--no-restart.false.
--restart --no-restart.false.: the last one wins
--no-restart --restart.true.
--restart --restartERROR_DUPLICATED_CLAS (23)

The last spelling wins, as in click and GNU tools, so a preset can be overridden: with alias run='solver --restart', run --no-restart does not restart. Each spelling may appear once. The help shows the pair as [--restart/--no-restart]; the completion offers both names; get and is_passed accept either name. The negation belongs to a named scalar flag and differs from its switch names: otherwise add reports ERROR_SWITCH_NEG_INCONSISTENT (36); a negation equal to the switch of another argument is a group consistency error (100).

Restricted choices (choices) ​

choices is a comma-separated list of the allowed values, checked by get (and by get_varying, on every value of a list, the default included). With case_sensitive=.false., a character value matches its choice in any case and get returns the declared spelling. choices cannot be used with logical values (ERROR_CHOICES_LOGICAL, 11).

f90
call cli%add(switch='--level', switch_ab='-l', help='Verbosity level', required=.false., act='store', def='1', &
             choices='1,3,5')
! case_sensitive=.false.: WENO5 matches weno5, and get returns the declared spelling
call cli%add(switch='--scheme', help='Space scheme', required=.false., act='store', def='muscl', &
             choices='weno5,muscl', case_sensitive=.false.)
$ choices --level 3 --scheme WENO5
level = 3, scheme = weno5
$ choices --level 2
choices: error: value of named option "--level" must be chosen in: (1,3,5) but "2" has been passed!

[exit status 1]

List-valued arguments (nargs) ​

nargsMeaningRead with
'N' (a positive integer)Exactly N values: the switch takes the next N arguments; a further one is the next argumentget into an array of N elements
'+'One or more valuesget_varying
'*'Zero or more values: the switch alone is an empty list, the default applies only when the switch is absentget_varying
f90
call cli%get(switch='--mesh', val=mesh, error=error)
call cli%get(switch='--coords', val=coords, error=error)          ! a fixed-size array of the right size
call cli%get_varying(switch='--fields', val=fields, error=error)   ! allocatable arrays, any size
call cli%get_varying(switch='--weights', val=weights, error=error)
$ lists --mesh wing.grd --coords 1 2 3 --fields u v p --weights 0.5 0.25
mesh    = wing.grd
coords  = 1 2 3
fields  = (3) u v p
weights =  0.50  0.25
$ lists --mesh wing.grd --fields
mesh    = wing.grd
coords  = 0 0 0
fields  = (0) 
weights =  1.00
$ lists --mesh wing.grd --coords 1 2
lists: error: option "--coords" requires 3 values!

Try 'lists --help' for help.
[exit status 1]

A list with a variable number of values ('+', '*') ends at the next switch or at the first command name. With nargs='N' the default must have exactly N values (ERROR_DEF_NARGS, 48); '+' and '*' accept a default of any length. A list cannot take an inline value (--coords=1, ERROR_INLINE_VALUE_NARGS).

Key=value options (map) ​

With map=.true., a list option takes KEY=VALUE pairs, typically to override the parameters of an input deck; map_keys restricts the keys:

f90
call cli%add(switch='--set', switch_ab='-s', help='Override input-deck parameters', required=.false., act='store', &
             nargs='+', map=.true., map_keys='cfl,nx,ny,t_end', def='cfl=0.8')
f90
cfl = 0.9_8 ; nx = 128                                                 ! the values of the input deck
call cli%get_map_value(switch='--set', key='cfl', val=cfl, found=found) ! overridden only if given
call cli%get_map_value(switch='--set', key='nx',  val=nx,  found=found)
$ map --set cfl=0.5 nx=256
cfl = 0.50, nx = 256
$ map
cfl = 0.80, nx = 128
$ map --set cfll=0.5
map: error: unknown key "cfll" for "--set" (allowed: cfl, nx, ny, t_end)! Did you mean "cfl"?

Try 'map --help' for help.
[exit status 1]
  • A pair is split at the first =: label=a=b is the key label with the value a=b; a= has an empty value.
  • A map is a named act='store' option with nargs ('+', '*' or a number), or act='append' (--set a=1 --set b=2); --set=a=1 is one pair. Positionals, flags and choices are not allowed (ERROR_MAP_INCONSISTENT, 42).
  • parse checks the pairs, whatever their source (command line, environment as comma-separated pairs, configuration file as blank-separated pairs, default): ERROR_MAP_FORMAT (38), ERROR_MAP_DUPLICATE_KEY (39), and, with map_keys, ERROR_MAP_UNKNOWN_KEY (40). Keys are case-sensitive.
  • Passed pairs replace the default ones, they are not merged.
  • cli%get_map(switch, keys, values, group, error) returns all the pairs, in order, into character(len=...), allocatable arrays. cli%get_map_value(switch, key, val, found, group, error) converts one value to the type of val (any kind get supports); a missing key leaves val untouched and sets found=.false., or is ERROR_MAP_KEY_MISSING (41) without found.
  • The usage shows [--set KEY=VALUE [KEY=VALUE...]], and the help lists keys: cfl, nx, ny, t_end.

Mutually exclusive arguments (exclude) ​

exclude names another switch of the group that cannot be passed together with this one:

f90
call cli%add(switch='--json', help='JSON output', required=.false., act='store_true', def='.false.', exclude='--csv')
call cli%add(switch='--csv',  help='CSV output',  required=.false., act='store_true', def='.false.', exclude='--json')
$ exclusive --mesh m.grd --json --csv
exclusive: error: the options "--json" and "--csv" are mutually exclusive, but both have been passed!

Try 'exclusive --help' for help.
[exit status 1]

exclude is pairwise and cannot be combined with required=.true.: for more than two switches, or to require exactly one of them, use a mutually exclusive set.

Environment variables (envvar) ​

envvar names a variable supplying the value when the switch is not on the command line (see Advanced for the lists, the flags and the generated names):

f90
call cli%init(progname='environment', auto_envvar_prefix='SOLVER')
call cli%add(switch='--mesh-file', help='Mesh', required=.true., act='store')                   ! SOLVER_MESH_FILE
call cli%add(switch='--workers', help='Workers', required=.false., act='store', nargs='+', def='1') ! SOLVER_WORKERS
call cli%add(switch='--fast', help='Fast mode', required=.false., act='store_true', def='.false.')  ! SOLVER_FAST
call cli%add(switch='--token', help='API token', required=.false., act='store', def='none', envvar='MY_TOKEN')

Resolution order, highest priority first: the command line, the environment variable (set and not blank), a configuration file, the default. A value from the environment satisfies a required argument; is_passed stays .false. (it means "on the command line").

Positional arguments ​

A positional argument is matched by its position among the values that are not switches (nor switch values), wherever they appear: prog in.dat --verbose 2.0 and prog --verbose in.dat 2.0 are the same.

f90
call cli%add(positional=.true., position=1, help='Input file', required=.true., act='store', metavar='INPUT')
call cli%add(positional=.true., position=2, help='Scale factor', required=.false., act='store', def='1.0', &
             metavar='SCALE')
call cli%add(switch='--verbose', help='Verbose', required=.false., act='store_true', def='.false.')
f90
call cli%get(position=1, val=input, error=error)
call cli%get(position=2, val=scale, error=error)
$ positional in.dat 2.5
input = in.dat, scale = 2.50, verbose = F
$ positional --verbose in.dat
input = in.dat, scale = 1.00, verbose = T
$ positional in.dat 2 3
positional: error: argument "3" is unknown!

Try 'positional --help' for help.
[exit status 1]

An argument that looks like a switch (a dash followed by anything but a digit or a dot) is never taken as a positional value, so -3.5 and - are values while --bogus is an unknown switch. A value beyond the last position is an unknown argument.

Restrictions: a positional must use act='store' and cannot use exclude, envvar or nargs. Positions may be declared in any order, but they must be 1..N without duplicates: a position declared twice is an error at add (ERROR_POSITION_DUPLICATE, 105), a missing position (1 and 3 without 2) is an error when parsing starts (ERROR_POSITION_GAP, 106).