A configuration file is a text file which specifies values for some pre-defined keys. For example, the following configuration specifies a few values (some of which depend on other values) and has a comment that is ignored:

# example of a simple configuration file
data_dir:   ~/data
terra_dir:  %(data_dir)s/MODIS/Terra/C5
aqua_dir:   %(data_dir)s/MODIS/Aqua/C5

This config file can be read with:

IDL> config = mg_read_config('simple.ini')
IDL> print, config->get('terra_dir')

My configuration file reader supports sections, interpolation (substituting a variable into another one, as above), and default values.

The returned value for my reader is an object with three methods: has_option, get, and put, but also supports overloaded operators for brackets, PRINT, and HELP.

Let’s consider a more complicated configuration file, sections.ini:

# example of using sections to group items (notice the same name can be used in
# different sections without conflict)

# these are options in the default section that can be accessed from any other
# section
data_root:     ~/data
output_root:   %(data_dir)s/processed

# Terra specific options
[ Terra ]
subdir:        MODIS/Terra/C5
data:          %(data_root)s/%(subdir)s
output:        %(output_root)s/%(subdir)s
variables:     [ Longitude, Latitude, Optical_Depth_Land_And_Ocean ]
grid:          %(data_dir)s/grids/NCEP-T62.nc

# Aqua specific options
[ Aqua ]
subdir:        MODIS/Aqua/C5
data:          %(data_root)s/%(subdir)s
output:        %(output_root)s/%(subdir)s
variables:     [ Longitude, Latitude, Deep_Blue_Angstrom_Exponent_Land ]
grid:          %(data_dir)s/grids/MERRA-125x1.25.nc

Read this file in the same manner as the simpler one:

IDL> config = mg_read_config('sections.ini')

Use the has_option and get methods to determine if particular options are present and to retrieve their values:

IDL> print, config->has_option('data_root')
IDL> print, config->get('data_root')

To retrieve an option that is not in the default section, the SECTION keyword must be used:

IDL> print, config->get('data', section='Terra')
IDL> print, config->get('variables', section='Terra')
[ Longitude, Latitude, Optical_Depth_Land_And_Ocean ]

Arrays can be extracted during the get method, if that is more useful:

IDL> terra_vars = config->get('variables', section='Terra', /extract)
IDL> help, terra_vars
TERRA_VARS      STRING    = Array[3]
IDL> print, terra_vars
Longitude Latitude Optical_Depth_Land_And_Ocean

The HELP and PRINT routines are overloaded for the config object returned:

IDL> help, config
IDL> print, config
[  ]
  data_root: ~/data
  output_root: %(data_dir)s/processed

[ Aqua ]
  variables: [ Longitude, Latitude, Deep_Blue_Angstrom_Exponent_Land ]
  grid: %(data_dir)s/grids/MERRA-125x1.25.nc
  data: %(data_root)s/%(subdir)s
  output: %(output_root)s/%(subdir)s
  subdir: MODIS/Aqua/C5

[ Terra ]
  variables: [ Longitude, Latitude, Optical_Depth_Land_And_Ocean ]
  grid: %(data_dir)s/grids/NCEP-T62.nc
  data: %(data_root)s/%(subdir)s
  output: %(output_root)s/%(subdir)s
  subdir: MODIS/Terra/C5

The code is GitHub in my library.