Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

nested variable expansion in namespace 1

Status
Not open for further replies.

johnlopez2000

Programmer
Aug 2, 2002
90
US
I am creating a nested namespace to create structures for varied computer information. The base namespace is xComputer, then inside it is ::xComputer::${x} where x=the COMPUTERNAME. Please see code below:

Code:
% namespace eval xComputer { }
% set x LOCALHOST
LOCALHOST
% namespace eval ::xComputer::$x { }
% set ::xComputer::${x}::HomeLAN "170.121.142"
170.121.142
% set x yyz0db03
yyz0db03
% namespace eval ::xComputer::$x { }
% set ::xComputer::${x}::HomeLAN "170.121.143"
170.121.143
% namespace children ::xComputer
::xComputer::yyz0db03 ::xComputer::LOCALHOST

so far so good. but now I attempt to 'discover' the namespace children and extract the content of HomeLAN:

Code:
% foreach x [namespace children ::xComputer] { puts $::xComputer::$x::HomeLAN }
can't read "::xComputer::": no such variable

some variations on the above:

Code:
% puts $::xComputer::${x}::HomeLAN
can't read "::xComputer::": no such variable
% puts ${::xComputer::${x}::HomeLAN}
can't read "::xComputer::${x": no such variable
% puts $(::xComputer::${x}::HomeLAN)
can't read "(::xComputer::::xComputer::yyz0db03::HomeLAN)": no such variable
% puts ${::xComputer::$(x)::HomeLAN}
can't read "::xComputer::$(x)::HomeLAN": no such variable
%

I am sure this can be done, but I am apparently missing the obvious.

Thanks for your help.

John Lopez
Enterprise PDM Architect
 
I think that you need that:
Code:
  foreach x [namespace children ::xComputer] { puts [set ::xComputer::$x::HomeLAN] }

It seems that Tcl is not able to substituate inside the namespace part of a qualified name.

A last word:
Code:
  set a
returns the value of the variable a (if a is defined)

More on set at
HTH

ulis
 
Ulis - thanks. that does work.

Code:
foreach x [namespace children ::xComputer] { puts [set ${x}::HomeLAN] }

note that x contains the fully qualified path from xComputer through & including the sub namespace (only mod), as reported by namespace children.

However, is there no way to nest or recursively decompose variable expansion based on brase or parenthetical grouping and order? An additional nesting level in the above may cause the above work around to fail. Such would happen if recursing a N depth nested namespace tree. I suppose one could work around that with a recursive proc call ... 'discovering' a given level, seeing if it has children, and if it does, recursively call the proc again, passing the child namespace, util you hit the bottom. Then eval the [info vars] at that level, and back out.

Thanks

Thanks

John Lopez
Enterprise PDM Architect
 
Not sure to understand:
However, is there no way to nest or recursively decompose variable expansion based on brase or parenthetical grouping and order?

Maybe this can help you?

Code:
  set cname ::x::y::z::name
  set spaces [lrange [split [string map {:: \0} $cname] \0] 1 end-1]
  puts $spaces
[red]x y z[/red]

1- double :: separators are replaced by \0 to have single separators
2- the resulting string is splitted
3- the result is trimmed

Hope this help you

ulis
 
Ulis - thanks, looks helpful.

However, I was thinking more of something like the following pseudo-code:

Code:
set a2 "ns"
set b "2"
set ::ns1::ns2::var 1
set x ${::ns1::${a${b}}::var}
where:
b is expanded first to replace the variable with "2"
then, a2 is expanded to replace the variable with "ns2"
then the namespace path is expanded to varas ::ns1::ns2::var, and the variable x is set to the value=1.

The above is a trivial example, but I hope illustrates it.

Contextually, I am creating namespace based "objects" in the TCL program to represent various computers 'probed' in the network and extracting information from them for administrative tasks.

shelling:

Code:
"net view | grep ${domain-prefix} > /tmp/hostlist.txt"

and then iterating through the hostlist file, i get all the active hosts within the domain.

