diff options
Diffstat (limited to 'tcllib/modules/inifile')
-rw-r--r-- | tcllib/modules/inifile/ChangeLog | 182 | ||||
-rw-r--r-- | tcllib/modules/inifile/ini.man | 100 | ||||
-rw-r--r-- | tcllib/modules/inifile/ini.tcl | 403 | ||||
-rw-r--r-- | tcllib/modules/inifile/inifile.pcx | 89 | ||||
-rw-r--r-- | tcllib/modules/inifile/inifile.test | 218 | ||||
-rw-r--r-- | tcllib/modules/inifile/pkgIndex.tcl | 2 | ||||
-rw-r--r-- | tcllib/modules/inifile/sample.ini | 5 | ||||
-rw-r--r-- | tcllib/modules/inifile/test.ini | 15 |
8 files changed, 1014 insertions, 0 deletions
diff --git a/tcllib/modules/inifile/ChangeLog b/tcllib/modules/inifile/ChangeLog new file mode 100644 index 0000000..8da18ed --- /dev/null +++ b/tcllib/modules/inifile/ChangeLog @@ -0,0 +1,182 @@ +2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.15 ======================== + * + +2012-01-05 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * ini.tcl: [Bug 3469006]: Followup to [Bug 3419727]. Fixed + * ini.man: the unscoped 'close' command left in the code. + * pkgIndex.tcl: Bumped version to 0.2.5 + +2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.14 ======================== + * + +2011-12-02 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * ini.tcl: [Bug 3419727]: Fixed the creative writing issue + * ini.man: with what should be local variables of _loadfile + * pkgIndex.tcl: and _commit. Generally reworked to use the + 'variable' command to bring object state into scope. + Bumped version to 0.2.4 + +2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.13 ======================== + * + +2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.12 ======================== + * + +2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.11.1 ======================== + * + +2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.11 ======================== + * + +2008-06-14 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * inifile.pcx: New file. Syntax definitions for the public + commands of the inifile package. + +2008-05-10 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * ini.tcl: Fixed definition of procedure 'commentchar'. Was + * ini.man: defined global instead of in the '::ini' namespace. + * pkgIndex.tcl: This fixes [SF Tcllib Bug 1917035]. Bumped version + to 0.2.3. + +2008-03-14 Andreas Kupries <andreask@activestate.com> + + * ini.tcl: Simplified the initialization code. Bumped version to + * ini.man: 0.2.2. + * pkgIndex.tcl: + +2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.10 ======================== + * + +2007-08-20 Andreas Kupries <andreask@activestate.com> + + * ini.man: Bumped package version to 0.2.1, due to bugfix in last + * ini.tcl: entry. + * pkgIndex.tcl: + +2007-08-16 Aaron Faupell <afaupell@users.sourceforge.net> + + * ini.man: clarifications to ini::open and ini::remove + * ini.tcl fixed bug in ini::value where default value only + worked if the section didnt exist + +2007-03-21 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * ini.man: Fixed all warnings due to use of now deprecated + commands. Added a section about how to give feedback. + +2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.9 ======================== + * + +2006-06-29 Aaron Faupell <afaupell@users.sourceforge.net> + + * ini.tcl: added default value option for value command, and added + commentchar command. change in comment behavior + * ini.man: clarifications for open, commit, and comment commands; added + commentchar command + +2006-01-23 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * inifile.test: More boilerplate simplified via use of test support. + +2006-01-19 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * inifile.test: Hooked into the new common test support code. + +2005-17-11 Aaron Faupell <afaupell@users.sourceforge.net> + + * ini.tcl: fixed bug causing empty ini files when opening + with w modes introduced on 2005-31-03 + +2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.8 ======================== + * + +2005-09-05 Pat Thoyts <patthoyts@users.sourceforge.net> + + * ini.tcl: Fix for bug #1280529 - collision with global + * inifile.test: variable names. Added tests for these. + +2005-31-03 Aaron Faupell <afaupell@users.sourceforge.net> + + * ini.tcl: fixed bug where ini files were corrupted when + saving a shorter version. due to not closing + and truncating file before writing. + +2004-10-05 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.7 ======================== + * + +2004-05-23 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.6.1 ======================== + * + +2004-03-06 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * inifile.test: Fixed [Tcllib SF Bug 899204] by (a) rewriting all + tests to be completely independent of each other and (b) + changing the mode when opening the test file to 'r'. It should + be noted that the write facilities of the module are not covered + by the testsuite. That is unfortunate. + +2004-02-15 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * + * Released and tagged Tcllib 1.6 ======================== + * + +2004-02-10 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * inifile.test: It was easier to make this package useable for Tcl + * ini.tcl: 8.2 than excluding it from test for versions of Tcl + * ini.man: before 8.4. So that was done. + +2003-07-15 Andreas Kupries <andreask@pliers.activestate.com> + + * ini.tcl: Got a rewritten system from Aaron. + * ini.man: Updated the documentation. + + * infile.test: New testsuite for module. + * test.ini: + +2003-07-04 Andreas Kupries <andreas_kupries@users.sourceforge.net> + + * ini.tcl: Added a comment header for RCS id, copyright notices, + etc. Slight reformatting of the code. Slight code changes to + make 'procheck' complain less (proper import of variables into + the scope). + + Documented possible bug. diff --git a/tcllib/modules/inifile/ini.man b/tcllib/modules/inifile/ini.man new file mode 100644 index 0000000..ce36ea1 --- /dev/null +++ b/tcllib/modules/inifile/ini.man @@ -0,0 +1,100 @@ +[vset VERSION 0.3] +[comment {-*- tcl -*- doctools manpage}] +[manpage_begin inifile n [vset VERSION]] +[moddesc {Parsing of Windows INI files}] +[titledesc {Parsing of Windows INI files}] +[category {Text processing}] +[require Tcl 8.2] +[require inifile [opt [vset VERSION]]] +[description] + +This package provides an interface for easy manipulation of Windows INI files. + +[para] + +[list_begin definitions] + +[call [cmd ::ini::open] [arg file] [opt "[option -encoding] [arg encoding]"] [opt [arg access]]] + +Opens an INI file and returns a handle that is used by other commands. +[arg access] is the same as the first form (non POSIX) of the [const open] +command, with the exception that mode [const a] is not supported. The +default mode is [const r+]. + +[para] The default [arg encoding] is the system encoding. + + +[call [cmd ::ini::close] [arg ini]] + +Close the specified handle. If any changes were made and not written by +[const commit] they are lost. + +[call [cmd ::ini::commit] [arg ini]] + +Writes the file and all changes to disk. The sections are written in +arbitrary order. The keys in a section are written in alphabetical +order. If the ini was opened in read only mode an error will be thrown. + +[call [cmd ::ini::revert] [arg ini]] + +Rolls all changes made to the inifile object back to the last +committed state. + +[call [cmd ::ini::filename] [arg ini]] + +Returns the name of the file the [arg ini] object is associated with. + +[call [cmd ::ini::sections] [arg ini]] + +Returns a list of all the names of the existing sections in the file handle +specified. + +[call [cmd ::ini::keys] [arg ini] [arg section]] + +Returns a list of all they key names in the section and file specified. + +[call [cmd ::ini::get] [arg ini] [arg section]] + +Returns a list of key value pairs that exist in the section and file specified. + +[call [cmd ::ini::exists] [arg ini] [arg section] [opt [arg key]]] + +Returns a boolean value indicating the existance of the specified section as a +whole or the specified key within that section. + +[call [cmd ::ini::value] [arg ini] [arg section] [arg key] [opt [arg default]]] + +Returns the value of the named key and section. If specified, +the default value will be returned if the key does not exist. If the key does +not exist and no default is specified an error will be thrown. + +[call [cmd ::ini::set] [arg ini] [arg section] [arg key] [arg value]] + +Sets the value of the key in the specified section. If the section does not +exist then a new one is created. + +[call [cmd ::ini::delete] [arg ini] [arg section] [opt [arg key]]] + +Removes the key or the entire section and all its keys. A section is not +automatically deleted when it has no remaining keys. + +[call [cmd ::ini::comment] [arg ini] [arg section] [opt [arg key]] [opt [arg text]]] + +Reads and modifies comments for sections and keys. To write a section comment use an +empty string for the [arg key]. To remove all comments use an empty string for [arg text]. +[arg text] may consist of a list of lines or one single line. Any embedded newlines in +[arg text] are properly handled. Comments may be written to nonexistant +sections or keys and will not return an error. Reading a comment from a nonexistant +section or key will return an empty string. + +[call [cmd ::ini::commentchar] [opt char]] + +Reads and sets the comment character. Lines that begin with this character are treated as +comments. When comments are written out each line is preceded by this character. The default +is [const \;]. + +[list_end] + +[vset CATEGORY inifile] +[include ../doctools2base/include/feedback.inc] +[manpage_end] diff --git a/tcllib/modules/inifile/ini.tcl b/tcllib/modules/inifile/ini.tcl new file mode 100644 index 0000000..938cb64 --- /dev/null +++ b/tcllib/modules/inifile/ini.tcl @@ -0,0 +1,403 @@ +# ini.tcl -- +# +# Querying and modifying old-style windows configuration files (.ini) +# +# Copyright (c) 2003-2007 Aaron Faupell <afaupell@users.sourceforge.net> +# Copyright (c) 2008-2012 Andreas Kupries <andreas_kupries@users.sourceforge.net> +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: ini.tcl,v 1.17 2012/01/05 21:04:55 andreas_kupries Exp $ + +package provide inifile 0.3 + +namespace eval ini { + variable nexthandle 0 + variable commentchar \; +} + +proc ::ini::open {ini args} { + variable nexthandle + + while {[string match -* [::set opt [lindex $args 0]]]} { + switch -exact -- $opt { + -- { + ::set args [lrange $args 1 end] + break + } + -encoding { + ::set enc [lindex $args 1] + ::set args [lrange $args 2 end] + } + default { + return -code error \ + -errorcode {INIFILE OPTION INVALID} \ + "Invalid option $opt, expected -encoding" + } + } + } + + ::set remainder [llength $args] + if {$remainder > 1} { + return -code error \ + -errorcode {WRONG-ARGS INIFILE} \ + "wrong\#args: should be \"ini::open ?-encoding E? ?mode?\"" + } elseif {$remainder == 1} { + ::set mode [lindex $args 0] + } else { + ::set mode r+ + } + + if { ![regexp {^(w|r)\+?$} $mode] } { + return -code error \ + -errorcode {INIFILE MODE INVALID} \ + "$mode is not a valid access mode" + } + + ::set fh ini$nexthandle + ::set tmp [::open $ini $mode] + fconfigure $tmp -translation crlf + if {[info exists enc]} { + if {[catch { + fconfigure $tmp -encoding $enc + } msg]} { + ::close $tmp + return -code error $msg + } + } + + namespace eval ::ini::$fh { + variable data; array set data {} + variable comments; array set comments {} + variable sections; array set sections {} + } + ::set ::ini::${fh}::channel $tmp + ::set ::ini::${fh}::file [_normalize $ini] + ::set ::ini::${fh}::mode $mode + + incr nexthandle + if { [string match "r*" $mode] } { + _loadfile $fh + } + return $fh +} + +# close the file and delete all stored info about it +# this does not save any changes. see ::ini::commit + +proc ::ini::close {fh} { + _valid_ns $fh + variable ::ini::${fh}::channel + ::close $channel + namespace delete ::ini::$fh + return +} + +# write all changes to disk + +proc ::ini::commit {fh} { + _valid_ns $fh + + variable ::ini::${fh}::data + variable ::ini::${fh}::comments + variable ::ini::${fh}::sections + variable ::ini::${fh}::channel + variable ::ini::${fh}::file + variable ::ini::${fh}::mode + variable commentchar + + if { $mode == "r" } { + return -code error \ + -errorcode {INIFILE READ-ONLY} \ + "cannot write to read-only file" + } + ::close $channel + ::set channel [::open $file w] + ::set char $commentchar + #seek $channel 0 start + foreach sec [array names sections] { + if { [info exists comments($sec)] } { + puts $channel "$char [join $comments($sec) "\n$char "]\n" + } + puts $channel "\[$sec\]" + foreach key [lsort -dictionary [array names data [_globescape $sec]\000*]] { + ::set key [lindex [split $key \000] 1] + if {[info exists comments($sec\000$key)]} { + puts $channel "$char [join $comments($sec\000$key) "\n$char "]" + } + puts $channel "$key=$data($sec\000$key)" + } + puts $channel "" + } + ::close $channel + ::set channel [::open $file r+] + return +} + +# internal command to read in a file +# see open and revert for public commands + +proc ::ini::_loadfile {fh} { + variable ::ini::${fh}::data + variable ::ini::${fh}::comments + variable ::ini::${fh}::sections + variable ::ini::${fh}::channel + variable ::ini::${fh}::file + variable ::ini::${fh}::mode + variable commentchar + + ::set cur {} + ::set com {} + + ::set char $commentchar + seek $channel 0 start + + foreach line [split [read $channel] "\n"] { + # bug 3612465 - allow and ignore leading and trailing whitespace. + ::set line [string trim $line] + + if { [string match "$char*" $line] } { + lappend com [string trim [string range $line [string length $char] end]] + } elseif { [string match {\[*\]} $line] } { + ::set cur [string range $line 1 end-1] + if { $cur == "" } { continue } + ::set sections($cur) 1 + if { $com != "" } { + ::set comments($cur) $com + ::set com {} + } + } elseif { [string match {*=*} $line] } { + ::set line [split $line =] + ::set key [string trim [lindex $line 0]] + if { $key == "" || $cur == "" } { continue } + ::set value [string trim [join [lrange $line 1 end] =]] + if { [regexp "^(\".*\")\s+${char}(.*)$" $value -> 1 2] } { + ::set value $1 + lappend com $2 + } + ::set data($cur\000$key) $value + if { $com != "" } { + ::set comments($cur\000$key) $com + ::set com {} + } + } + } + return +} + +# internal command to escape glob special characters + +proc ::ini::_globescape {string} { + return [string map {* \\* ? \\? \\ \\\\ \[ \\\[ \] \\\]} $string] +} + +# internal command to check if a section or key is nonexistant + +proc ::ini::_exists {fh sec args} { + variable ::ini::${fh}::sections + variable ::ini::${fh}::data + + if { ![info exists sections($sec)] } { + return -code error \ + -errorcode {INIFILE SECTION INVALID} \ + "no such section \"$sec\"" + } + if { [llength $args] > 0 } { + ::set key [lindex $args 0] + if { ![info exists data($sec\000$key)] } { + return -code error \ + -errorcode {INIFILE KEY INVALID} \ + "can't read key \"$key\"" + } + } + return +} + +# internal command to check validity of a handle + +if { [package vcompare [package provide Tcl] 8.4] < 0 } { + proc ::ini::_normalize {path} { + return $path + } + proc ::ini::_valid_ns {name} { + variable ::ini::${name}::data + if { ![info exists data] } { + return -code error \ + -errorcode {INIFILE HANDLE INVALID} \ + "$name is not an open INI file" + } + } +} else { + proc ::ini::_normalize {path} { + file normalize $path + } + proc ::ini::_valid_ns {name} { + if { ![namespace exists ::ini::$name] } { + return -code error \ + -errorcode {INIFILE HANDLE INVALID} \ + "$name is not an open INI file" + } + } +} + +# get and set the ini comment character + +proc ::ini::commentchar { {new {}} } { + variable commentchar + if {$new != ""} { + if {[string length $new] > 1} { + return -code error \ + -errorcode {INIFILE COMMENT-CHAR INVALID} \ + "comment char must be a single character" + } + ::set commentchar $new + } + return $commentchar +} + +# return all section names + +proc ::ini::sections {fh} { + _valid_ns $fh + variable ::ini::${fh}::sections + return [array names sections] +} + +# return boolean indicating existance of section or key in section + +proc ::ini::exists {fh sec {key {}}} { + _valid_ns $fh + variable ::ini::${fh}::sections + variable ::ini::${fh}::data + + if { $key == "" } { + return [info exists sections($sec)] + } + return [info exists data($sec\000$key)] +} + +# return all key names of section +# error if section is nonexistant + +proc ::ini::keys {fh sec} { + _valid_ns $fh + _exists $fh $sec + variable ::ini::${fh}::data + + ::set keys {} + foreach x [array names data [_globescape $sec]\000*] { + lappend keys [lindex [split $x \000] 1] + } + return $keys +} + +# return all key value pairs of section +# error if section is nonexistant + +proc ::ini::get {fh sec} { + _valid_ns $fh + _exists $fh $sec + variable ::ini::${fh}::data + + ::set r {} + foreach x [array names data [_globescape $sec]\000*] { + lappend r [lindex [split $x \000] 1] $data($x) + } + return $r +} + +# return the value of a key +# return default value if key or section is nonexistant otherwise error + +proc ::ini::value {fh sec key {default {}}} { + _valid_ns $fh + variable ::ini::${fh}::data + + if {$default != "" && ![info exists data($sec\000$key)]} { + return $default + } + _exists $fh $sec $key + return [::set data($sec\000$key)] +} + +# set the value of a key +# new section or key names are created + +proc ::ini::set {fh sec key value} { + _valid_ns $fh + variable ::ini::${fh}::sections + variable ::ini::${fh}::data + + ::set sec [string trim $sec] + ::set key [string trim $key] + if { $sec == "" || $key == "" } { + return -code error \ + -errorcode {INIFILE SYNTAX} \ + "section or key may not be empty" + } + ::set data($sec\000$key) $value + ::set sections($sec) 1 + return $value +} + +# delete a key or an entire section +# may delete nonexistant keys and sections + +proc ::ini::delete {fh sec {key {}}} { + _valid_ns $fh + variable ::ini::${fh}::sections + variable ::ini::${fh}::data + + if { $key == "" } { + array unset data [_globescape $sec]\000* + array unset sections [_globescape $sec] + } + catch {unset data($sec\000$key)} +} + +# read and set comments for sections and keys +# may comment nonexistant sections and keys + +proc ::ini::comment {fh sec key args} { + _valid_ns $fh + variable ::ini::${fh}::comments + + ::set r $sec + if { $key != "" } { append r \000$key } + if { [llength $args] == 0 } { + if { ![info exists comments($r)] } { return {} } + return $comments($r) + } + if { [llength $args] == 1 && [lindex $args 0] == "" } { + unset -nocomplain comments($r) + return {} + } + # take care of any embedded newlines + for {::set i 0} {$i < [llength $args]} {incr i} { + ::set args [eval [list lreplace $args $i $i] [split [lindex $args $i] \n]] + } + eval [list lappend comments($r)] $args +} + +# return the physical filename for the handle + +proc ::ini::filename {fh} { + _valid_ns $fh + variable ::ini::${fh}::file + return $file +} + +# reload the file from disk losing all changes since the last commit + +proc ::ini::revert {fh} { + _valid_ns $fh + namespace eval ::ini::$fh { + array set data {} + array set comments {} + array set sections {} + } + if { ![string match "w*" $mode] } { + _loadfile $fh + } +} diff --git a/tcllib/modules/inifile/inifile.pcx b/tcllib/modules/inifile/inifile.pcx new file mode 100644 index 0000000..f74749e --- /dev/null +++ b/tcllib/modules/inifile/inifile.pcx @@ -0,0 +1,89 @@ +# -*- tcl -*- inifile.pcx +# Syntax of the commands provided by package inifile. + +# For use by TclDevKit's static syntax checker. +# See http://www.activestate.com/solutions/tcl/ +# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api +# for the documentation describing the format of the code contained in this file +# + +package require pcx +pcx::register inifile +pcx::tcldep 0.2.1 needs tcl 8.2 + +namespace eval ::inifile {} + +#pcx::message FOO {... text ...} type +#pcx::scan <VERSION> <NAME> <RULE> + +pcx::check 0.2.1 std ::ini::close \ + {checkSimpleArgs 1 1 { + checkChannelID + }} +pcx::check 0.2.1 std ::ini::comment \ + {checkSimpleArgs 4 4 { + checkChannelID + checkWord + checkWord + checkWord + }} +pcx::check 0.2.1 std ::ini::commit \ + {checkSimpleArgs 1 1 { + checkChannelID + }} +pcx::check 0.2.1 std ::ini::delete \ + {checkSimpleArgs 2 3 { + checkChannelID + checkWord + checkWord + }} +pcx::check 0.2.1 std ::ini::exists \ + {checkSimpleArgs 1 1 { + checkChannelID + }} +pcx::check 0.2.1 std ::ini::filename \ + {checkSimpleArgs 1 1 { + checkChannelID + }} +pcx::check 0.2.1 std ::ini::get \ + {checkSimpleArgs 1 2 { + checkWord + checkWord + }} +pcx::check 0.2.1 std ::ini::keys \ + {checkSimpleArgs 2 2 { + checkChannelID + checkWord + }} +# TODO: file open access mode +pcx::check 0.2.1 std ::ini::open \ + {checkSimpleArgs 1 2 { + checkWord + checkWord + }} +pcx::check 0.2.1 std ::ini::revert \ + {checkSimpleArgs 1 1 { + checkChannelID + }} +pcx::check 0.2.1 std ::ini::sections \ + {checkSimpleArgs 1 1 { + checkChannelID + }} +pcx::check 0.2.1 std ::ini::set \ + {checkSimpleArgs 4 4 { + checkChannelID + checkWord + checkWord + checkWord + }} +pcx::check 0.2.1 std ::ini::value \ + {checkSimpleArgs 3 4 { + checkChannelID + checkWord + checkWord + checkWord + }} + +# Initialization via pcx::init. +# Use a ::inifile::init procedure for non-standard initialization. +pcx::complete diff --git a/tcllib/modules/inifile/inifile.test b/tcllib/modules/inifile/inifile.test new file mode 100644 index 0000000..3aa9627 --- /dev/null +++ b/tcllib/modules/inifile/inifile.test @@ -0,0 +1,218 @@ +# -*- tcl -*- +# Tests for module 'inifile' + +# ------------------------------------------------------------------------- + +source [file join \ + [file dirname [file dirname [file join [pwd] [info script]]]] \ + devtools testutilities.tcl] + +testsNeedTcl 8.2 +testsNeedTcltest 1.0 + +testing { + useLocal ini.tcl inifile +} + +#--------------------------------------------------------------------- + +set inifile [localPath ini.tcl] +set testini [localPath test.ini] +set sampini [localPath sample.ini] + +#--------------------------------------------------------------------- + +test inifile-1.1 {ini::open} { + set res [ini::open $testini r] + ini::close $res + set res +} {ini0} + +test inifile-1.2 {ini::sections} { + set hdl [ini::open $testini r] + set res [ini::sections $hdl] + ini::close $hdl + set res +} {emptysection section1 \{test section2} + +test inifile-1.3 {ini::keys} { + set hdl [ini::open $testini r] + set res [ini::keys $hdl section1] + ini::close $hdl + set res +} {testkey key} + +test inifile-1.4 {ini::keys} { + set hdl [ini::open $testini r] + set res [ini::keys $hdl \{test] + ini::close $hdl + set res +} {\}key} + +test inifile-1.5 {ini::get} { + set hdl [ini::open $testini r] + set res [ini::get $hdl section1] + ini::close $hdl + set res +} {testkey hi key value} + +test inifile-1.6 {ini::get} { + set hdl [ini::open $testini r] + set res [ini::get $hdl \{test] + ini::close $hdl + set res +} {\}key {$blah}} + +test inifile-1.7 {ini::value} { + set hdl [ini::open $testini r] + set res [ini::value $hdl section1 key] + ini::close $hdl + set res +} {value} + +test inifile-1.8 {ini::value} { + set hdl [ini::open $testini r] + set res [ini::value $hdl \{test \}key] + ini::close $hdl + set res +} {$blah} + +test inifile-1.9 {ini::exists} { + set hdl [ini::open $testini r] + set res [ini::exists $hdl section1] + ini::close $hdl + set res +} {1} + +test inifile-1.10 {ini::exists} { + set hdl [ini::open $testini r] + set res [ini::exists $hdl section] + ini::close $hdl + set res +} {0} + +test inifile-1.11 {ini::exists} { + set hdl [ini::open $testini r] + set res [ini::exists $hdl section1 testkey] + ini::close $hdl + set res +} {1} + +test inifile-1.12 {ini:::exists} { + set hdl [ini::open $testini r] + set res [ini::exists $hdl section1 blah] + ini::close $hdl + set res +} {0} + +test inifile-1.13 {ini:::exists} { + set hdl [ini::open $testini r] + set res [ini::exists $hdl \{test] + ini::close $hdl + set res +} {1} + +test inifile-1.14 {ini:::exists} { + set hdl [ini::open $testini r] + set res [ini::exists $hdl \{test \}key] + ini::close $hdl + set res +} {1} + +#--------------------------------------------------------------------- +# Tests for bug #1281136 -- +set N 0 +foreach name {nexthandle commentchar} { + test inifile-2.$N {bug 1281136 - collision with global variable names} { + set script {list [catch { + array set ::%var {} + source %file + } err] $err} + regsub {%file} $script $inifile script + regsub {%var} $script $name script + interp create slave0 + set r [slave0 eval $script] + interp delete slave0 + set r + } {0 {}} + incr N +} +foreach name {data comments sections} { + test inifile-2.$N {bug 1281136 - collision with global variable names} { + set script {list [catch { + ::set ::%var 0 + source %file + set res [ini::open %testini r] + ini::close $res + } err] $err} + foreach {s v} [list %file $inifile %var $name %testini $testini] { + regsub $s $script $v script + } + interp create slave0 + set r [slave0 eval $script] + interp delete slave0 + set r + } {0 {}} + incr N +} + +#--------------------------------------------------------------------- + +test inifile-3.0 {bug 3612465, leading & trailing spaces} { + set fh [ini::open $sampini] + set res [ini::sections $fh] + ini::close $fh + unset fh + set res +} General + +test inifile-3.1 {bug 3612465, leading & trailing spaces} { + set fh [ini::open $sampini] + #set res [llength [ini::sections $fh]] + set res [lsort -dict [ini::keys $fh General]] + ini::close $fh + unset fh + set res +} {key key2} + +#--------------------------------------------------------------------- + +test inifile-4.0 {bug c4b8162da5 - ini::open} { + set res [ini::open $testini -encoding unicode r] + ini::close $res + set res +} {ini16} + +# Test various error conditions. +test inifile-4.1 {bug c4b8162da5 - ini::open - invalid encoding} { + catch { + ini::open $testini -encoding foo r + } res + set res +} {unknown encoding "foo"} + +test inifile-4.2 {bug c4b8162da5 - ini::open - invalid option} { + catch { + ini::open $testini -bogus foo r + } res + set res +} {Invalid option -bogus, expected -encoding} + +test inifile-4.3 {bug c4b8162da5 - ini::open - invalid mode} { + catch { + ini::open $testini x + } res + set res +} {x is not a valid access mode} + +test inifile-4.4 {bug c4b8162da5 - ini::open - invalid mode} { + catch { + set res [ini::open $testini w-] + } res + set res +} {w- is not a valid access mode} + +#--------------------------------------------------------------------- +# Clean up +testsuiteCleanup +return diff --git a/tcllib/modules/inifile/pkgIndex.tcl b/tcllib/modules/inifile/pkgIndex.tcl new file mode 100644 index 0000000..9aa3f98 --- /dev/null +++ b/tcllib/modules/inifile/pkgIndex.tcl @@ -0,0 +1,2 @@ +if { ![package vsatisfies [package provide Tcl] 8.2] } { return } +package ifneeded inifile 0.3 [list source [file join $dir ini.tcl]] diff --git a/tcllib/modules/inifile/sample.ini b/tcllib/modules/inifile/sample.ini new file mode 100644 index 0000000..884ccae --- /dev/null +++ b/tcllib/modules/inifile/sample.ini @@ -0,0 +1,5 @@ +[General] + key=value +key2=value2 + + ; .... diff --git a/tcllib/modules/inifile/test.ini b/tcllib/modules/inifile/test.ini new file mode 100644 index 0000000..ac8eb56 --- /dev/null +++ b/tcllib/modules/inifile/test.ini @@ -0,0 +1,15 @@ +[emptysection] + +; a comment for section 1 + +[section1] +key=value +testkey=hi + +[section2] +; key comment +key=othervalue + + +[{test] +}key = $blah |