Here's what I have:
proc print_globals {} {
foreach name [info globals] {
global $name
puts "$name -> $$name"
}
}
the output of which I am trying to get to be
...
tcl_version -> 8.5
...
but here's what's actually occurring
tcl_version -> $tcl_version
I know I am overlooking something simple. A little help??
The $variable_name is a short cut for
set variable_name
Two consecutive $ does not work.
You shoud use:
puts "$name -> [set $name]"
which is completely equivalent to
puts "[set name] -> [set [set name]]"
David Bariod
proc print_globals {} {
foreach name [info globals] {
global $name
if [array exists $name] {
parray $name
} else {
puts "$name = [set $name]"
}
}
}
this would also work
eval puts \"$name = \$$name\"
Carl
> proc print_globals {} {
> foreach name [info globals] {
> global $name
> if [array exists $name] {
> parray $name
> } else {
> puts "$name = [set $name]"
> }
> }
> }
The [upvar] command neatly combines making a global
reference with providing a convenient local alias.
proc print_globals {{pattern *}} {
foreach name [info globals $pattern] {
upvar #0 $name v
if {[array exists v]} {
parray v
} else {
puts "$name = $v"
}
}
}
This also could very easily be modified to
print variables in the calling, rather than the
global, scope (just use "upvar 1" instead of
"upvar #0"). Finally, the use of a match-pattern
that defaults to "*" gives a better parallel with
the behaviour of "info vars" and "info global".
hth
--
Jonathan Bromley
This will not always work.
If your variable name contains space, it will fail.
Of course that is not a common usage to have space in
variable name but it is totally legal.
David Bariod
That will go badly wrong if you have any global variables called
'name', you know? Try this one instead:
proc printGlobals {} {
foreach name [info globals] {
upvar #0 $name var
if {![info exist var]} continue; # Skip some awkward cases
if {[array exists var]} {
# This is a bit of cheat for printing an array...
uplevel #0 [list parray $name]
} else {
puts "$name -> $var"
}
}
}
Works when I try it (but produces rather more output than I care to
list here...)
> I know I am overlooking something simple. A little help??
Your problem was that $$ does not do double-dereferencing. You could
have tried with [set $name] instead, but that is still not as good as
the alternative I posted.
Donal.
> upvar #0 $name var
> if {![info exist var]} continue; # Skip some awkwar
Hmmm, so there are cases where globals show up in [info globals] but
don't yet have a value? I know this is the case with namespaced
variables, but couldn't reproduce with the equivalent [global myvar]
command.
Anyway, good to know.
Here's what I use in my "inspect" (code browser) package:
proc ::quotehtml { html } {
return [string map {< < > > & &} $html]
}
proc ::inspect::findVars { namespace {pattern *}} {
return [lsort [info vars ${namespace}::$pattern]]
}
proc ::inspect::displayVars { {namespace ::} {pattern *} } {
set vars [::inspect::findVars $namespace $pattern]
set output "
<h4> Variables in $namespace</h4>
<pre>
"
foreach var $vars {
if {[array exists $var]} {
set arrayNames [array names $var]
append output "Array [quotehtml $var]\n"
foreach arrayName $arrayNames {
append output " [quotehtml ${var}\($arrayName\)] =
'[quotehtml [set ${var}($arrayName)]]'\n"
}
} elseif {[info exists $var]} {
append output " [quotehtml $var] = '[quotehtml [set $var]]'\n"
} else {
append output " [quotehtml $var] is currently undefined\n"
}
}
append output "</pre>\n"
return $output
}
By default this works on the global namespace and avoids the use of
[upvar].
Yes, when there are traces attached to an unset global variable (or
you've done certain very ugly things with [upvar]). This results in
the variable having an entry in the table of variables, but still
being marked as 'not existing'.
Donal.