A [channel] '''[http://www.tcl.tk/man/tcl/TclCmd/transchan.htm%|%transform]''' is a mapping applied at the byte-level to a [channel] . It operates on bytes rather than strings . Tcl converts to/from the channel's [encoding] at a higher level (closer to the script level) than transforms operate at . ** Examples ** [TLS]: uses transforms internally. ** Description ** Transforms are instrumental in [stacked channels] . [PT]: Here is an example of a [base64] channel transform using Tcl [Changes in Tcl/Tk 8.6%|%8.6] features. You push this transform onto any other sort of channel and it will base64 encode the data as it passes through. ====== # A base64 channel transform. # # usage: chan push $channel ::tcl::binary::transform_base64 # package require Tcl 8.6 proc ::tcl::binary::K {a b} {set a} proc ::tcl::binary::transform_base64 {cmd handle args} { upvar #0 [namespace current]::_transform_r_$handle rstate upvar #0 [namespace current]::_transform_w_$handle wstate switch -exact -- $cmd { initialize { set rstate {}; set wstate {} return [list initialize finalize read write flush drain] } finalize { unset rstate wstate return } write { foreach buffer $args break append wstate $buffer set len [string length $wstate] set end [expr {$len - ($len % 3)}] set edge [expr {$end - 1}] set res [binary encode base64 [string range $wstate 0 $edge]] set wstate [string range $wstate $end end] return $res } flush { set buffer [K $wstate [set wstate {}]] set res [binary encode base64 $buffer] return $res } read { foreach buffer $args break append rstate $buffer set len [string length $rstate] set end [expr {$len - ($len % 4)}] set edge [expr {$end - 1}] set res [string range $rstate 0 $edge] set rstate [string range $rstate $end end] set resx [binary decode base64 $res] if {[string length $resx] % 3 != 0} { puts stderr "alert: $res" } return $resx } drain { set res [K [binary decode base64 $rstate] [set rstate {}]] return $res } } } ====== The above channel transform will not wrap lines , so you end up with a file with one line of base64 encoded data . It is more common to see such files broken into lines every 60 characters or so . As channel transforms are stackable we can choose to have a second transform deal with writing such files . ====== proc ::tcl::binary::maxlen {maxlen wrapchar cmd handle args} { upvar #0 [namespace current]::_maxlen_$handle state switch -exact -- $cmd { initialize { set state {} return [list initialize finalize write flush read] } finalize {unset state} write { foreach data $args break append state $data set mark 0 set edge [expr {$maxlen - 1}] set res {} while {([string length $state] - $mark) > $maxlen} { append res [string range $state $mark $edge]$wrapchar incr mark $maxlen incr edge $maxlen } set state [string range $state $mark end] return $res } flush {return [K $state [set state {}]]} read {return [lindex $args 0]} } } ====== This transform buffers the output data, injecting ''wrapchar'' every ''maxlen'' characters . To use this , we first stack this transform and then the base64 transform onto the primary channel . For instance : ====== set f [open $filename w] chan push $f [list ::tcl::binary::maxlen 60 \n] chan push $f [list ::tcl::binary::transform_base64] puts $f $data seek $f 0 read $f close $f ====== [Lars H]: Here is a rewrite of the above '''maxlen''' as an [ensemble with parameters]: ====== namespace eval ::tcl::binary::maxlen { namespace export initialize finalize write flush read namespace ensemble create -parameters {maxlen wrapchar} proc initialize {maxlen wrapchar handle mode} { variable $handle {} return [namespace export] } proc finalize {maxlen wrapchar handle} { unset [namespace current]::$handle } proc write {maxlen wrapchar handle data} { namespace upvar ::tcl::binary::maxlen $handle state append state $data set mark 0 set edge [expr {$maxlen - 1}] set res {} while {([string length $state] - $mark) > $maxlen} { append res [string range $state $mark $edge]$wrapchar incr mark $maxlen incr edge $maxlen } set state [string range $state $mark end] return $res } proc flush {maxlen wrapchar handle} { namespace upvar ::tcl::binary::maxlen $handle state return $state[set state {}] } proc read {maxlen wrapchar handle data} {return $data} } ====== ** See Also ** [channel]: the starting point for info about channels <> Channel | Concept