proc until {cond code} {
uplevel 1 [list while !($cond) $code]
}See also control::do (in tcllib).The original rewriting of the command was like this:list while !$cond $codebut that doesn't work since a cond value of, say, $i > 5 is rewritten as the condition argument !$i > 5 which will always evaluate to false (the ! operator has priority, and the result of evaluating it is either 1 or 0, which is never greater than 5). Other condition strings are likely to lead to other interesting errors.Rewriting the command as
list while !($cond) $codeensures that all of $cond is evaluated before negating the result.
This doesn't implement the usual meaning of until, which executes the code and then tests cond after.Larry Smith I use:
# an unbounded loop or one with a terminating condition of while or until.
# always executes at least once. If no while or until conditions is attached,
# loops forever until <break>.
proc repeat {script {whenexit ""} {test ""}} {
if {[catch {uplevel $script} err]} return
switch -- $whenexit {
"" {uplevel "while 1 \{$script\}"}
"while" {uplevel "while \{$test\} \{$script\}"}
"until" {uplevel "while \{!($test)\} \{$script\}"}
}
}The advantage of the above is you can leave out the while or until entirely and just use break to exit from anywhere in the loop.DKF: The usual definition is typically expressed as a do-while loop, which is a form that puts the test last. When expressed condition-first, it is natural to expect the condition to be checked first...Larry Smith Didn't do it that way since I use do as a compact for loop replacement (this version allows do <var> <expr>..<expr> by <expr>, though it still accepts x for "by"):
proc do {var range loop} {
set br [string first ".." $range]; set by [string first "by" $range $br+1]; if {$by == -1} {set by [string first "x" $range $br+1]}
if {$by == -1} {set by 1; set end end} {set by [expr [string range $range $by+1 end]; set end [expr {$by-1}]}
set from [expr [string range $range 0 $br-1]]; set to [expr [string range $range $br+2 $end]]
if {$to<$from} {if {$by > 0} {! by -$by}; set cond >=} else {set cond "<="}
set script "for \{set $var $from\} \{\$$var $cond $to\} \{incr $var $by\} \{$loop\}"
^^ $script
}RLH Someone else was thinking about this too: until

