Skip to content

API Reference ​

FiNeR exposes a single module:

fortran
use finer

The module re-exports everything from the internal modules. The primary user-facing type is file_ini.

file_ini type ​

Public members ​

MemberTypeDescription
filenamecharacter(len=:), allocatablePath of the INI file (set automatically by load/save, or set directly)

Public methods ​

MethodDescription
freeFree all dynamic memory, resetting the object
loadLoad INI data from a file or string
has_optionInquire whether an option exists
has_sectionInquire whether a section exists
sectionGet a section name by index
sections_numberReturn the number of sections
indexGet the index of a named section or option
count_valuesCount the number of space-separated values in an option
addAdd a section or option (updates value if option already exists)
getGet an option value, with an optional default
get_stringGet an option value as an allocatable string
delDelete a section or option
itemsReturn all option name/value pairs as a 2-D array
loopIterate over options with a do while loop
printPretty-print file data to a Fortran unit
saveSave file data to a physical file

free ​

Safely resets a file_ini variable, deallocating all sections and options. Use this before re-loading new data into an existing variable.

fortran
use finer
type(file_ini) :: fini

call fini%load(filename='old.ini')
! ... work with old data ...
call fini%free
call fini%load(filename='new.ini')

load ​

Loads INI data. Either filename or source must be provided; if both are given, filename takes priority.

Signature:

fortran
call fini%load(filename=, source=, separator=, error=)
ArgumentIntentTypeDescription
filenamein, optionalcharacter(*)Path to the INI file
sourcein, optionalcharacter(*)INI content as a string
separatorin, optionalcharacter(1)Option separator (default =)
errorout, optionalintegerError code (0 = success)
fortran
use finer
type(file_ini)                :: fini
character(len=:), allocatable :: source

! Load from file with custom separator
call fini%load(filename='config.ini', separator=':')

! Load from an in-memory string
call fini%free
source = '[section-1]'//new_line('A')// &
         'option-1 = one'//new_line('A')// &
         'option-2 = 2.'//new_line('A')// &
         '           3. ; inline comment'//new_line('A')// &
         '[section-2]'//new_line('A')// &
         'option-1 = foo'
call fini%load(source=source)

has_option ​

Returns .true. if the named option exists anywhere in the file (or within a specific section). Optionally returns the name of the section containing the first match.

fortran
use finer
type(file_ini)   :: fini
character(100)   :: sec_name
logical          :: found

call fini%load(filename='config.ini')

found = fini%has_option(option_name='host')

! Also get the containing section name
found = fini%has_option(option_name='host', section_name=sec_name)
if (found) print *, 'host is in section: ', trim(sec_name)

INFO

section_name is a fixed-length buffer. If the actual section name is longer than the buffer, the returned name is truncated.


has_section ​

Returns .true. if the named section exists.

fortran
use finer
type(file_ini) :: fini

call fini%load(filename='config.ini')

if (fini%has_section(section_name='database')) then
  print *, 'database section found'
end if

section ​

Returns the name of the section at position i. Use with sections_number() to loop over all sections.

fortran
use finer
type(file_ini)                :: fini
character(len=:), allocatable :: sec_name
integer                       :: s

call fini%load(filename='config.ini')

do s = 1, fini%sections_number()
  sec_name = fini%section(s)
  print *, 'Section: ', sec_name
end do

index ​

Returns the index of a section, or of an option within a section. Returns 0 if not found. The optional back=.true. argument returns the last matching occurrence instead of the first.

Signatures:

fortran
i = fini%index(section=, back=)          ! index of section
i = fini%index(section=, option=, back=) ! index of option in section
fortran
use finer
type(file_ini) :: fini
integer        :: s, o

call fini%load(filename='config.ini')

s = fini%index(section_name='database')
if (s > 0) print *, 'database is section #', s

o = fini%index(section_name='database', option_name='host')
if (o > 0) print *, 'host is option #', o, ' in database'

count_values ​

Counts the number of space-separated tokens in an option's value. Useful for allocating arrays before calling get.

fortran
use finer
type(file_ini)      :: fini
integer, allocatable :: array(:)
integer              :: Nv