then using the SysInternals tools, I can extract logged in users, processes on the CPU stack, computer information (including HD's approaching 100%), etc. and then execute needed maintanence via some scripts on the network mounts at that computer via psexec, rsh, etc.

I have used a similar approaching to probing unused/idle CPUs in the company network and executing remote jobs to facilitate massive CAD data file conversions, as an example.

At any rate, the idea here is to place the needed computer info in a structure per computer probed, and then use the information to perform some task.

Other applications, might like LISP, allow one to recurse down a list tree structure, constructed of recursively decomposed namespace paths, until one arrives at the variables (atoms), and then act on their content.

Such could be done via using:
Code:
namespace eval x1 {
	set a 1
	set b 2
	namespace eval x2 {
		set c 3
		set d 4
		namespace eval x3 {
			set e 5
			set f 6
		}

	}
}


proc printVars {{nmspace ""}} {

	if {"$nmspace" == ""} {
	    set xCurrentNamespace [namespace current] 
	} else {
	    set xCurrentNamespace "$nmspace"
	}
	set lCurrentNamespaceChildren [namespace children $xCurrentNamespace ]
	if { "$lCurrentNamespaceChildren" == "" } {
		puts stdout "namespace vars: [info vars ${xCurrentNamespace}::*]"
		foreach i [info vars ${xCurrentNamespace}::*] {
		    puts stdout "variable $i = [set $i]"
		}
	} else {
		foreach ns $lCurrentNamespaceChildren {
		    puts stdout "namespace vars: [info vars ${xCurrentNamespace}::*]"
		    foreach i [info vars ${xCurrentNamespace}::*] {
		        puts stdout "variable $i = [set $i]"
		     }
			set x [printVars $ns]
		}
	}
}

set x [printVars "x1"]

however, I suppose what I was trying to get to was an inline decomposure.

Thanks

John Lopez
Enterprise PDM Architect
 
If you want objects, may this is more simpler for you:
Code:
  array set ::objects {}
  # create a node
  set departement R&D
  set node $department.//Alice
  set ::objects($node.address) $ip
  # add user
  lappend ::objects($node.users) $user1
  # add application
  lappend ::objects($node.appli) $appli1
  # get all users of R&D:
  set rdusers [list]
  for each nodeusers [array names ::objects R&D.*.users] \
  { set rdusers [concat $rdusers $nodeusers] }

My advice is to use array when you need to build var names.

One more advice: build variable names then get their value by set:
Code:
  set a2 "ns"
  set b "2"
  set varname ::ns1::$a$b::var
  set x [set $varname]
[blue](${::ns1::${a${b}}::var} is NOT what you want)[/blue]

HTH

ulis
 
Ulis -thanks again. Please note the following:

Code:
% set a2 "ns"
ns
%   set b "2"
2
%   set varname ::ns1::$a$b::var
can't read "a": no such variable
%   set x [set $varname]
can't read "varname": no such variable
%

John Lopez
Enterprise PDM Architect
 
maybe set varname ::ns1::$a$b::var should be ::ns1::$a[red]2[/red]$b::var

_________________
Bob Rashkin
 
Bong - thanks.

However, the idea is that b=2, and therefore the represented constructive name of the variable a2 is contructed from the char 'a' + the variable expansion of 'b' which equals 2. therefore a$b = variable name a2, and then, and expansion of a2 would yield the intermediate namespace name.

Hence, this requires a nested variable expansion, which TCL apparently does not support.

The idea of per the following pseudo-code:
Code:
set c 2
set b2 1
set a1 "Hi there"
puts stdout "$a($b($c))"

would suggest that there was operator/parenthetical precidence that could be applied to variable expansion on the command line. Thus, this would recon to a precidence based recursion of variable expansion based on the above grouping.

Thanks again.

John Lopez
Enterprise PDM Architect
 
The syntax you stated above: set varname ::ns1::$a$b::var is read by the interpreter as: associate the variable named 'varname' with the value '::ns1::' followed by the value of the variable 'a' followed by the value of the variable 'b' followed by '::var'.

So I guess what you want is set varname ::ns1::[red]\[/red]$a$b::var.



_________________
Bob Rashkin
 
You're near to win John ;-)

Code:
  set c 2
  set b(2) 1
  set a(1) "Hi there"
  puts stdout "$a($b($c))"

ulis
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top