Updated 2013-01-10 08:38:53 by MHo

Is there a standard/popular parser for .ini style configuration file parsers? If not, here is one that I use. It doesn't write config files, but does read them into arrays named by config file section.

-- Todd Coram
 namespace eval cfg {
    variable version 1.0

    variable sections [list DEFAULT]

    variable cursection DEFAULT
    variable DEFAULT;   # DEFAULT section
 }

 proc cfg::sections {} {
    return $cfg::sections
 }

 proc cfg::variables {{section DEFAULT}} {
    return [array names ::cfg::$section]
 }

 proc cfg::add_section {str} {
    variable sections
    variable cursection

    set cursection [string trim $str \[\]]
    if {[lsearch -exact $sections $cursection] == -1} {
      lappend sections $cursection
      variable ::cfg::${cursection}
    }
 }

 proc cfg::setvar {varname value {section DEFAULT}} {
    variable sections
    if {[lsearch -exact $sections $section] == -1} {
      cfg::add_section $section
    }
    set ::cfg::${section}($varname) $value
 }

 proc cfg::getvar {varname {section DEFAULT}} {
    variable sections
    if {[lsearch -exact $sections $section] == -1} {
      error "No such section: $section"
    }
   return [set ::cfg::${section}($varname)]
 }


 proc cfg::parse_file {filename} {
    variable sections
    variable cursection
    set line_no 1
    set fd [open $filename r]
    while {![eof $fd]} {
        set line [string trim [gets $fd] " "]
        if {$line == ""} continue
        switch -regexp -- $line {
           ^#.* { }
           ^\\[.*\\]$ {
               cfg::add_section $line
           }
           .*=.* {
               set pair [split $line =]
               set name [string trim [lindex $pair 0] " "]
               set value [string trim [lindex $pair 1] " "]
               cfg::setvar $name $value $cursection
           } 
           default {
               error "Error parsing $filename (line: $line_no): $line"
           }
         }
       incr line_no
     }
     close $fd
 }

Given: (startup.ini)
 # a DEFAULT attribute
 #
 debug=true

 [EMAIL]
 from_addr = [email protected]
 to_addr = [email protected]

 [DEFAULT]
 trace_level = 5

Here is how you can use it:
  cfg::parse_file startup.ini
  set dbg $cfg::DEFAULT(debug)
  set dbg [cfg::getvar debug DEFAULT]
  puts "email comes from $cfg::EMAIL(from_addr)"

Removed unneeded $ characters and added missing g and " characters to get the script working. -- [George H. Lewis]

There also is an inifile parser in Tcllib. MHo: And another on here: One more inifile parser, including test and documentation.

David Easton 19 Mar 2004 - I had a need for reading and writing config files within a metakit virtual filesystem. Unfortunately the Tcllib inifile parser was not suitable due to the access specifiers used with the config file. I came up with the Snit cfg package to get around these problems.

AMG: Here's another approach: Config file using slave interp