if false { For the impatient, the star expansion {*}(expr) can be emulated inside a proc. In Tcl 8.4 the procedure xproc below transforms it to a eval-construction. } # stringIsList {ab c d} => yes # stringIsList {ab {*}c d} => no proc stringIsList s { expr {[catch {llength $s}] ? no : yes} } # findClosingBrace {[list a b] c d e} => {[list a b]} # findClosingBrace {{a b} c d} => {a b} # findClosingBrace {$abc def ghi} => {$abc} # findClosingBrace {abc def ghi} => {abc} proc findClosingBrace str { array set closing [list \[ \] \{ \} \" \"] switch -exact -- [string index $str 0] { \[ - \{ - \" { set i 0 set closingBrace $closing([string index $str 0]) set i [string first $closingBrace $str] while {![info complete [string range $str 0 $i]]} { set i [string first $closingBrace $str [incr i]] } if {$i < 0} then { return -code error [list unmatched delimiter on $str] } string range $str 0 $i } default { set l [regexp -inline {^[$]?[[:alnum:]_]*(?:[[:space:]]|$)} $str] string trimright [lindex $l 0] } } } # expandStar {abc def} => {abc def} # expandStar {c {*}d e c {*}d e} => {{c } d { e c } d { e}} proc expandStar {line {i 0}} { set i [string first "{*}" $line $i] if {$i < 0 || [stringIsList $line]} then { list $line } else { set result {} set i0 [expr {$i - 1}] set first [string range $line 0 $i0] lappend result $first set i3 [expr {$i + 3}] set expr [findClosingBrace [string range $line $i3 end]] lappend result $expr set iRest [expr {$i3 + [string length $expr]}] set rest [string range $line $iRest end] eval lappend result [expandStar $rest] } } # expandCommandLine {abc def} => {abc def} # expandCommandLine {c {*}d e} => {eval [list c] d [list e]} # expandCommandLine {ab [c {*}d e] e f} => {ab [eval [list c] d [list e]] e f} proc expandCommandLine line { if {[string first {{*}} $line] < 0} then { return $line } regexp {^[[:space:]]*} $line result append result eval set i [string first \[ $line] if {$i < 0} { foreach {a b} [expandStar $line] { set a [string trim $a] if {$a ne ""} then { append result " \[list " $a "\]" } append result " " $b } string trimright $result } else { set line1 [string range $line 0 [expr {$i - 1}]] set middle [findClosingBrace [string range $line $i end]] set l [string length $middle] set expr [string range $middle 1 end-1] append line1 \[ [expandCommandLine $expr] \] set rest [string range $line [expr {$i + $l}] end] append line1 [expandCommandLine $rest] set result "" foreach {a b} [expandStar $line1] { set a [string trim $a] if {$a ne ""} then { append result " \[list " $a "\]" } append result " " $b } string trimright $result } } proc explodeLines lines { set result {} set currentLine "" foreach line [split $lines \n] { append currentLine \n $line if {[info complete $currentLine]} then { lappend result [string trimleft $currentLine \n] set currentLine "" } } set result } proc xproc {name arglist body} { set expandedLines {} foreach line [explodeLines $body] { lappend expandedLines [expandCommandLine $line] } uplevel [list proc $name $arglist [join $expandedLines \n]] } if false { sourceCode is a simplified proc-inspector: } proc sourceCode p { list proc $p [info args $p] [info body $p] } if false { This little test proc shows us how to do it: } xproc test1 arg1 { list {*}$arg1 } if false { Now watch the result: % sourceCode test1 proc test1 arg1 { eval [list list] $arg1 } % The {*} construction has been replaced by an appropriate eval construction. }