This file is indexed.

/usr/share/tcltk/tcllib1.17/inifile/ini.tcl is in tcllib 1.17-dfsg-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
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
    }
}