This file is indexed.

/usr/share/tcltk/tcllib1.17/namespacex/namespacex.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
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## 'unknown hook' code -- Derived from http://wiki.tcl.tk/12790 (Neil Madden).
## 'var/state' code    -- Derived from http://wiki.tcl.tk/1489 (various).
## BSD Licensed
# # ## ### ##### ######## ############# ######################

# namespacex hook  - Easy extensibility of 'namespace unknown'.
# namespacex info  - Get all variables/children, direct and indirect
# namespacex state - Save/restore the variable-based state of namespaces.

# # ## ### ##### ######## ############# ######################
## Requisites

package require Tcl 8.5  ; # namespace ensembles, {*}

namespace eval ::namespacex {
    namespace export add hook info state
    namespace ensemble create

    namespace eval hook {
	namespace export add proc on next
	namespace ensemble create

	# add - hook a command prefix into the chain of unknown handlers for a
	#       namespace. The prefix will be run with whatever args there are, so
	#       it should use 'args' to accomodate? to everything.

	# on  - ditto for separate guard and action command prefixes.
	#       If the guard fails it chains via next, otherwise the
	#       action runs. The action can asume that the guard checked for proper
	#       number of arguments, maybe even types. Whatever fits.

	# proc - like add, but an unamed procedure, with arguments and
	#        body. Not much use, except maybe to handle the exact way
	#        of chaining on your own (next can take a rewritten
	#        command, the 'on' compositor makes no use of that.

	# Both 'proc' and 'on' are based on 'add'.
    }

    namespace eval info {
	namespace export allvars allchildren vars
	namespace ensemble create
    }

    namespace eval state {
	namespace export drop set get
	namespace ensemble create
    }
}

# # ## ### ##### ######## ############# ######################
## Implementation :: Hooks - Visible API

# # ## ### ##### ######## ############# ######################
## (1) Core: Register a command prefix to be run by 
##           namespace unknown of a namespace FOO.
##           FOO defaults to the current namespace.
##
##     The prefixes are executed in reverse order of registrations,
##     i.e. the prefix registered last is executed first. The next
##     is run if and only if the current prefix forced this via
##    '::namespacex::hook::next'. IOW the chain is managed cooperatively.

proc ::namespacex::hook::add {args} {
    # syntax: ?namespace? cmdprefix

    if {[llength $args] > 2} {
	return -code error "wrong\#args, should be \"?namespace? cmdprefix\""
    } elseif {[llength $args] == 2} {
	lassign $args namespace cmdprefix
    } else { # [llength $args] == 1
	lassign $args cmdprefix
	set namespace [uplevel 1 { namespace current }]
    }

    #puts UH|ADD|for|$namespace|
    #puts UH|ADD|old|<<[Get $namespace]>>
    #puts UH|ADD|cmd|<<$cmdprefix>>

    Set $namespace [namespace code [list Handle $cmdprefix [Get $namespace]]]
    return
}

proc ::namespacex::hook::proc {args} {
    # syntax: ?namespace? arguments body

    set procNamespace [uplevel 1 { namespace current }]

    if {([llength $args] < 2) ||
	([llength $args] > 3)} {
	return -code error "wrong\#args, should be \"?namespace? arguments body\""
    } elseif {[llength $args] == 3} {
	lassign $args namespace arguments body
    } else { # [llength $args] == 2
	lassign $args arguments body
	set namespace $procNamespace
    }

    add $namespace [list ::apply [list $arguments $body $procNamespace]]
    return
}

proc ::namespacex::hook::on {args} {
    # syntax: ?namespace? guardcmd actioncmd

    if {([llength $args] < 2) ||
	([llength $args] > 3)} {
	return -code error "wrong\#args, should be \"?namespace? guard action\""
    } elseif {[llength $args] == 3} {
	lassign $args namespace guard action
    } else { # [llength $args] == 2
	lassign $args guard action
	set namespace [uplevel 1 { namespace current }]
    }

    add $namespace [list ::apply [list {guard action args} {
	if {![{*}$guard {*}$args]} {
	    # This is what requires '[ns current]' as context.
	    next
	}
	return [{*}$action {*}$args]
    } [namespace current]] $guard $action]
    return
}

