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


proc readConfig {filename {defaults {}}} {
    global cfg
    # Read the file in
    set f [open $filename]
    set contents [read $f]
    close $f
    # Set up the defaults, if supplied
    foreach {var defaultValue} $defaults {
	set cfg($var) $defaultValue
    }
    # Parse the file's contents
    foreach line [split $contents "\n"] {
	set line [string trim $line]
	# Skip comments
	if {[string match "#*" $line] || [string match ";*" $line]} continue
	# Skip blanks
	if {$line eq ""} continue
 
	if {[regexp {^\w+$} $line]} {
	    # Boolean case
	    set cfg([string tolower $line]) true
	} elseif {[regexp {^(\w+)\s+([^,]+)$} $line -> var value]} {
	    # Simple value case
	    set cfg([string tolower $var]) $value
	} elseif {[regexp {^(\w+)\s+(.+)$} $line -> var listValue]} {
	    # List value case
	    set cfg([string tolower $var]) {}
	    foreach value [split $listValue ","] {
		lappend cfg([string tolower $var]) [string trim $value]
	    }
	} else {
	    error "malformatted config file: $filename"
	}
    }
}
 
# Need to supply some default values due to config file grammar ambiguities
readConfig "fruit.cfg" {
    needspeeling false
    seedsremoved false
}
puts "Full name: $cfg(fullname)"
puts "Favourite: $cfg(favouritefruit)"
puts "Peeling?   $cfg(needspeeling)"
puts "Unseeded?  $cfg(seedsremoved)"
puts "Family:    $cfg(otherfamily)"