The task is to read a configuration file in standard configuration file format,
and set variables accordingly.

For this task, we have a configuration file as follows:

# This is a configuration file in standard configuration file format
#
# Lines beginning with a hash or a semicolon are ignored by the application
# program. Blank lines are also ignored by the application program.

# This is the fullname parameter
FULLNAME Foo Barber

# This is a favourite fruit
FAVOURITEFRUIT banana

# This is a boolean that should be set
NEEDSPEELING

# This boolean is commented out
; SEEDSREMOVED

# Configuration option names are not case sensitive, but configuration parameter
# data is case sensitive and may be preserved by the application program.

# An optional equals sign can be used to separate configuration parameter data
# from the option name. This is dropped by the parser. 

# A configuration option may take multiple parameters separated by commas.
# Leading and trailing whitespace around parameter names and parameter data fields
# are ignored by the application program.

OTHERFAMILY Rhu Barber, Harry Barber



For the task we need to set four variables according to the configuration entries as follows:

fullname = Foo Barber
favouritefruit = banana
needspeeling = true
seedsremoved = false


We also have an option that contains multiple parameters. These may be stored in an array.

 otherfamily(1) = Rhu Barber
 otherfamily(2) = Harry Barber


Related tasks
 Update a configuration file


#!/usr/bin/instantfpc
 
{$if not defined(fpc) or (fpc_fullversion < 20600)}
  {$error FPC 2.6.0 or greater required}
{$endif}
 
{$mode objfpc}{$H+}
 
uses
  Classes,SysUtils,gvector,ghashmap;
 
type
  TStrHashCaseInsensitive = class
    class function hash(s: String; n: Integer): Integer;
  end;
 
class function TStrHashCaseInsensitive.hash(s: String; n: Integer): Integer;
var
  x: Integer;
  c: Char;
begin
  x := 0;
  for c in UpCase(s) do Inc(x,Ord(c));
  Result := x mod n;
end;
 
type
  TConfigValues  = specialize TVector<String>;
  TConfigStorage = class(specialize THashMap<String,TConfigValues,TStrHashCaseInsensitive>)
    destructor Destroy; override;
  end;
 
destructor TConfigStorage.Destroy;
var
  It: TIterator;
begin
  if Size > 0 then begin
    It := Iterator;
    repeat
      It.Value.Free;
    until not It.Next;
    It.Free;
  end;
  inherited Destroy;
end;
 
var
  ConfigStrings,ConfigValues: TStrings;
  ConfigStorage: TConfigStorage;
  ConfigLine,ConfigName,ConfigValue: String;
  SeparatorPos: Integer;
begin
  ConfigStrings := TStringList.Create;
  ConfigValues  := TStringList.Create;
  ConfigValues.Delimiter := ',';
  ConfigValues.StrictDelimiter := true;
  ConfigStorage := TConfigStorage.Create;
 
  ConfigStrings.LoadFromFile('config.test');
  for ConfigLine in ConfigStrings do begin
    if Length(ConfigLine) > 0 then begin
      case ConfigLine[1] of
        '#',';': ; // ignore
        else begin
          // look for = first
          SeparatorPos := Pos('=',ConfigLine);
          // if not found, then look for space
          if SeparatorPos = 0 then begin
            SeparatorPos := Pos(' ',ConfigLine);
          end;
          // found space
          if SeparatorPos <> 0 then begin
            ConfigName := UpCase(Copy(ConfigLine,1,SeparatorPos - 1));
            ConfigValues.DelimitedText := Copy(ConfigLine,SeparatorPos + 1,Length(ConfigLine) - SeparatorPos);
          // no = or space found, take the whole line as a key name
          end else begin
            ConfigName := UpCase(Trim(ConfigLine));
          end;
          if not ConfigStorage.Contains(ConfigName) then begin
            ConfigStorage[ConfigName] := TConfigValues.Create;
          end;
          for ConfigValue in ConfigValues do begin
            ConfigStorage[ConfigName].PushBack(Trim(ConfigValue));
          end;
        end;
      end;
    end;
  end;
 
  WriteLn('FULLNAME = ' + ConfigStorage['FULLNAME'][0]);
  WriteLn('FAVOURITEFRUIT = ' + ConfigStorage['FAVOURITEFRUIT'][0]);
  WriteLn('NEEDSPEELING = ' + BoolToStr(ConfigStorage.Contains('NEEDSPEELING'),true));
  WriteLn('SEEDSREMOVED = ' + BoolToStr(ConfigStorage.Contains('SEEDSREMOVED'),true));
  WriteLn('OTHERFAMILY(1) = ' + ConfigStorage['OTHERFAMILY'][0]);
  WriteLn('OTHERFAMILY(2) = ' + ConfigStorage['OTHERFAMILY'][1]);
 
  ConfigStorage.Free;
  ConfigValues.Free;
  ConfigStrings.Free;
end.