proc ::namespacex::hook::next {args} {
    #puts UH|NEXT|$args|
    return -code continue -level 2 $args
}

# # ## ### ##### ######## ############# ######################
## Implementation :: Hooks - Internal Helpers.
## Get and set the unknown handler for a specified namespace.

# Generic handler with the user's handler and previous handler as
# arguments. The latter is an invokation of the internal handler
# again, with its own arguments. In this way 'Handle' forms the spine
# of the chain of handlers, running them and handling 'next' to
# traverse the chain. From a data structure perspective we have deeply
# nested list here, which is recursed into as the chain is traversed.

proc ::namespacex::hook::Get {ns} {
    return [namespace eval $ns { namespace unknown }]
}

proc ::namespacex::hook::Set {ns handler} {
    #puts UH|SET|$ns|<<$handler>>

    namespace eval $ns [list namespace unknown $handler]
    return
}

proc ::namespacex::hook::Handle {handler old args} {
    #puts UH|HDL|$handler|||old|$old||args||$args|

    set rc [catch {
	uplevel 1 $handler $args
    } result]

    #puts UH|HDL|rc=$rc|result=$result|

    if {$rc == 4} {
        # continue - invoke next handler

	if {$old eq {}} {
	    # no next handler available - stop
	    #puts UH|HDL|STOP
	    return -code error "invalid command name \"[lindex $args 0]\""
	}

        if {![llength $result]} {
            uplevel 1 $old $args
        } else {
            uplevel 1 $old $result
        }
    } else {
        return -code $rc $result
    }
}

# # ## ### ##### ######## ############# ######################
## Implementation :: Info - Visible API

proc ::namespacex::info::allvars {ns} {
    if {![string match {::*} $ns]} { set ns ::$ns }
    ::set result [::info vars ${ns}::*]
    foreach cns [allchildren $ns] {
	lappend result {*}[::info vars ${cns}::*]
    }
    return [Strip $ns $result]
}

proc ::namespacex::info::allchildren {ns} {
    if {![string match {::*} $ns]} { set ns ::$ns }
    ::set result [list]
    foreach cns [::namespace children $ns] {
	lappend result {*}[allchildren $cns]
	lappend result $cns
    }
    return $result
}

proc ::namespacex::info::vars {ns {pattern *}} {
    return [Strip $ns [::info vars ${ns}::$pattern]]
}

proc ::namespacex::info::Strip {ns itemlist} {
    set n [string length $ns]
    if {![string match {::*} $ns]} {
	incr n 4
    } else {
	incr n 2
    }

    set result {}
    foreach i $itemlist {
	lappend result [string range $i $n end]
    }
    return $result
}

# # ## ### ##### ######## ############# ######################
## Implementation :: State - Visible API

proc ::namespacex::state::drop {ns} {
    if {![string match {::*} $ns]} { ::set ns ::$ns }
    namespace eval $ns [list ::unset {*}[::namespacex info allvars $ns]]
    return
}

proc ::namespacex::state::get {ns} {
    if {![string match {::*} $ns]} { ::set ns ::$ns }
    ::set result {}
    foreach v [::namespacex info allvars $ns] {
	namespace upvar $ns $v value
	lappend result $v $value
    }
    return $result
}

proc ::namespacex::state::set {ns state} {
    if {![string match {::*} $ns]} { ::set ns ::$ns }
    # Inlined 'state drop'.
    namespace eval $ns [list ::unset  {*}[::namespacex info allvars $ns]]
    namespace eval $ns [list variable {*}$state]
    return
}

# # ## ### ##### ######## ############# ######################
## Ready

package provide namespacex 0.1