Reputation: 35
Im trying to modify a variable using upvar (in an upward stack), but the value of the variable is passed to the procedure and not the variable name.
I cannot change what is passed, since it is already implemented widely on the program.
Is there a way to modify the file name in some way ?
proc check_file_exists {name} {
upvar $name newName
check_exists $name #Do all checks that file is there
set newName $name_1
}
check_file_exists $name
puts $name
this code will print the old name of the file and not the new one.
Upvotes: -1
Views: 355
Reputation: 13282
What I think you should do is bite the bullet and change the calls. It's a fairly simple search-and-replace, after all. The code will be more sane than if you use any of the other solutions.
check_file_exists name
Or, you could add another parameter to the parameter list and use that to pass the name, making the first argument a dummy argument.
check_file_exists $name name
Or, if you're not using the return value, you could return the new value and assign it back:
set name [check_file_exists $name]
Or, you could assign the new value to a global variable (e.g. theValue
) inside the procedure, and assign that back:
check_file_exists $name
# don't need this if you're in global scope
global theValue
set name $theValue
Or, you could assign the name to a global variable (e.g. theName
) and access that inside the procedure: the procedure will be able to update name
directly.
# don't need this if you're in global scope
global theName
set theName name
check_file_exists $name
(There are some variations on this f.i. using upvar
.)
None of the alternatives are pretty, and all of them still require you to make a change at the call (except the last, if you only ever use one variable for this value). If you're adamant about not doing that, there's always Donal's info frame
solution, which only requires the procedure itself to be changed.
Let me know if you want help with the procedure code for any of these alternatives.
Upvotes: 1
Reputation: 137787
This is quite difficult; it's really not the way you're supposed to work. But you can do it using info frame -1
(a facility usually used for debugging) to find out exactly how the current procedure was called. However, you need to be careful as the caller might be using the result of a command: this is an unsafe hack.
proc check_file_exists {name} {
set caller [dict get [info frame -1] cmd]
if {[regexp {^check_file_exists +\$(\w+)} $caller -> varName]} {
# OK, we were called with a simple variable name
puts "Called with variable $varName"
} else {
# Complicated case! Help...
return -code error "must be called with a simple variable's contents"
}
upvar 1 $varName newName
check_exists $name
set newName $name_1
}
Upvotes: 1