'''tcl::chan::join 1.0''' ''Reflected/virtual channel support'' Concatenation channel **SYNOPSIS** package require '''Tcl 8.5''' package require '''TclOO''' package require '''tcl::chan::empty ?1?''' package require '''tcl::chan::join ?1.0?''' * '''::tcl::chan::join''' ?''chan''?... **DESCRIPTION** The '''tcl::chan::join''' package provides a command creating a read-only concatenation channel much like the '''tcl::chan::cat''' command. Unlike '''tcl::chan::cat''', a channel created with '''tcl::chan::join''' supports random.access, i.e. the '''seek''' and '''tell''' commands. Note that if any of the sub-channels does not support random-access (seeking) the join-channel won't support seeking too, and it will be usable only as a sequential, read-only channel. The created channel takes ownership of the sub-channels they were constructed with. Closing the join-channel will close all its sub-channels. For the above rule, a join-channel may be built using the same subchannel more times, ====== set subch [open "fileA.txt" rb] set jch [tcl::chan::join $subch $subch $subch] ;# join $subch 3 times ====== but sharing the same sub-channel among two join-channels may produce unexpected results when one of the join-channels is closed, leaving the other join-channel with a closed subchannel. ====== package require tcl::chan::string set subch [tcl::chan::string "0123456789"] ;# or open a true file ... set jch1 [tcl::chan::join $subch] ;# jch1 'owns' subch set jch2 [tcl::chan::join $subch] ;# jch2 is going to use a subchannel owned by another channel; ;# this is not an error, but the beginning of chaos ... set res1 [read $jch1 4] ;# expected "0123" --> "0123" set res1 [read $jch1 4] ;# expected "3567" --> "3567" set res2 [read $jch2 4] ;# expected "0123" --> "" ???? first unexpected result .. close $jch2 ;# by closing jch2, all its subchannels will be closed. (!including the shared subchannel!) set res1 [read $jch1 4] ;# expected "89" --> error : cannot find channel named xxx (the subchannel name)" ====== **API** '''::tcl::chan::join''' ?''chan''?...: This command creates a read-only, random-access channel, joining all the provided channels, and returns its handle. **Examples** Premise: Altough not indispensable per-se, the presence of the official tcl::chan::* commands of the official Tcllib suite, such as tcl::chan:string, is strongly recommended for composing channels like shown in the following examples. * Get the overall size of a channel ====== package require tcl::chan::string set subch1 [tcl::chan::string "0123456789"] set subch2 [tcl::chan::string "ABCDEFGHIJ"] set jch [tcl::chan::join $subch1 $subch2] chan seek $jch 0 end set nBytes [chan tell $jch] ;# --> 20 ====== * Join the same subchannel more times. Let's suppose we have 3 big files that must be joined, interleaved with a fixed separator ... ====== # be fd1, fd2, fd3 three channelID set chSep [tcl::chan::string "-----separator------"] set jch [tcl::chan::join $fd1 $chSep $fd2 $chSep $fd3] ====== * Join nothing. This may seem a pathological case, but it's legal to create an empty channel! ====== set jch [tcl::chan::join] ;# !no subchannels ! if { [eof $jch] } { puts "EOF reached"} ;# --> .. nothing set contents [read $jch] puts "contents: \"$contents\"" ;# --> contents: "" if { [eof $jch] } { puts "EOF reached"} ;# --> "EOF reached" ====== * Dealing with errors. Usually when a join-channel is closed, all its sub-channels are closed. Note that if a join-channel fails at creation-time, its sub-channels won't be closed. ====== set subch1 [tcl::chan::string "0123456789"] set subch2 "fakeChannel set subch3 [tcl::chan::string "ABCDEFGHIJ"] set jch [tcl::chan::join $subch1 $subch2 $subch2] ;# --> error: can not find channel named "fakeChannel" ... # .... $subch1 and $subch2 are still open valid channelID ====== **KEYWORDS** concatenation channel, reflected channel, tip 219, virtual channel **CATEGORY** Channels **COPYRIGHT** Copyright (c) 2019 Aldo Buratti based on tcl::chan::cat by Andreas Kupries