Version 4 of refchan

Updated 2010-07-26 17:46:50 by emiliano

[add pointer to this tcl 8.5 core man page and describe the purpose of it.]

http://www.tcl.tk/man/tcl8.5/TclCmd/refchan.htm

DKF: Reflected channels are channels that are implemented in Tcl code. They're also a very new feature.

PT: Here is an implementation of a memchan type memory channel. That is a channel interface to a variable holding some data that you write into it. We can use this in the vfs package to provide various implementations of memchan channels depending upon what packages are loaded into what version of Tcl. It illustrates the necessary construction of a simple reflected channel.

    proc vfs::memchan {} {
        # Create the channel and obtain a generated channel identifier
        set fd [chan create {read write} [namespace origin memchan_handler]]
        # Initialize the data and seek position
        set ::vfs::_memchan_buf($fd) ""
        set ::vfs::_memchan_pos($fd) 0
        return $fd
    }

    proc vfs::memchan_handler {cmd chan args} {
        upvar 1 ::vfs::_memchan_buf($chan) buf
        upvar 1 ::vfs::_memchan_pos($chan) pos
        switch -exact -- $cmd {
            initialize {
                foreach {mode} $args break
                return [list initialize finalize watch read write seek]
            }
            finalize {
                unset buf pos
            }
            seek {
                foreach {offset base} $args break
                switch -exact -- $base {
                    current { incr offset $pos }
                    end     { incr offset [string length $buf] }
                }
                return [set pos $offset]
            }
            read {
                foreach {count} $args break
                set r [string range $buf $pos [expr {$pos + $count - 1}]]
                incr pos [string length $r]
                return $r
            }
            write {
                foreach {data} $args break
                set count [string length $data]
                if { $pos >= [string length $buf] } {
                    append buf $data
                } else {
                    set last [expr { $pos + $count - 1 }]
                    set buf [string replace $buf $pos $last $data]
                }
                incr pos $count
                return $count
            }
            watch {
                # We are required to implement 'watch' but are doing nothing.
                foreach {eventspec} $args break
            }
        }
    }

Usage is something like:

 set chan [vfs::memchan]
 puts $chan "data from somewhere"
 seek $chan 0
 read $chan
 close $chan