call fini%load(source='[foo]'//new_line('A')//'array = 1 2 3 4 5')

Nv = fini%count_values(section_name='foo', option_name='array')
allocate(array(1:Nv))
call fini%get(section_name='foo', option_name='array', val=array)
print *, array   ! 1 2 3 4 5

add ​

Adds a section, or adds/updates an option within a section. If the section does not exist, it is created automatically. If the option already exists, its value is updated.

Signatures:

fortran
call fini%add(section=)                      ! add section only
call fini%add(section=, option=, val=)       ! add/update option
call fini%add(section=, option=, val=, delimiter=)  ! array with delimiter

val is unlimited polymorphic — pass any intrinsic scalar or array.

fortran
use finer
use penf, only: R8P
type(file_ini) :: fini

call fini%add(section_name='sec-foo')
call fini%add(section_name='sec-foo', option_name='bar',   val=-32.1_R8P)
call fini%add(section_name='sec-foo', option_name='baz',   val=' hello FiNeR! ')
call fini%add(section_name='sec-foo', option_name='array', val=[1, 2, 3, 4])
call fini%add(section_name='sec-bar')
call fini%add(section_name='sec-bar', option_name='bools', val=[.true., .false., .false.])

get ​

Retrieves an option value. The receiving variable (val) can be a scalar or an array of integer, real, complex, logical or character type. The optional delimiter argument specifies the separator between array values (default: space).

fortran
use finer
use penf, only: I4P
type(file_ini)       :: fini
integer(I4P)         :: error
integer, allocatable :: arr(:)
character(64)        :: host

call fini%load(filename='config.ini')

call fini%get(section_name='database', option_name='host',  val=host,  error=error)
allocate(arr(1:fini%count_values(section_name='foo', option_name='array')))
call fini%get(section_name='foo',      option_name='array', val=arr,   error=error)
if (error == 0) print *, arr

TIP

Always allocate the receiving array to the correct size with count_values before calling get with an array val. If val is too small to hold all the values, get returns an error and leaves val unchanged.

Errors ​

error is 0 on success. Otherwise val is left unchanged and error tells why:

ErrorMeaning
ERR_OPTIONthe section or the option does not exist
ERR_OPTION_VALSthe option has no value, the value cannot be converted to the type of val (e.g. abc or 1.5 read into an integer, an integer too big for the kind of val), the type of val is not supported, or an array val is too small

Default values ​

Pass default= to give val a fallback value whenever the option cannot be got. error still reports what happened, so a default can be told from a value read from the file.

fortran
use finer
use penf, only: I4P, R8P
type(file_ini) :: fini
integer(I4P)   :: error
real(R8P)      :: radius
integer        :: steps
real(R8P)      :: origin(3)

call fini%load(filename='config.ini')

call fini%get(section_name='cylinder', option_name='radius', val=radius, default=-1._R8P)
call fini%get(section_name='cylinder', option_name='steps',  val=steps,  default=0, error=error)
if (error /= 0) print *, 'steps not found or not valid, using ', steps
call fini%get(section_name='cylinder', option_name='origin', val=origin, default=[0._R8P, 0._R8P, 0._R8P])

A complex val accepts a complex, real or integer default of any kind. A real val accepts a real or integer default of any kind, an integer val accepts an integer default of any kind that it can represent, a logical or character val accepts a default of the same type. An array default must have the same size as val. A default that does not fit these rules is ignored: val is left unchanged.

Complex values ​

Complex values use the Fortran notation, (real,imaginary), with or without blanks inside the parentheses.

ini
[cylinder]
epsilon = (80., 1.0d-4) ; water permittivity
modes   = (1.0, 2.0) (3.0, 4.0)
fortran
use finer
use penf, only: R8P
type(file_ini)            :: fini
complex(R8P)              :: epsilon
complex(R8P), allocatable :: modes(:)

call fini%load(filename='config.ini')

call fini%get(section_name='cylinder', option_name='epsilon', val=epsilon)
allocate(modes(1:fini%count_values(section_name='cylinder', option_name='modes')))
call fini%get(section_name='cylinder', option_name='modes', val=modes)

call fini%add(section_name='cylinder', option_name='mu', val=(1._R8P, 0._R8P))   ! written as (1.0,0.0)

In a list of complex values each value is delimited by its parentheses, so the delimiter (blank by default) can also appear inside a value. count_values counts the parenthesised groups when the whole option value starts with ( and ends with ).

A value without parentheses (80. 1.0d-4) is not a complex value: reading it into a complex variable returns ERR_OPTION_VALS.


get_string ​

Retrieves an option value into a deferred-length allocatable string, which is (re)allocated to the exact length of the value. Unlike get, the receiving variable does not need to be allocated, or long enough, before the call.

fortran
use finer
use penf, only: I4P
type(file_ini)                :: fini
integer(I4P)                  :: error
character(len=:), allocatable :: host

call fini%load(filename='config.ini')

call fini%get_string(section_name='database', option_name='host', val=host, error=error)
call fini%get_string(section_name='database', option_name='user', val=host, default='nobody')

If the section or the option does not exist, or the option has no value, an error is returned and val is set to default, if passed, otherwise it is left unchanged.

WARNING

get with a character val needs an already allocated variable and silently truncates a value longer than val. Prefer get_string for strings of unknown length.


del ​

Deletes a section (and all its options) or a single option within a section.

fortran
use finer
type(file_ini) :: fini

call fini%load(filename='config.ini')

call fini%del(section_name='sec-foo', option_name='bar')  ! delete one option
call fini%del(section_name='sec-bar')                     ! delete whole section

WARNING

Deleting a section removes all of its options.


items ​

Returns a (N, 2) allocatable character array where each row holds [option_name, option_value] as strings.

fortran
use finer
type(file_ini)                :: fini
character(len=:), allocatable :: it(:,:)
integer                       :: i

call fini%load(filename='config.ini')

it = fini%items(section_name='database')
do i = 1, size(it, dim=1)
  print *, trim(it(i,1)), ' = ', trim(it(i,2))
end do

loop ​

Provides a do while iteration over options. Returns .true. and fills option(:) with [name, value] on each call; returns .false. when exhausted and resets the internal counter.

The state of a loop is stored in the file_ini object, so the object must be a variable (not an intent(in) dummy argument), and loops over different sections or different files do not interfere. Run a loop to completion before starting a new one over the same section.

Signatures:

fortran
do while (fini%loop(option_pairs=opt))             ! all options in file
do while (fini%loop(section_name=, option_pairs=)) ! options in one section
fortran
use finer
type(file_ini)                :: fini
character(len=:), allocatable :: opt(:)

call fini%load(filename='config.ini')

! Iterate over all options in 'database' section
do while (fini%loop(section_name='database', option_pairs=opt))
  print *, trim(opt(1)), ' = ', trim(opt(2))
end do

! Iterate over every option in the entire file
do while (fini%loop(option_pairs=opt))
  print *, trim(opt(1)), ' = ', trim(opt(2))
end do

print ​

Pretty-prints all file data to a Fortran I/O unit.

ArgumentIntentTypeDescription
unitinintegerFortran unit number (6 = stdout)
prefin, optionalcharacter(*)Line prefix string
iostatout, optionalintegerI/O status
iomsgout, optionalcharacter(*)I/O error message
retain_commentsin, optionallogicalPrint inline comments (default .false.)
fortran
use finer
type(file_ini) :: fini
integer        :: iostat
character(200) :: iomsg

call fini%load(filename='config.ini')
call fini%print(unit=6, pref='|-->', iostat=iostat, iomsg=iomsg)
call fini%print(unit=6, retain_comments=.true.)

save ​

Saves file data to a physical file. If filename is not passed, the value of the filename public member is used (which may have been set by a previous load call).

ArgumentIntentTypeDescription
filenamein, optionalcharacter(*)Output file path
iostatout, optionalintegerI/O status
iomsgout, optionalcharacter(*)I/O error message
retain_commentsin, optionallogicalWrite inline comments (default .false.)
fortran
use finer
use penf, only: R8P
type(file_ini) :: fini
integer        :: iostat
character(200) :: iomsg

call fini%add(section_name='sec-foo', option_name='bar', val=-32.1_R8P)
call fini%save(filename='foo.ini', iostat=iostat, iomsg=iomsg)
call fini%save(filename='foo-with-comments.ini', retain_comments=.true.)

Error codes ​

Defined in module finer_backend and re-exported by finer:

ConstantValueMeaning
ERR_OPTION_NAME1Bad option name
ERR_OPTION_VALS2Bad option values
ERR_OPTION3Generic option error
ERR_SECTION_NAME4Bad section name
ERR_SECTION_OPTIONS5Bad section options
ERR_SECTION6Generic section error
ERR_SOURCE_MISSING7No source provided to load