[David Easton] ''19 March 2004'' - This [Snit] based package provides the ability to read and write ''ini'' style config files. Although it should work with any ''ini'' style config files, I wrote it to solve a particular problem where I wanted to read and write config files within a [metakit] virtual filesystem. The [inifile] parser did not work because it opens the file using access specifiers that did not seem to be supported within the vfs mounted with vfs::mk4::Mount. The ''read'' method is used to read the config file into memory. The ''write'' method is used to write the config file from memory to disk. All other operations do not change the file on disk, but only the values in memory. Limitations: There is no support for comments within a configuration file. ''i.e. Comments will be lost when a config file is written'' As usual, feel free to edit, improve and use the code on this page. [DDG] I was adding a dummy option because snit0.97 fails to load `$self configurelist $args' if no option was actually given. [WHD] For the record, the correct solution is to delete the call "$self configurelist $args". If you have no options, there's no reason to call it. ################################################################################ # # Package: cfg # # Description: # Package of utilities for in-memory configuration file routines # # Provides the following functions: # # cfg create - Create a cfg handle with name # cfg create %AUTO% - Create a cfg handle # cfg list - List all open cfg handles # # read # write # destroy # show # # get
# set
# delete
# exists
# # sections # section get
# section set
? ? ... # section delete
# section exists
# # Author: David Easton # Date: Nov 2003 # ################################################################################ package provide cfg 1.0 namespace eval cfg { package require snit snit::type cfg { # fix to use it with snit0.97 option -dummy "" typevariable cfgList [list] typemethod list {} { return $cfgList } # Used for efficient lreplace proc K {x y} { set x } # Define variable in which to store the cfg information variable data variable sectionList constructor {args} { $self configurelist $args lappend cfgList $self set sectionList [list] } destructor { if {[set i [lsearch $cfgList $self]] != -1} { set cfgList [lreplace $cfgList $i $i] } } # # Private methods # method AddSection {section} { if {[lsearch $sectionList $section] == -1} { lappend sectionList $section set data($section:keyList) [list] } } method DelSection {section} { if {[set i [lsearch $sectionList $section]] != -1} { set sectionList [lreplace $sectionList $i $i] foreach entry [array names data $section,*] { unset data($entry) } unset data($section:keyList) } } method AddKey {section key} { $self AddSection $section if {[lsearch $data($section:keyList) $key] == -1} { lappend data($section:keyList) $key } } method DelKey {section key} { if {[set i [lsearch $data($section:keyList) $key]] != -1} { set data($section:keyList) [lreplace $data($section:keyList) $i $i] unset data($section,$key) } } # # Public methods # method read {filename} { set retCode ok set section "" if {[catch {open $filename r} fileId]} { set retCode "error" } else { # Read whole file as a list set dataList [split [read -nonewline $fileId] \n] close $fileId # Now process the list foreach line $dataList { # Ignore blank lines if {[string trim $line] == ""} {continue} # Ignore comments if {[string match "#*" $line]} {continue} # Match sections if {[regexp {\[(.*)\]} $line junk section]} { # We have reached a new section } if {[string match "*=*" $line]} { foreach {key val} [split $line =] {break} $self set $section $key $val } } } return -code $retCode } method write {filename} { set retCode "ok" # Make parent directories if needed if {![info exists [file dirname $filename]]} { file mkdir [file dirname $filename] } # Open file for writing if {[catch {open $filename w} fid]} { set retCode "error" } else { foreach section $sectionList { puts $fid "\[$section\]" foreach key $data($section:keyList) { puts $fid "$key=$data($section,$key)" } puts $fid "" } flush $fid close $fid } } method sections {} { return $sectionList } method get {section key} { set value "" if [info exists data($section,$key)] { set value $data($section,$key) } return $value } method set {section key value} { if {![info exists data($section,$key)]} { $self AddKey $section $key } set data($section,$key) $value } method delete {section key} { $self DelKey $section $key } method exists {section key} { return [info exists data($section,$key)] } method show {} { foreach section $sectionList { puts "\[$section\]" foreach key $data($section:keyList) { puts "$key=$data($section,$key)" } puts "" } } method section {args} { if {[llength $args] < 2} { set message "wrong # args: should be \"$self section