Julian Noble
8 months ago
74 changed files with 5589 additions and 0 deletions
@ -0,0 +1,124 @@ |
|||||||
|
2019-03-12 Aldo Buratti |
||||||
|
|
||||||
|
* cat.tcl - BUGFIX in event-handling . Version bumped to 1.0.3 |
||||||
|
* |
||||||
|
2013-12-17 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* randseed.man: Fixed package name. |
||||||
|
|
||||||
|
2013-11-22 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* memchan.tcl (Events): Ticket [864a0c83e3]. Do not suppress |
||||||
|
* string.tcl: readable events at end of the channel. Needed |
||||||
|
* variable.tcl: to signal the eof condition. Like for regular |
||||||
|
files, always readable. Versions bumped to 1.0.3, 1.0.2, and |
||||||
|
1.0.3 respectively |
||||||
|
|
||||||
|
2013-04-03 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* tclib_fifo2.man: Renamed more manpages, clashing with the |
||||||
|
* tclib_fifo.man: Memchan package. List are the new names, |
||||||
|
* tclib_memchan.man: with prefix "tcllib_". |
||||||
|
* tclib_null.man: |
||||||
|
* tclib_random.man: |
||||||
|
* tclib_zero.man: |
||||||
|
|
||||||
|
2013-03-04 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* string.man: Renamed, clashes with Tcl core manpage. |
||||||
|
* tcllib_string.man: New name. |
||||||
|
|
||||||
|
* variable.man: Renamed, clashes with Tcl core manpage. |
||||||
|
* tcllib_variable.man: New name. |
||||||
|
|
||||||
|
2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.15 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2012-10-05 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* cat.tcl (read): Fixed bugs in the reader. Bad check of buffer |
||||||
|
* pkgIndex.tcl: length, and buffer length was not taken into |
||||||
|
account for the next read after an incomplete one. Version |
||||||
|
bumped to 1.0.2. |
||||||
|
|
||||||
|
2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.14 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2011-08-09 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* memchan.tcl: Fixed missing initialization of 'content' instance |
||||||
|
variable. Bumped to version 1.0.2. |
||||||
|
|
||||||
|
* variable.tcl: Fixed missing invokation of superclass |
||||||
|
constructor. Fixed missing initialization of linked 'content' |
||||||
|
variable, if not existing. Fixed missing import of linked |
||||||
|
variable into the event handling. Bumped to version 1.0.2. |
||||||
|
|
||||||
|
* cat.tcl: Removed bogus invokation of superclass constructor, |
||||||
|
there is no such. Bumped to version 1.0.1. |
||||||
|
|
||||||
|
* facade.tcl: Added missing logger requirements, dropped bogus |
||||||
|
call to superclass constructor. Bumped to version 1.0.1. |
||||||
|
|
||||||
|
* std.tcl: Fixed command scoping issues, and dropped bogus call to |
||||||
|
superclass constructor. Bumped to version 1.0.1. |
||||||
|
|
||||||
|
2011-05-31 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* cat.man: New base channels. Concatenation of channels, |
||||||
|
* cat.tcl: standard channel combining stdin and stdout, |
||||||
|
* facade.man: and a facade for wrapping around other |
||||||
|
* facade.tcl: channels. |
||||||
|
* std.man: |
||||||
|
* std.tcl: |
||||||
|
* pkgIndex.tcl: |
||||||
|
|
||||||
|
2011-02-21 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* pkgIndex.tcl: Removed the superfluous [list] command in the |
||||||
|
ifneeded script. |
||||||
|
|
||||||
|
2011-02-16 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* memchan.tcl: Fixed constructor chaining, added the missing |
||||||
|
* pkgIndex.tcl: 'next'. The bug prevented proper initialization |
||||||
|
* string.tcl: of the event core. All versions bumped to 1.0.1 |
||||||
|
* variable.tcl: |
||||||
|
|
||||||
|
2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.13 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2010-07-29 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* fifo.man: New files, documentation for the packages in |
||||||
|
* fifo2.man: this module. |
||||||
|
* halfpipe.man: |
||||||
|
* memchan.man: |
||||||
|
* null.man: |
||||||
|
* nullzero.man: |
||||||
|
* random.man: |
||||||
|
* randseed.man: |
||||||
|
* string.man: |
||||||
|
* textwindow.man: |
||||||
|
* variable.man: |
||||||
|
* zero.man: |
||||||
|
|
||||||
|
2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.12 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2009-12-01 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* New module 'virtchannel_base', providing classes implementing |
||||||
|
various virtual channels aka reflected channels. TclOO based. |
@ -0,0 +1,44 @@ |
|||||||
|
null, zero, fifo, memchan, fifo2 |
||||||
|
|
||||||
|
Re-implementations of Memchan's channel types. |
||||||
|
|
||||||
|
random |
||||||
|
|
||||||
|
Semi re-implementation of a Memchan channel type. |
||||||
|
"Random" byte generator, simple feedback register. |
||||||
|
Memchan uses ISAAC (http://burtleburtle.net/bob/rand/isaacafa.html). |
||||||
|
|
||||||
|
string, variable |
||||||
|
|
||||||
|
Variants of 'memchan', with fixed content, and the content |
||||||
|
factored out to a namespaced variable, respectively. |
||||||
|
|
||||||
|
randomseed |
||||||
|
|
||||||
|
Support to generate and combine seed lists for the |
||||||
|
random channel, using semi-random sources in Tcl. |
||||||
|
|
||||||
|
halfpipe |
||||||
|
|
||||||
|
Half channel, simpler callback API. fifo2 is build on top this |
||||||
|
basic block. |
||||||
|
|
||||||
|
textwindow |
||||||
|
|
||||||
|
Channel attaches to text widget to write data into. |
||||||
|
|
||||||
|
cat |
||||||
|
|
||||||
|
Concatenation channel, delivering the data from 1 or more |
||||||
|
channels, one after the other. |
||||||
|
|
||||||
|
facade |
||||||
|
|
||||||
|
A wrapper around any other channel. Mainly for debugging, |
||||||
|
allowing a developer to observe the activity on the wrapped |
||||||
|
channel. |
||||||
|
|
||||||
|
std |
||||||
|
|
||||||
|
Unification of stdin and stdout into a single read/write |
||||||
|
channel |
@ -0,0 +1,48 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[vset Version 1.0.4] |
||||||
|
[manpage_begin tcl::chan::cat n [vset Version]] |
||||||
|
[keywords {concatenation channel}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2011 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Concatenation channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::core [opt 1.1]] |
||||||
|
[require tcl::chan::cat [opt [vset Version]]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::cat] package provides a command creating |
||||||
|
concatenation channels. These are non-seekable channels owning a list |
||||||
|
of subordinate channels whose contents they return in order, until all |
||||||
|
are exhausted. In this manner the channel is the concatentation of the |
||||||
|
contents of all the sub-ordinate channels. |
||||||
|
|
||||||
|
[para] Note that the created channels take ownership of the channels |
||||||
|
they were constructed with. Whenever they have exhausted one of their |
||||||
|
channel it will be closed. Similarly, closing the cat channel will |
||||||
|
close all the sub-ordinates it still has. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::core] framework. |
||||||
|
|
||||||
|
[para] Event handling is delegated to the currently active sub-channel. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::cat] [arg chan]...] |
||||||
|
|
||||||
|
This command creates the concatenation channel using all the provided |
||||||
|
channels, and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,135 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2011,2019 Andreas Kupries |
||||||
|
|
||||||
|
# Facade concatenating the contents of the channels it was constructed |
||||||
|
# with. Owns the sub-ordinate channels and closes them on exhaustion and/or |
||||||
|
# when closed itself. |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::cat 1.0.4 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2011 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Facade concatenating the contents of the channels it |
||||||
|
# Meta description was constructed with. Owns the sub-ordinate channels |
||||||
|
# Meta description and closes them on exhaustion and/or when closed itself. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::core |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::cat {args} { |
||||||
|
return [::chan create {read} [cat::implementation new {*}$args]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::cat::implementation { |
||||||
|
superclass ::tcl::chan::core ; # -> initialize, finalize. |
||||||
|
|
||||||
|
# We are not using the standard event handling class, because here |
||||||
|
# it will not be timer-driven. We propagate anything related to |
||||||
|
# events to catin and catout instead and let them handle things. |
||||||
|
|
||||||
|
constructor {args} { |
||||||
|
set channels $args |
||||||
|
# Disable translation (and hence encoding) in the wrapped channels. |
||||||
|
# This will happen in our generic layer instead. |
||||||
|
foreach c $channels { |
||||||
|
fconfigure $c -translation binary |
||||||
|
} |
||||||
|
set delay 10 |
||||||
|
set watching 0 |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
destructor { |
||||||
|
foreach c $channels { |
||||||
|
::close $c |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
variable channels timer delay watching |
||||||
|
|
||||||
|
method watch {c requestmask} { |
||||||
|
if {"read" in $requestmask} { |
||||||
|
# Activate event handling. Either drive an eof home via |
||||||
|
# timers, or activate things in the foremost sub-ordinate. |
||||||
|
|
||||||
|
set watching 1 |
||||||
|
if {![llength $channels]} { |
||||||
|
set timer [after $delay [namespace code [list my Post $c]]] |
||||||
|
} else { |
||||||
|
chan event [lindex $channels 0] readable [list chan postevent $c read] |
||||||
|
} |
||||||
|
} else { |
||||||
|
# Stop events. Either kill timer, or disable in the |
||||||
|
# foremost sub-ordinate. |
||||||
|
|
||||||
|
set watching 0 |
||||||
|
if {![llength $channels]} { |
||||||
|
catch { after cancel $timer } |
||||||
|
} else { |
||||||
|
chan event [lindex $channels 0] readable {} |
||||||
|
} |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
if {![llength $channels]} { |
||||||
|
# This signals EOF higher up. |
||||||
|
return {} |
||||||
|
} |
||||||
|
|
||||||
|
set buf {} |
||||||
|
while {([string length $buf] < $n) && |
||||||
|
[llength $channels]} { |
||||||
|
|
||||||
|
set in [lindex $channels 0] |
||||||
|
set toread [expr {$n - [string length $buf]}] |
||||||
|
append buf [::read $in $toread] |
||||||
|
|
||||||
|
if {[eof $in]} { |
||||||
|
close $in |
||||||
|
set channels [lrange $channels 1 end] |
||||||
|
|
||||||
|
# The close of the exhausted subordinate killed any |
||||||
|
# fileevent handling we may have had attached to this |
||||||
|
# channel. Update the settings (i.e. move to the next |
||||||
|
# subordinate, or to timer-based, to drive the eof |
||||||
|
# home). |
||||||
|
|
||||||
|
if {$watching} { |
||||||
|
my watch $c read |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# When `buf` is empty, all channels have been exhausted and |
||||||
|
# closed, therefore returning this empty string will cause an |
||||||
|
# EOF higher up. |
||||||
|
return $buf |
||||||
|
} |
||||||
|
|
||||||
|
method Post {c} { |
||||||
|
set timer [after $delay [namespace code [list my Post $c]]] |
||||||
|
chan postevent $c read |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::cat 1.0.4 |
||||||
|
return |
@ -0,0 +1,69 @@ |
|||||||
|
#- - -- --- ----- -------- ------------- --------------------- |
||||||
|
# cat.test -*- tcl -*- |
||||||
|
# (C) 2019 Andreas Kupries. BSD licensed. |
||||||
|
#- - -- --- ----- -------- ------------- --------------------- |
||||||
|
|
||||||
|
source [file join \ |
||||||
|
[file dirname [file dirname [file join [pwd] [info script]]]] \ |
||||||
|
devtools testutilities.tcl] |
||||||
|
|
||||||
|
testsNeedTcl 8.5 |
||||||
|
testsNeedTcltest 2.0 |
||||||
|
testsNeed TclOO 1 |
||||||
|
|
||||||
|
support { |
||||||
|
use virtchannel_core/core.tcl tcl::chan::core |
||||||
|
use virtchannel_core/events.tcl tcl::chan::events |
||||||
|
useLocal string.tcl tcl::chan::string |
||||||
|
} |
||||||
|
testing { |
||||||
|
useLocal cat.tcl tcl::chan::cat |
||||||
|
} |
||||||
|
|
||||||
|
#- - -- --- ----- -------- ------------- --------------------- |
||||||
|
## No wrong#args, allowed to zero and up |
||||||
|
|
||||||
|
#- - -- --- ----- -------- ------------- --------------------- |
||||||
|
|
||||||
|
test tcl-chan-cat-2.0 {tell, nothing} -setup { |
||||||
|
set c [tcl::chan::cat] |
||||||
|
} -body { |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result -1 |
||||||
|
|
||||||
|
test tcl-chan-cat-2.1 {ticket 1975182bdd - file events} -setup { |
||||||
|
# setup a cat'enated channel |
||||||
|
set fa [tcl::chan::string "ABCDE..XYZ"] |
||||||
|
set fb [tcl::chan::string "0123456789"] |
||||||
|
set ch [tcl::chan::cat $fa $fb] |
||||||
|
} -body { |
||||||
|
set r {} |
||||||
|
chan event $ch readable { |
||||||
|
if { [eof $ch] } { |
||||||
|
set done . |
||||||
|
} else { |
||||||
|
lappend r [read $ch 4] |
||||||
|
} |
||||||
|
} |
||||||
|
vwait done |
||||||
|
set r |
||||||
|
} -cleanup { |
||||||
|
close $ch |
||||||
|
unset ch fa fb r |
||||||
|
} -result {ABCD E..X YZ01 2345 6789 {}} |
||||||
|
|
||||||
|
#- - -- --- ----- -------- ------------- --------------------- |
||||||
|
# Explicit cleanup of loaded support classes. |
||||||
|
|
||||||
|
rename tcl::chan::events {} |
||||||
|
rename tcl::chan::core {} |
||||||
|
testsuiteCleanup |
||||||
|
return |
||||||
|
|
||||||
|
# Local Variables: |
||||||
|
# mode: tcl |
||||||
|
# indent-tabs-mode: nil |
||||||
|
# End: |
@ -0,0 +1,73 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::facade n 1.1] |
||||||
|
[keywords {concatenation channel}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2011 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Facade channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require logger] |
||||||
|
[require tcl::chan::core [opt 1.1]] |
||||||
|
[require tcl::chan::facade [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::facade] package provides a command creating |
||||||
|
facades to other channels. These are channels which own a single |
||||||
|
subordinate channel and delegate all operations to. |
||||||
|
|
||||||
|
[para] The main use for facades is the debugging of actions on a |
||||||
|
channel. While most of the information could be tracked by a virtual |
||||||
|
channel transformation it does not have access to the event-related |
||||||
|
operation, and furthermore they are only available in Tcl 8.6. |
||||||
|
|
||||||
|
[para] Therefore this channel, usable with Tcl 8.5, and having access |
||||||
|
to everything going on for a channel. |
||||||
|
|
||||||
|
[para] The intercepted actions on channel are logged through package |
||||||
|
[package logger]. |
||||||
|
|
||||||
|
[para] Beyond that facades provide the following additional channel |
||||||
|
configuration options: |
||||||
|
|
||||||
|
[list_begin options] |
||||||
|
[opt_def -self] |
||||||
|
The TclOO object handling the facade. |
||||||
|
|
||||||
|
[opt_def -fd] |
||||||
|
The handle of the subordinate, i.e. wrapped channel. |
||||||
|
|
||||||
|
[opt_def -used] |
||||||
|
The last time the wrapped channel was read from or written to by |
||||||
|
the facade, as per [cmd {clock milliseconds}]. A value of [const 0] |
||||||
|
indicates that the subordinate channel was not accessed at all, yet. |
||||||
|
|
||||||
|
[opt_def -created] |
||||||
|
The time the facade was created, as per [cmd {clock milliseconds}]. |
||||||
|
|
||||||
|
[opt_def -user] |
||||||
|
A free-form value identifying the user of the facade and its |
||||||
|
wrapped channel. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
Of these only option [option -user] is writable. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::facade] [arg chan]] |
||||||
|
|
||||||
|
This command creates the facade channel around the provided |
||||||
|
channel [arg chan], and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,234 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2011 Andreas Kupries |
||||||
|
|
||||||
|
# Facade wrapping around some other channel. All operations on the |
||||||
|
# facade are delegated to the wrapped channel. This makes it useful |
||||||
|
# for debugging of Tcl's activity on a channel. While a transform can |
||||||
|
# be used for that as well it does not have access to some things of |
||||||
|
# the base-channel, i.e. all the event managment is not visible to it, |
||||||
|
# whereas the facade has access to even this. |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::facade 1.0.2 |
||||||
|
# Meta as::author {Colin McCormack} |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2011 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Facade wrapping around some other channel. All |
||||||
|
# Meta description operations on the facade are delegated to the |
||||||
|
# Meta description wrapped channel. This makes it useful for debugging |
||||||
|
# Meta description of Tcl's activity on a channel. While a transform |
||||||
|
# Meta description can be used for that as well it does not have |
||||||
|
# Meta description access to some things of the base-channel, i.e. all |
||||||
|
# Meta description the event managment is not visible to it, whereas |
||||||
|
# Meta description the facade has access to even this. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::core |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
## TODO document the special options of the facade |
||||||
|
## TODO log integration. |
||||||
|
## TODO document that facada takes ownership of the channel. |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require logger |
||||||
|
package require tcl::chan::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
logger::initNamespace ::tcl::chan::facade |
||||||
|
proc ::tcl::chan::facade {args} { |
||||||
|
return [::chan create {read} [facade::implementation new {*}$args]] |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::facade::implementation { |
||||||
|
superclass ::tcl::chan::core ; # -> initialize, finalize. |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
# We are not using the standard event handling class, because here |
||||||
|
# it will not be timer-driven. We propagate anything related to |
||||||
|
# events to the wrapped channel instead and let it handle things. |
||||||
|
|
||||||
|
constructor {thechan} { |
||||||
|
# Access to the log(ger) commands. |
||||||
|
namespace path [list {*}[namespace path] ::tcl::chan::facade] |
||||||
|
|
||||||
|
set chan $thechan |
||||||
|
|
||||||
|
# set some configuration data |
||||||
|
set created [clock milliseconds] |
||||||
|
set used 0 |
||||||
|
set user "" ;# user data - freeform |
||||||
|
|
||||||
|
# validate args |
||||||
|
if {$chan eq [self]} { |
||||||
|
return -code error "recursive chan! No good." |
||||||
|
} elseif {$chan eq ""} { |
||||||
|
return -code error "Needs a chan argument" |
||||||
|
} |
||||||
|
|
||||||
|
set blocking [::chan configure $chan -blocking] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
destructor { |
||||||
|
log::debug {[self] destroyed} |
||||||
|
if {[catch { ::chan close $chan } e o]} { |
||||||
|
log::debug {failed to close $chan [self] because "$e" ($o)} |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
variable chan used user created blocking |
||||||
|
|
||||||
|
method initialize {myself mode} { |
||||||
|
log::debug {$myself initialize $chan $mode} |
||||||
|
log::debug {$chan configured: ([::chan configure $chan])} |
||||||
|
return [next $chan $mode] |
||||||
|
} |
||||||
|
|
||||||
|
method finalize {myself} { |
||||||
|
log::debug {$myself finalize $chan} |
||||||
|
catch {::chan close $chan} |
||||||
|
catch {next $myself} |
||||||
|
catch {my destroy} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method blocking {myself mode} { |
||||||
|
if {[catch { |
||||||
|
::chan configure $chan -blocking $mode |
||||||
|
set blocking $mode |
||||||
|
} e o]} { |
||||||
|
log::debug {$myself blocking $chan $mode -> error $e ($o)} |
||||||
|
} else { |
||||||
|
log::debug {$myself blocking $chan $mode -> $e} |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method watch {myself requestmask} { |
||||||
|
log::debug {$myself watch $chan $requestmask} |
||||||
|
|
||||||
|
if {"read" in $requestmask} { |
||||||
|
fileevent readable $chan [my Callback Readable $myself] |
||||||
|
} else { |
||||||
|
fileevent readable $chan {} |
||||||
|
} |
||||||
|
|
||||||
|
if {"write" in $requestmask} { |
||||||
|
fileevent writable $chan [my Callback Writable $myself] |
||||||
|
} else { |
||||||
|
fileevent writable $chan {} |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method read {myself n} { |
||||||
|
log::debug {$myself read $chan begin eof: [::chan eof $chan], blocked: [::chan blocked $chan]} |
||||||
|
set used [clock milliseconds] |
||||||
|
|
||||||
|
if {[catch { |
||||||
|
set data [::chan read $chan $n] |
||||||
|
} e o]} { |
||||||
|
log::error {$myself read $chan $n -> error $e ($o)} |
||||||
|
} else { |
||||||
|
log::debug {$myself read $chan $n -> [string length $data] bytes: [string map {\n \\n} "'[string range $data 0 20]...[string range $data end-20 end]"]'} |
||||||
|
log::debug {$myself read $chan eof = [::chan eof $chan]} |
||||||
|
log::debug {$myself read $chan blocked = [::chan blocked $chan]} |
||||||
|
log::debug {$chan configured: ([::chan configure $chan])} |
||||||
|
|
||||||
|
set gone [catch {chan eof $chan} eof] |
||||||
|
if { |
||||||
|
($data eq {}) && |
||||||
|
!$gone && !$eof && !$blocking |
||||||
|
} { |
||||||
|
log::error {$myself EAGAIN} |
||||||
|
return -code error EAGAIN |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
log::debug {$myself read $chan result: [string length $data] bytes} |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method write {myself data} { |
||||||
|
log::debug {$myself write $chan [string length $data] / [::chan pending output $chan] / [::chan pending output $myself]} |
||||||
|
set used [clock milliseconds] |
||||||
|
::chan puts -nonewline $chan $data |
||||||
|
return [string length $data] |
||||||
|
} |
||||||
|
|
||||||
|
method configure {myself option value} { |
||||||
|
log::debug {[self] configure $myself $option -> $value} |
||||||
|
|
||||||
|
if {$option eq "-user"} { |
||||||
|
set user $value |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
::chan configure $fd $option $value |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method cget {myself option} { |
||||||
|
switch -- $option { |
||||||
|
-self { return [self] } |
||||||
|
-fd { return $chan } |
||||||
|
-used { return $used } |
||||||
|
-created { return $created } |
||||||
|
-user { return $user } |
||||||
|
default { |
||||||
|
return [::chan configure $chan $option] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
method cgetall {myself} { |
||||||
|
set result [::chan configure $chan] |
||||||
|
lappend result \ |
||||||
|
-self [self] \ |
||||||
|
-fd $chan \ |
||||||
|
-used $used \ |
||||||
|
-created $created \ |
||||||
|
-user $user |
||||||
|
|
||||||
|
log::debug {[self] cgetall $myself -> $result} |
||||||
|
return $result |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
# Internals. Methods. Event generation. |
||||||
|
method Readable {myself} { |
||||||
|
log::debug {$myself readable $chan - [::chan pending input $chan]} |
||||||
|
::chan postevent $myself read |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method Writable {myself} { |
||||||
|
log::debug {$myself writable $chan - [::chan pending output $chan]} |
||||||
|
::chan postevent $myself write |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method Callback {method args} { |
||||||
|
list [uplevel 1 {namespace which my}] $method {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::facade 1.0.2 |
||||||
|
return |
@ -0,0 +1,138 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::fifo 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Re-implementation of Memchan's fifo |
||||||
|
# Meta description channel. Based on Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new |
||||||
|
# Meta description channels. No arguments. Result is the |
||||||
|
# Meta description handle of the new channel. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::fifo {} { |
||||||
|
return [::chan create {read write} [fifo::implementation new]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::fifo::implementation { |
||||||
|
superclass ::tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow write |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
set max [string length $read] |
||||||
|
set last [expr {$at + $n - 1}] |
||||||
|
set result {} |
||||||
|
|
||||||
|
# last+1 <= max |
||||||
|
# <=> at+n <= max |
||||||
|
# <=> n <= max-at |
||||||
|
|
||||||
|
if {$n <= ($max - $at)} { |
||||||
|
# The request is less than what we have left in the read |
||||||
|
# buffer, we take it, and move the read pointer forward. |
||||||
|
|
||||||
|
append result [string range $read $at $last] |
||||||
|
incr at $n |
||||||
|
incr $size -$n |
||||||
|
} else { |
||||||
|
# We need the whole remaining read buffer, and more. For |
||||||
|
# the latter we shift the write buffer contents over into |
||||||
|
# the read buffer, and then read from the latter again. |
||||||
|
|
||||||
|
append result [string range $read $at end] |
||||||
|
incr n -[string length $result] |
||||||
|
|
||||||
|
set at 0 |
||||||
|
set read $write |
||||||
|
set write {} |
||||||
|
set size [string length $read] |
||||||
|
set max $size |
||||||
|
|
||||||
|
# at == 0 |
||||||
|
if {$n <= $max} { |
||||||
|
# The request is less than what we have in the updated |
||||||
|
# read buffer, we take it, and move the read pointer |
||||||
|
# forward. |
||||||
|
|
||||||
|
append result [string range $read 0 $last] |
||||||
|
set at $n |
||||||
|
incr $size -$n |
||||||
|
} else { |
||||||
|
# We need the whole remaining read buffer, and |
||||||
|
# more. As we took the data from write already we have |
||||||
|
# nothing left, and update accordingly. |
||||||
|
|
||||||
|
append result $read |
||||||
|
|
||||||
|
set at 0 |
||||||
|
set read {} |
||||||
|
set size 0 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
my Readable |
||||||
|
|
||||||
|
if {$result eq {}} { |
||||||
|
return -code error EAGAIN |
||||||
|
} |
||||||
|
|
||||||
|
return $result |
||||||
|
} |
||||||
|
|
||||||
|
method write {c bytes} { |
||||||
|
append write $bytes |
||||||
|
set n [string length $bytes] |
||||||
|
incr size $n |
||||||
|
my Readable |
||||||
|
return $n |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable at read write size |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {} { |
||||||
|
set at 0 |
||||||
|
set read {} |
||||||
|
set write {} |
||||||
|
set size 0 |
||||||
|
next |
||||||
|
} |
||||||
|
|
||||||
|
method Readable {} { |
||||||
|
if {$size} { |
||||||
|
my allow read |
||||||
|
} else { |
||||||
|
my disallow read |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::fifo 1.1 |
||||||
|
return |
@ -0,0 +1,113 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::fifo2 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes This fifo2 command does not have to |
||||||
|
# Meta as::notes deal with the pesky details of |
||||||
|
# Meta as::notes threading for cross-thread |
||||||
|
# Meta as::notes communication. That is hidden in the |
||||||
|
# Meta as::notes implementation of reflected |
||||||
|
# Meta as::notes channels. It is less optimal as the |
||||||
|
# Meta as::notes command provided by Memchan as this |
||||||
|
# Meta as::notes fifo2 may involve three threads when |
||||||
|
# Meta as::notes sending data around: The threads the |
||||||
|
# Meta as::notes two endpoints are in, and the thread |
||||||
|
# Meta as::notes holding this code. Memchan's C |
||||||
|
# Meta as::notes implementation does not need this last |
||||||
|
# Meta as::notes intermediary thread. |
||||||
|
# Meta description Re-implementation of Memchan's fifo2 |
||||||
|
# Meta description channel. Based on Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new |
||||||
|
# Meta description channels. No arguments. Result are the |
||||||
|
# Meta description handles of the two new channels. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::halfpipe |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::halfpipe |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::fifo2 {} { |
||||||
|
|
||||||
|
set coordinator [fifo2::implementation new] |
||||||
|
|
||||||
|
lassign [halfpipe \ |
||||||
|
-write-command [list $coordinator froma] \ |
||||||
|
-close-command [list $coordinator closeda]] \ |
||||||
|
a ha |
||||||
|
|
||||||
|
lassign [halfpipe \ |
||||||
|
-write-command [list $coordinator fromb] \ |
||||||
|
-close-command [list $coordinator closedb]] \ |
||||||
|
b hb |
||||||
|
|
||||||
|
$coordinator connect $a $ha $b $hb |
||||||
|
|
||||||
|
return [list $a $b] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::fifo2::implementation { |
||||||
|
method connect {thea theha theb thehb} { |
||||||
|
set a $thea |
||||||
|
set b $theb |
||||||
|
set ha $theha |
||||||
|
set hb $thehb |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method closeda {c} { |
||||||
|
set a {} |
||||||
|
if {$b ne {}} { |
||||||
|
close $b |
||||||
|
set b {} |
||||||
|
} else { |
||||||
|
my destroy |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method closedb {c} { |
||||||
|
set b {} |
||||||
|
if {$a ne {}} { |
||||||
|
close $a |
||||||
|
set a {} |
||||||
|
} else { |
||||||
|
my destroy |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method froma {c bytes} { |
||||||
|
$hb put $bytes |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method fromb {c bytes} { |
||||||
|
$ha put $bytes |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable a b ha hb |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::fifo2 1.1 |
||||||
|
return |
@ -0,0 +1,82 @@ |
|||||||
|
# ------------------------------------------------------------------------- |
||||||
|
# fifo2.test -*- tcl -*- |
||||||
|
# (C) 2019 Andreas Kupries. BSD licensed. |
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
source [file join \ |
||||||
|
[file dirname [file dirname [file join [pwd] [info script]]]] \ |
||||||
|
devtools testutilities.tcl] |
||||||
|
|
||||||
|
testsNeedTcl 8.5 |
||||||
|
testsNeedTcltest 2.0 |
||||||
|
testsNeed TclOO 1 |
||||||
|
|
||||||
|
support { |
||||||
|
use virtchannel_core/core.tcl tcl::chan::core |
||||||
|
use virtchannel_core/events.tcl tcl::chan::events |
||||||
|
} |
||||||
|
testing { |
||||||
|
useLocal halfpipe.tcl tcl::chan::halfpipe |
||||||
|
useLocal fifo2.tcl tcl::chan::fifo2 |
||||||
|
} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-fifo2-1.1 {constructor wrong\#args} -body { |
||||||
|
tcl::chan::fifo2 X |
||||||
|
} -returnCodes error \ |
||||||
|
-result {wrong # args: should be "tcl::chan::fifo2"} |
||||||
|
|
||||||
|
test tcl-chan-fifo2-1.2 {destructor kills both sides and coordinator} -setup { |
||||||
|
lassign [tcl::chan::fifo2] a b |
||||||
|
} -match glob -body { |
||||||
|
lappend r [lsort -dict [file channels]] |
||||||
|
lappend r [info class instances ::tcl::chan::fifo2::implementation] |
||||||
|
close $a |
||||||
|
lappend r [lsort -dict [file channels]] |
||||||
|
lappend r [info class instances ::tcl::chan::fifo2::implementation] |
||||||
|
} -cleanup { |
||||||
|
unset a b r |
||||||
|
} -result {{rc4 rc5 stderr stdin stdout} ::oo::Obj* {stderr stdin stdout} {}} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-fifo2-2.0 {tell, initial, empty} -setup { |
||||||
|
lassign [tcl::chan::fifo2] a b |
||||||
|
} -body { |
||||||
|
list [tell $a] [tell $b] |
||||||
|
} -cleanup { |
||||||
|
close $a |
||||||
|
unset a b |
||||||
|
} -result {-1 -1} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-fifo2-tkt-3f48fd6ea2 {fixed misindexing} -setup { |
||||||
|
lassign [tcl::chan::fifo2] a b |
||||||
|
chan configure $a -buffersize 1 |
||||||
|
chan configure $b -buffering none |
||||||
|
chan puts -nonewline $b foobar ;# push 6 chars |
||||||
|
chan read $a 2 ;# read 2 |
||||||
|
chan read $a 4 ;# read 4, fifo has nothing left |
||||||
|
chan puts -nonewline $b baz ;# push 3 more |
||||||
|
} -body { |
||||||
|
chan read $a 1 ;# read 1, the `b` |
||||||
|
} -cleanup { |
||||||
|
close $a |
||||||
|
unset a b |
||||||
|
} -result b |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
# Explicit cleanup of loaded (support) classes. |
||||||
|
rename tcl::chan::events {} |
||||||
|
rename tcl::chan::core {} |
||||||
|
rename tcl::chan::halfpipe {} |
||||||
|
rename tcl::chan::fifo2 {} |
||||||
|
testsuiteCleanup |
||||||
|
return |
||||||
|
|
||||||
|
# Local Variables: |
||||||
|
# mode: tcl |
||||||
|
# indent-tabs-mode: nil |
||||||
|
# End: |
@ -0,0 +1,81 @@ |
|||||||
|
[vset VERSION 1.0.2] |
||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::halfpipe n [vset VERSION]] |
||||||
|
[keywords callbacks] |
||||||
|
[keywords fifo] |
||||||
|
[keywords {in-memory channel}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009, 2019 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {In-memory channel, half of a fifo2}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::halfpipe [opt [vset VERSION]]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::halfpipe] package provides a command creating |
||||||
|
one half of a [package tcl::chan::fifo2] pair. Writing into such a |
||||||
|
channel invokes a set of callbacks which then handle the data. This is |
||||||
|
similar to a channel handler, except having a much simpler API. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::halfpipe] [opt "[option -option] [arg value]..."]] |
||||||
|
|
||||||
|
This command creates a halfpipe channel and configures it with the |
||||||
|
callbacks to run when the channel is closed, data was written to it, |
||||||
|
or ran empty. See the section [sectref Options] for the list of |
||||||
|
options and associated semantics. |
||||||
|
|
||||||
|
The result of the command is a list containing two elements, the |
||||||
|
handle of the new channel, and the object command of the channel |
||||||
|
handler, in this order. |
||||||
|
|
||||||
|
The latter is supplied to the caller to provide her with access to the |
||||||
|
[method put] method for adding data to the channel. |
||||||
|
|
||||||
|
[para] Two halfpipes with a bit of glue logic in the callbacks make |
||||||
|
for one [package tcl::chan::fifo2]. |
||||||
|
|
||||||
|
[call [arg objectCmd] [method put] [arg bytes]] |
||||||
|
|
||||||
|
This method of the channel handler object puts the data [arg bytes] |
||||||
|
into the channel so that it can be read from it. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[section Options] |
||||||
|
|
||||||
|
[list_begin options] |
||||||
|
[opt_def -close-command cmdprefix] |
||||||
|
|
||||||
|
This callback is invoked when the channel is closed. |
||||||
|
A single argument is supplied, the handle of the channel being closed. |
||||||
|
The result of the callback is ignored. |
||||||
|
|
||||||
|
[opt_def -write-command cmdprefix] |
||||||
|
|
||||||
|
This callback is invoked when data is written to the channel. |
||||||
|
Two arguments are supplied, the handle of the channel written to, and the data written. |
||||||
|
The result of the callback is ignored. |
||||||
|
|
||||||
|
[opt_def -empty-command cmdprefix] |
||||||
|
|
||||||
|
This callback is invoked when the channel has run out of data to read. |
||||||
|
A single argument is supplied, the handle of the channel. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,194 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009, 2019 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::halfpipe 1.0.3 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009,2019 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of one half of a pipe |
||||||
|
# Meta description channel. Based on Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new |
||||||
|
# Meta description channels. Option arguments. Result is the |
||||||
|
# Meta description handle of the new channel, and the object |
||||||
|
# Meta description command of the handler object. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::halfpipe {args} { |
||||||
|
set handler [halfpipe::implementation new {*}$args] |
||||||
|
return [list [::chan create {read write} $handler] $handler] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::halfpipe::implementation { |
||||||
|
superclass ::tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow write |
||||||
|
set eof 0 |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
method finalize {c} { |
||||||
|
my Call -close-command $c |
||||||
|
next $c |
||||||
|
} |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
set max [string length $read] |
||||||
|
set last [expr {$at + $n - 1}] |
||||||
|
set result {} |
||||||
|
|
||||||
|
# last+1 <= max |
||||||
|
# <=> at+n <= max |
||||||
|
# <=> n <= max-at |
||||||
|
|
||||||
|
if {$n <= ($max - $at)} { |
||||||
|
# There is enough data in the buffer to fill the request, so take |
||||||
|
# it from there and move the read pointer forward. |
||||||
|
|
||||||
|
append result [string range $read $at $last] |
||||||
|
incr at $n |
||||||
|
incr $size -$n |
||||||
|
} else { |
||||||
|
# We need the whole remaining read buffer, and more. For |
||||||
|
# the latter we make the write buffer the new read buffer, |
||||||
|
# and then read from it again. |
||||||
|
|
||||||
|
append result [string range $read $at end] |
||||||
|
incr n -[string length $result] |
||||||
|
|
||||||
|
set at 0 |
||||||
|
set last [expr {$n - 1}] |
||||||
|
set read $write |
||||||
|
set write {} |
||||||
|
set size [string length $read] |
||||||
|
set max $size |
||||||
|
|
||||||
|
# at == 0 simplifies expressions |
||||||
|
if {$n <= $max} { |
||||||
|
# The request is less than what we have in the new |
||||||
|
# read buffer, we take it, and move the read pointer |
||||||
|
# forward. |
||||||
|
|
||||||
|
append result [string range $read 0 $last] |
||||||
|
set at $n |
||||||
|
incr $size -$n |
||||||
|
} else { |
||||||
|
# We need the whole remaining read buffer, and |
||||||
|
# more. As we took the data from write already we have |
||||||
|
# nothing left, and update accordingly. |
||||||
|
|
||||||
|
append result $read |
||||||
|
|
||||||
|
set at 0 |
||||||
|
set read {} |
||||||
|
set size 0 |
||||||
|
} |
||||||
|
} |
||||||
|
my Readable |
||||||
|
if {$result eq {} && !$eof} { |
||||||
|
return -code error EAGAIN |
||||||
|
} |
||||||
|
return $result |
||||||
|
} |
||||||
|
|
||||||
|
method write {c bytes} { |
||||||
|
my Call -write-command $c $bytes |
||||||
|
return [string length $bytes] |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method put bytes { |
||||||
|
append write $bytes |
||||||
|
set n [string length $bytes] |
||||||
|
if {$n == 0} { |
||||||
|
my variable eof |
||||||
|
set eof 1 |
||||||
|
} else { |
||||||
|
incr size $n |
||||||
|
} |
||||||
|
my Readable |
||||||
|
return $n |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable at eof read write size options |
||||||
|
# at : first location in read buffer not yet read |
||||||
|
# eof : indicates whether the end of the data has been reached |
||||||
|
# read : read buffer |
||||||
|
# write : buffer for received data, i.e. |
||||||
|
# written into the halfpipe from |
||||||
|
# the other side. |
||||||
|
# size : combined length of receive and read buffers |
||||||
|
# == amount of stored data |
||||||
|
# options : configuration array |
||||||
|
|
||||||
|
# The halpipe uses a pointer (`at`) into the data buffer to |
||||||
|
# extract the characters read by the user, while not shifting the |
||||||
|
# data down in memory. Doing such a shift would cause a large |
||||||
|
# performance hit (O(n**2) operation vs O(n)). This however comes |
||||||
|
# with the danger of the buffer growing out of bounds as ever more |
||||||
|
# data is appended by the receiver while the reader is not |
||||||
|
# catching up, preventing a release. The solution to this in turn |
||||||
|
# is to split the buffer into two. An append-only receive buffer |
||||||
|
# (`write`) for incoming data, and a `read` buffer with the |
||||||
|
# pointer. When the current read buffer is entirely consumed the |
||||||
|
# current receive buffer becomes the new read buffer and a new |
||||||
|
# empty receive buffer is started. |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {args} { |
||||||
|
array set options { |
||||||
|
-write-command {} |
||||||
|
-empty-command {} |
||||||
|
-close-command {} |
||||||
|
} |
||||||
|
# todo: validity checking of options (legal names, legal |
||||||
|
# values, etc.) |
||||||
|
array set options $args |
||||||
|
set at 0 |
||||||
|
set read {} |
||||||
|
set write {} |
||||||
|
set size 0 |
||||||
|
next |
||||||
|
} |
||||||
|
|
||||||
|
method Readable {} { |
||||||
|
if {$size || $eof} { |
||||||
|
my allow read |
||||||
|
} else { |
||||||
|
my variable channel |
||||||
|
my disallow read |
||||||
|
my Call -empty-command $channel |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method Call {o args} { |
||||||
|
if {![llength $options($o)]} return |
||||||
|
uplevel \#0 [list {*}$options($o) {*}$args] |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::halfpipe 1.0.3 |
||||||
|
return |
@ -0,0 +1,169 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# Variable string channel (in-memory r/w file, internal variable). |
||||||
|
# Seekable beyond the end of the data, implies appending of 0x00 |
||||||
|
# bytes. |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::memchan 1.0.5 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Re-implementation of Memchan's memchan |
||||||
|
# Meta description channel. Based on Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new |
||||||
|
# Meta description channels. No arguments. Result is the |
||||||
|
# Meta description handle of the new channel. Essentially |
||||||
|
# Meta description an in-memory read/write random-access |
||||||
|
# Meta description file. Similar to -> tcl::chan::variable, |
||||||
|
# Meta description except the content variable is internal, |
||||||
|
# Meta description part of the channel. Further similar to |
||||||
|
# Meta description -> tcl::chan::string, except that the |
||||||
|
# Meta description content is here writable, and |
||||||
|
# Meta description extendable. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::memchan {} { |
||||||
|
return [::chan create {read write} [memchan::implementation new]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::memchan::implementation { |
||||||
|
superclass ::tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
constructor {} { |
||||||
|
set content {} |
||||||
|
set at 0 |
||||||
|
next |
||||||
|
} |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow write |
||||||
|
my Events |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
variable content at |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
# First determine the location of the last byte to read, |
||||||
|
# relative to the current location, and limited by the maximum |
||||||
|
# location we are allowed to access per the size of the |
||||||
|
# content. |
||||||
|
|
||||||
|
set last [expr {min($at + $n,[string length $content])-1}] |
||||||
|
|
||||||
|
# Then extract the relevant range from the content, move the |
||||||
|
# seek location behind it, and return the extracted range. Not |
||||||
|
# to forget, switch readable events based on the seek |
||||||
|
# location. |
||||||
|
|
||||||
|
set res [string range $content $at $last] |
||||||
|
set at $last |
||||||
|
incr at |
||||||
|
|
||||||
|
my Events |
||||||
|
return $res |
||||||
|
} |
||||||
|
|
||||||
|
method write {c newbytes} { |
||||||
|
# Return immediately if there is nothing is to write. |
||||||
|
set n [string length $newbytes] |
||||||
|
if {$n == 0} { |
||||||
|
return $n |
||||||
|
} |
||||||
|
|
||||||
|
# Determine where and how to write. There are three possible cases. |
||||||
|
# (1) Append at/after the end. |
||||||
|
# (2) Starting in the middle, but extending beyond the end. |
||||||
|
# (3) Replace in the middle. |
||||||
|
|
||||||
|
set max [string length $content] |
||||||
|
if {$at >= $max} { |
||||||
|
# Ad 1. |
||||||
|
append content $newbytes |
||||||
|
set at [string length $content] |
||||||
|
} else { |
||||||
|
set last [expr {$at + $n - 1}] |
||||||
|
if {$last >= $max} { |
||||||
|
# Ad 2. |
||||||
|
set content [string replace $content $at end $newbytes] |
||||||
|
set at [string length $content] |
||||||
|
} else { |
||||||
|
# Ad 3. |
||||||
|
set content [string replace $content $at $last $newbytes] |
||||||
|
set at $last |
||||||
|
incr at |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
my Events |
||||||
|
return $n |
||||||
|
} |
||||||
|
|
||||||
|
method seek {c offset base} { |
||||||
|
# offset == 0 && base == current |
||||||
|
# <=> Seek nothing relative to current |
||||||
|
# <=> Report current location. |
||||||
|
|
||||||
|
if {!$offset && ($base eq "current")} { |
||||||
|
return $at |
||||||
|
} |
||||||
|
|
||||||
|
# Compute the new location per the arguments. |
||||||
|
|
||||||
|
set max [string length $content] |
||||||
|
switch -exact -- $base { |
||||||
|
start { set newloc $offset} |
||||||
|
current { set newloc [expr {$at + $offset }] } |
||||||
|
end { set newloc [expr {$max + $offset }] } |
||||||
|
} |
||||||
|
|
||||||
|
# Check if the new location is beyond the range given by the |
||||||
|
# content. |
||||||
|
|
||||||
|
if {$newloc < 0} { |
||||||
|
return -code error "Cannot seek before the start of the channel" |
||||||
|
} elseif {$newloc > $max} { |
||||||
|
# We can seek beyond the end of the current contents, add |
||||||
|
# a block of zeros. |
||||||
|
#puts XXX.PAD.[expr {$newloc - $max}] |
||||||
|
append content [binary format @[expr {$newloc - $max}]] |
||||||
|
} |
||||||
|
|
||||||
|
# Commit to new location, switch readable events, and report. |
||||||
|
set at $newloc |
||||||
|
|
||||||
|
my Events |
||||||
|
return $at |
||||||
|
} |
||||||
|
|
||||||
|
method Events {} { |
||||||
|
# Always readable -- Even if the seek location is at the end |
||||||
|
# (or beyond). In that case the readable events are fired |
||||||
|
# endlessly until the eof indicated by the seek location is |
||||||
|
# properly processed by the event handler. Like for regular |
||||||
|
# files -- Ticket [864a0c83e3]. |
||||||
|
my allow read |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::memchan 1.0.5 |
||||||
|
return |
@ -0,0 +1,92 @@ |
|||||||
|
# ------------------------------------------------------------------------- |
||||||
|
# memchan.test -*- tcl -*- |
||||||
|
# (C) 2017 Andreas Kupries. BSD licensed. |
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
source [file join \ |
||||||
|
[file dirname [file dirname [file join [pwd] [info script]]]] \ |
||||||
|
devtools testutilities.tcl] |
||||||
|
|
||||||
|
testsNeedTcl 8.5 |
||||||
|
testsNeedTcltest 2.0 |
||||||
|
testsNeed TclOO 1 |
||||||
|
|
||||||
|
support { |
||||||
|
use virtchannel_core/core.tcl tcl::chan::core |
||||||
|
use virtchannel_core/events.tcl tcl::chan::events |
||||||
|
} |
||||||
|
testing { |
||||||
|
useLocal memchan.tcl tcl::chan::memchan |
||||||
|
} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-memchan-1.0 {constructor wrong\#args} -body { |
||||||
|
tcl::chan::memchan X |
||||||
|
} -returnCodes error \ |
||||||
|
-result {wrong # args: should be "tcl::chan::memchan"} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-memchan-2.0 {tell, initial, empty} -setup { |
||||||
|
set c [tcl::chan::memchan] |
||||||
|
} -body { |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
test tcl-chan-memchan-2.1 {seek from start, expand, tell} -setup { |
||||||
|
set c [tcl::chan::memchan] |
||||||
|
} -body { |
||||||
|
seek $c 10 |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 10 |
||||||
|
|
||||||
|
test tcl-chan-memchan-2.2 {seek from end, eof, empty, tell} -setup { |
||||||
|
set c [tcl::chan::memchan] |
||||||
|
} -body { |
||||||
|
seek $c 0 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
test tcl-chan-memchan-2.3 {seek from end, eof, non-empty, tell} -setup { |
||||||
|
set c [tcl::chan::memchan] |
||||||
|
puts $c Hello |
||||||
|
} -body { |
||||||
|
seek $c 0 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 6 |
||||||
|
|
||||||
|
test tcl-chan-memchan-2.4 {seek from end, non-eof, non-empty, tell} -setup { |
||||||
|
set c [tcl::chan::memchan] |
||||||
|
puts $c Hello |
||||||
|
} -body { |
||||||
|
seek $c -6 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
# Explicit cleanup of loaded support classes. |
||||||
|
rename tcl::chan::events {} |
||||||
|
rename tcl::chan::core {} |
||||||
|
testsuiteCleanup |
||||||
|
return |
||||||
|
|
||||||
|
# Local Variables: |
||||||
|
# mode: tcl |
||||||
|
# indent-tabs-mode: nil |
||||||
|
# End: |
@ -0,0 +1,54 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::null 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Re-implementation of Memchan's null |
||||||
|
# Meta description channel. Based on Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new |
||||||
|
# Meta description channels. No arguments. Result is the |
||||||
|
# Meta description handle of the new channel. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::null {} { |
||||||
|
return [::chan create {write} [null::implementation new]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::null::implementation { |
||||||
|
superclass ::tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow write |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
# Ignore the data in most particulars. We do count it so that we |
||||||
|
# can tell the caller that everything was written. Null device. |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
return [string length $data] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::null 1.1 |
||||||
|
return |
@ -0,0 +1,44 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::nullzero n 1.1] |
||||||
|
[keywords /dev/null] |
||||||
|
[keywords /dev/zero] |
||||||
|
[keywords null] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[keywords zero] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Null/Zero channel combination}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::nullzero [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::nullzero] package provides a command creating channels, |
||||||
|
which are a combination of null and zero devices. They immediately forget |
||||||
|
whatever is written to them, and on reading return an infinite stream of null |
||||||
|
characters. |
||||||
|
|
||||||
|
[para] Packages related to this are [package tcl::chan::null] and |
||||||
|
[package tcl::chan::zero]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel handler |
||||||
|
is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::nullzero]] |
||||||
|
|
||||||
|
This command creates a new nullzero channel and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,62 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::nullzero 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of a channel combining |
||||||
|
# Meta description Memchan's null and zero channels in a |
||||||
|
# Meta description single device. Based on Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new |
||||||
|
# Meta description channels. No arguments. Result is the |
||||||
|
# Meta description handle of the new channel. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::nullzero {} { |
||||||
|
return [::chan create {read write} [nullzero::implementation new]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::nullzero::implementation { |
||||||
|
superclass ::tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow read write |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
# Ignore the data in most particulars. We do count it so that we |
||||||
|
# can tell the caller that everything was written. Null device. |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
return [string length $data] |
||||||
|
} |
||||||
|
|
||||||
|
# Generate and return a block of N null bytes, as requested. Zero |
||||||
|
# device. |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
return [binary format @$n] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::nullzero 1.1 |
||||||
|
return |
@ -0,0 +1,17 @@ |
|||||||
|
if {![package vsatisfies [package provide Tcl] 8.5 9]} {return} |
||||||
|
|
||||||
|
package ifneeded tcl::chan::cat 1.0.4 [list source [file join $dir cat.tcl]] |
||||||
|
package ifneeded tcl::chan::facade 1.0.2 [list source [file join $dir facade.tcl]] |
||||||
|
package ifneeded tcl::chan::fifo 1.1 [list source [file join $dir fifo.tcl]] |
||||||
|
package ifneeded tcl::chan::fifo2 1.1 [list source [file join $dir fifo2.tcl]] |
||||||
|
package ifneeded tcl::chan::halfpipe 1.0.3 [list source [file join $dir halfpipe.tcl]] |
||||||
|
package ifneeded tcl::chan::memchan 1.0.5 [list source [file join $dir memchan.tcl]] |
||||||
|
package ifneeded tcl::chan::null 1.1 [list source [file join $dir null.tcl]] |
||||||
|
package ifneeded tcl::chan::nullzero 1.1 [list source [file join $dir nullzero.tcl]] |
||||||
|
package ifneeded tcl::chan::random 1.1 [list source [file join $dir random.tcl]] |
||||||
|
package ifneeded tcl::chan::std 1.0.2 [list source [file join $dir std.tcl]] |
||||||
|
package ifneeded tcl::chan::string 1.0.4 [list source [file join $dir string.tcl]] |
||||||
|
package ifneeded tcl::chan::textwindow 1.1 [list source [file join $dir textwindow.tcl]] |
||||||
|
package ifneeded tcl::chan::variable 1.0.5 [list source [file join $dir variable.tcl]] |
||||||
|
package ifneeded tcl::chan::zero 1.1 [list source [file join $dir zero.tcl]] |
||||||
|
package ifneeded tcl::randomseed 1.1 [list source [file join $dir randseed.tcl]] |
@ -0,0 +1,80 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::random 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of a channel similar to |
||||||
|
# Meta description Memchan's random channel. Based on Tcl |
||||||
|
# Meta description 8.5's channel reflection support. Exports |
||||||
|
# Meta description a single command for the creation of new |
||||||
|
# Meta description channels. One argument, a list of |
||||||
|
# Meta description numbers to initialize the feedback |
||||||
|
# Meta description register of the internal random number |
||||||
|
# Meta description generator. Result is the handle of the |
||||||
|
# Meta description new channel. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require tcl::chan::events |
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::random {seed} { |
||||||
|
return [::chan create {read} [random::implementation new $seed]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::random::implementation { |
||||||
|
superclass tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
constructor {theseed} { |
||||||
|
my variable seed next |
||||||
|
set seed $theseed |
||||||
|
set next [expr "([join $seed +]) & 0xff"] |
||||||
|
next |
||||||
|
} |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow read |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
# Generate and return a block of N randomly selected bytes, as |
||||||
|
# requested. Random device. |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
set buffer {} |
||||||
|
while {$n} { |
||||||
|
append buffer [binary format c [my Next]] |
||||||
|
incr n -1 |
||||||
|
} |
||||||
|
return $buffer |
||||||
|
} |
||||||
|
|
||||||
|
variable seed |
||||||
|
variable next |
||||||
|
|
||||||
|
method Next {} { |
||||||
|
my variable seed next |
||||||
|
set result $next |
||||||
|
set next [expr {(2*$next - [lindex $seed 0]) & 0xff}] |
||||||
|
set seed [linsert [lrange $seed 1 end] end $result] |
||||||
|
return $result |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::random 1.1 |
||||||
|
return |
@ -0,0 +1,43 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::randomseed n 1.1] |
||||||
|
[keywords /dev/random] |
||||||
|
[keywords merge] |
||||||
|
[keywords random] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords seed] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Utilities for random channels}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::randomseed [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::randomseed] package provides a a few utility commands |
||||||
|
to help with the seeding of [package tcl::chan::random] channels. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::randomseed]] |
||||||
|
|
||||||
|
This command creates returns a list of seed integers suitable as seed |
||||||
|
argument for random channels. The numbers are derived from the process |
||||||
|
id, current time, and Tcl random number generator. |
||||||
|
|
||||||
|
[call [cmd ::tcl::combine] [arg seed1] [arg seed2]] |
||||||
|
|
||||||
|
This command takes to seed lists and combines them into a single list |
||||||
|
by XORing them elementwise, modulo 256. If the lists are not of equial |
||||||
|
length the shorter of the two is padded with 0s before merging. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,58 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::randomseed 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Generate and combine seed lists for the |
||||||
|
# Meta description random number generator inside of the |
||||||
|
# Meta description tcl::chan::random channel. Sources of |
||||||
|
# Meta description randomness are process id, time in two |
||||||
|
# Meta description granularities, and Tcl's random number |
||||||
|
# Meta description generator. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl {} |
||||||
|
|
||||||
|
proc ::tcl::randomseed {} { |
||||||
|
set result {} |
||||||
|
foreach v [list \ |
||||||
|
[pid] \ |
||||||
|
[clock seconds] \ |
||||||
|
[expr {int(256*rand())}] \ |
||||||
|
[clock clicks -milliseconds]] \ |
||||||
|
{ |
||||||
|
lappend result [expr {$v % 256}] |
||||||
|
} |
||||||
|
return $result |
||||||
|
} |
||||||
|
|
||||||
|
proc ::tcl::combine {a b} { |
||||||
|
while {[llength $a] < [llength $b]} { |
||||||
|
lappend a 0 |
||||||
|
} |
||||||
|
while {[llength $b] < [llength $a]} { |
||||||
|
lappend b 0 |
||||||
|
} |
||||||
|
|
||||||
|
set result {} |
||||||
|
foreach x $a y $b { |
||||||
|
lappend result [expr {($x ^ $y) % 256}] |
||||||
|
} |
||||||
|
return $result |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::randomseed 1.1 |
||||||
|
return |
@ -0,0 +1,43 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::std n 1.1] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {standard io}] |
||||||
|
[keywords stdin] |
||||||
|
[keywords stdout] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2011 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Standard I/O, unification of stdin and stdout}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::core [opt 1.1]] |
||||||
|
[require tcl::chan::std [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::std] package provides a command creating |
||||||
|
a standard channel which unifies stdin and stdout into a single |
||||||
|
read- and writable channel. The result is not seek-able, like |
||||||
|
the original standard channels. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::core] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::std]] |
||||||
|
|
||||||
|
This command creates the std channel and returns its handle. |
||||||
|
|
||||||
|
[para] The channel is created only once, on the first call, and all |
||||||
|
future calls simply return this handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,97 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2011 Andreas Kupries |
||||||
|
|
||||||
|
# Facade wrapping the separate channels for stdin and stdout into a |
||||||
|
# single read/write channel for all regular standard i/o. Not |
||||||
|
# seekable. Fileevent handling is propagated to the regular channels |
||||||
|
# the facade wrapped about. Only one instance of the class is |
||||||
|
# ever created. |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::std 1.0.2 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2011 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Facade wrapping the separate channels for stdin |
||||||
|
# Meta description and stdout into a single read/write channel for |
||||||
|
# Meta description all regular standard i/o. Not seekable. Only one |
||||||
|
# Meta description instance of the class is ever created. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::core |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::std {} { |
||||||
|
::variable std |
||||||
|
if {$std eq {}} { |
||||||
|
set std [::chan create {read write} [std::implementation new]] |
||||||
|
} |
||||||
|
return $std |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::std::implementation { |
||||||
|
superclass ::tcl::chan::core ; # -> initialize, finalize. |
||||||
|
|
||||||
|
# We are not using the standard event handling class, because here |
||||||
|
# it will not be timer-driven. We propagate anything related to |
||||||
|
# events to stdin and stdout instead and let them handle things. |
||||||
|
|
||||||
|
constructor {} { |
||||||
|
# Disable encoding and translation processing in the wrapped channels. |
||||||
|
# This will happen in our generic layer instead. |
||||||
|
fconfigure stdin -translation binary |
||||||
|
fconfigure stdout -translation binary |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method watch {c requestmask} { |
||||||
|
|
||||||
|
if {"read" in $requestmask} { |
||||||
|
fileevent readable stdin [list chan postevent $c read] |
||||||
|
} else { |
||||||
|
fileevent readable stdin {} |
||||||
|
} |
||||||
|
|
||||||
|
if {"write" in $requestmask} { |
||||||
|
fileevent readable stdin [list chan postevent $c write] |
||||||
|
} else { |
||||||
|
fileevent readable stdout {} |
||||||
|
} |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
# Read is redirected to stdin. |
||||||
|
return [::read stdin $n] |
||||||
|
} |
||||||
|
|
||||||
|
method write {c newbytes} { |
||||||
|
# Write is redirected to stdout. |
||||||
|
puts -nonewline stdout $newbytes |
||||||
|
flush stdout |
||||||
|
return [string length $newbytes] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan { |
||||||
|
::variable std {} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::std 1.0.2 |
||||||
|
return |
@ -0,0 +1,124 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::string 1.0.4 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of a channel representing |
||||||
|
# Meta description an in-memory read-only random-access |
||||||
|
# Meta description file. Based on using Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new channels. |
||||||
|
# Meta description One argument, the contents of the file. |
||||||
|
# Meta description Result is the handle of the new channel. |
||||||
|
# Meta description Similar to -> tcl::chan::memchan, except |
||||||
|
# Meta description that the content is read-only. Seekable |
||||||
|
# Meta description only within the bounds of the content. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::string {content} { |
||||||
|
return [::chan create {read} [string::implementation new $content]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::string::implementation { |
||||||
|
superclass ::tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
constructor {thecontent} { |
||||||
|
set content $thecontent |
||||||
|
set at 0 |
||||||
|
next |
||||||
|
} |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my Events |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
variable content at |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
|
||||||
|
# First determine the location of the last byte to read, |
||||||
|
# relative to the current location, and limited by the maximum |
||||||
|
# location we are allowed to access per the size of the |
||||||
|
# content. |
||||||
|
|
||||||
|
set last [expr {min($at + $n,[string length $content])-1}] |
||||||
|
|
||||||
|
# Then extract the relevant range from the content, move the |
||||||
|
# seek location behind it, and return the extracted range. Not |
||||||
|
# to forget, switch readable events based on the seek |
||||||
|
# location. |
||||||
|
|
||||||
|
set res [string range $content $at $last] |
||||||
|
set at $last |
||||||
|
incr at |
||||||
|
|
||||||
|
my Events |
||||||
|
return $res |
||||||
|
} |
||||||
|
|
||||||
|
method seek {c offset base} { |
||||||
|
# offset == 0 && base == current |
||||||
|
# <=> Seek nothing relative to current |
||||||
|
# <=> Report current location. |
||||||
|
|
||||||
|
if {!$offset && ($base eq "current")} { |
||||||
|
return $at |
||||||
|
} |
||||||
|
|
||||||
|
# Compute the new location per the arguments. |
||||||
|
|
||||||
|
set max [string length $content] |
||||||
|
switch -exact -- $base { |
||||||
|
start { set newloc $offset} |
||||||
|
current { set newloc [expr {$at + $offset }] } |
||||||
|
end { set newloc [expr {$max + $offset }] } |
||||||
|
} |
||||||
|
|
||||||
|
# Check if the new location is beyond the range given by the |
||||||
|
# content. |
||||||
|
|
||||||
|
if {$newloc < 0} { |
||||||
|
return -code error "Cannot seek before the start of the channel" |
||||||
|
} elseif {$newloc > $max} { |
||||||
|
return -code error "Cannot seek after the end of the channel" |
||||||
|
} |
||||||
|
|
||||||
|
# Commit to new location, switch readable events, and report. |
||||||
|
set at $newloc |
||||||
|
|
||||||
|
my Events |
||||||
|
return $at |
||||||
|
} |
||||||
|
|
||||||
|
method Events {} { |
||||||
|
# Always readable -- Even if the seek location is at the end |
||||||
|
# (or beyond). In that case the readable events are fired |
||||||
|
# endlessly until the eof indicated by the seek location is |
||||||
|
# properly processed by the event handler. Like for regular |
||||||
|
# files -- Ticket [864a0c83e3]. |
||||||
|
my allow read |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::string 1.0.4 |
||||||
|
return |
@ -0,0 +1,94 @@ |
|||||||
|
# ------------------------------------------------------------------------- |
||||||
|
# string.test -*- tcl -*- |
||||||
|
# (C) 2017 Andreas Kupries. BSD licensed. |
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
source [file join \ |
||||||
|
[file dirname [file dirname [file join [pwd] [info script]]]] \ |
||||||
|
devtools testutilities.tcl] |
||||||
|
|
||||||
|
testsNeedTcl 8.5 |
||||||
|
testsNeedTcltest 2.0 |
||||||
|
testsNeed TclOO 1 |
||||||
|
|
||||||
|
support { |
||||||
|
use virtchannel_core/core.tcl tcl::chan::core |
||||||
|
use virtchannel_core/events.tcl tcl::chan::events |
||||||
|
} |
||||||
|
testing { |
||||||
|
useLocal string.tcl tcl::chan::string |
||||||
|
} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-string-1.0 {constructor wrong\#args} -body { |
||||||
|
tcl::chan::string |
||||||
|
} -returnCodes error \ |
||||||
|
-result {wrong # args: should be "tcl::chan::string content"} |
||||||
|
|
||||||
|
test tcl-chan-string-1.1 {constructor wrong\#args} -body { |
||||||
|
tcl::chan::string C X |
||||||
|
} -returnCodes error \ |
||||||
|
-result {wrong # args: should be "tcl::chan::string content"} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-string-2.0 {tell, initial, empty} -setup { |
||||||
|
set c [tcl::chan::string ""] |
||||||
|
} -body { |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
test tcl-chan-string-2.1 {seek from start beyond eof is error} -setup { |
||||||
|
set c [tcl::chan::string ""] |
||||||
|
} -body { |
||||||
|
seek $c 10 |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -returnCodes error -result {Cannot seek after the end of the channel} |
||||||
|
|
||||||
|
test tcl-chan-string-2.2 {seek from end, eof, empty, tell} -setup { |
||||||
|
set c [tcl::chan::string ""] |
||||||
|
} -body { |
||||||
|
seek $c 0 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
test tcl-chan-string-2.3 {seek from end, eof, non-empty, tell} -setup { |
||||||
|
set c [tcl::chan::string Hello\n] |
||||||
|
} -body { |
||||||
|
seek $c 0 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 6 |
||||||
|
|
||||||
|
test tcl-chan-string-2.4 {seek from end, non-eof, non-empty, tell} -setup { |
||||||
|
set c [tcl::chan::string Hello\n] |
||||||
|
} -body { |
||||||
|
seek $c -6 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
# Explicit cleanup of loaded support classes. |
||||||
|
rename tcl::chan::events {} |
||||||
|
rename tcl::chan::core {} |
||||||
|
testsuiteCleanup |
||||||
|
return |
||||||
|
|
||||||
|
# Local Variables: |
||||||
|
# mode: tcl |
||||||
|
# indent-tabs-mode: nil |
||||||
|
# End: |
@ -0,0 +1,43 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::fifo n 1.1] |
||||||
|
[keywords fifo] |
||||||
|
[keywords {in-memory channel}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {In-memory fifo channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::fifo [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::fifo] package provides a command creating |
||||||
|
channels which live purely in memory. Access is fifo-like, i.e. things |
||||||
|
are read out of the channel in the order they were written to it. |
||||||
|
|
||||||
|
This is equivalent to the fifo channels provided by the package |
||||||
|
[package Memchan], except that this is written in pure Tcl, not C. On |
||||||
|
the other hand, [package Memchan] is usable with Tcl 8.4 and before, |
||||||
|
whereas this package requires Tcl 8.5 or higher, and [package TclOO]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::fifo]] |
||||||
|
|
||||||
|
This command creates a new fifo channel and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,50 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::fifo2 n 1.1] |
||||||
|
[keywords {connected fifos}] |
||||||
|
[keywords fifo] |
||||||
|
[keywords {in-memory channel}] |
||||||
|
[keywords {inter-thread communication}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {In-memory interconnected fifo channels}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::halfpipe [opt 1.1]] |
||||||
|
[require tcl::chan::fifo2 [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::fifo2] package provides a command creating |
||||||
|
pairs of channels which live purely in memory and are connected to |
||||||
|
each other in a fifo manner. What is written to one half of the pair |
||||||
|
can be read from the other half, in the same order. One particular |
||||||
|
application for this is communication between threads, with one half |
||||||
|
of the pair moved to the thread to talk to. |
||||||
|
|
||||||
|
This is equivalent to the fifo2 channels provided by the package |
||||||
|
[package Memchan], except that this is written in pure Tcl, not C. On |
||||||
|
the other hand, [package Memchan] is usable with Tcl 8.4 and before, |
||||||
|
whereas this package requires Tcl 8.5 or higher, and [package TclOO]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::fifo2]] |
||||||
|
|
||||||
|
This command creates a new connected pair of fifo channels and returns |
||||||
|
their handles, as a list containing two elements. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,45 @@ |
|||||||
|
[vset VERSION 1.0.5] |
||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::memchan n [vset VERSION]] |
||||||
|
[keywords {in-memory channel}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009-2017 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {In-memory channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::memchan [opt [vset VERSION]]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::memchan] package provides a command creating |
||||||
|
channels which live purely in memory. They provide random-access, |
||||||
|
i.e. are seekable. This is equivalent to the memchan channels provided by |
||||||
|
the package [package Memchan], except that this is written in pure Tcl, |
||||||
|
not C. On the other hand, [package Memchan] is usable with Tcl 8.4 and |
||||||
|
before, whereas this package requires Tcl 8.5 or higher, and |
||||||
|
[package TclOO]. |
||||||
|
|
||||||
|
[para] Packages related to this are [package tcl::chan::string] and |
||||||
|
[package tcl::chan::variable]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::memchan]] |
||||||
|
|
||||||
|
This command creates a new memchan channel and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,45 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::null n 1.1] |
||||||
|
[keywords /dev/null] |
||||||
|
[keywords null] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Null channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::null [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::null] package provides a command creating null |
||||||
|
channels, i.e. write-only channels which immediately forget whatever |
||||||
|
is written to them. This is equivalent to the null channels provided by |
||||||
|
the package [package Memchan], except that this is written in pure Tcl, |
||||||
|
not C. On the other hand, [package Memchan] is usable with Tcl 8.4 and |
||||||
|
before, whereas this package requires Tcl 8.5 or higher, and |
||||||
|
[package TclOO]. |
||||||
|
|
||||||
|
[para] Packages related to this are [package tcl::chan::zero] and |
||||||
|
[package tcl::chan::nullzero]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::null]] |
||||||
|
|
||||||
|
This command creates a new null channel and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,46 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::random n 1.1] |
||||||
|
[keywords /dev/random] |
||||||
|
[keywords random] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Random channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::random [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::random] package provides a command creating |
||||||
|
random channels, i.e. read-only channels which return an infinite |
||||||
|
stream of pseudo-random characters upon reading. This is similar to |
||||||
|
the random channels provided by the package [package Memchan], except |
||||||
|
that this is written in pure Tcl, not C, and uses a much simpler |
||||||
|
generator as well. On the other hand, [package Memchan] is usable with |
||||||
|
Tcl 8.4 and before, whereas this package requires Tcl 8.5 or higher, |
||||||
|
and TclOO. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::random] [arg seed]] |
||||||
|
|
||||||
|
This command creates a new random channel and returns its handle. |
||||||
|
|
||||||
|
The seed is a list of integer numbers used to initialize the |
||||||
|
internal feedback shift register of the generator. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,46 @@ |
|||||||
|
[vset VERSION 1.0.4] |
||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::string n [vset VERSION]] |
||||||
|
[keywords {in-memory channel}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Read-only in-memory channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::string [opt [vset VERSION]]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::string] package provides a command creating |
||||||
|
channels which live purely in memory. They provide random-access, |
||||||
|
i.e. are seekable. |
||||||
|
|
||||||
|
In contrast to the channels created by [package tcl::chan::memchan] |
||||||
|
they are read-only however, their content is provided at the time of |
||||||
|
construction and immutable afterward. |
||||||
|
|
||||||
|
[para] Packages related to this are [package tcl::chan::memchan] and |
||||||
|
[package tcl::chan::variable]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::string] [arg content]] |
||||||
|
|
||||||
|
This command creates a new string channel and returns its handle. The |
||||||
|
channel provides random read-only access to the [arg content] string. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,47 @@ |
|||||||
|
[vset VERSION 1.0.5] |
||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::variable n [vset VERSION]] |
||||||
|
[keywords {in-memory channel}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {In-memory channel using variable for storage}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::variable [opt [vset VERSION]]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::variable] package provides a command creating |
||||||
|
channels which live purely in memory. They provide random-access, |
||||||
|
i.e. are seekable. |
||||||
|
|
||||||
|
In contrast to the channels created by [package tcl::chan::memchan] |
||||||
|
the data is not hidden in the channel however, but stored in an |
||||||
|
associated variable, specified at the time of construction. |
||||||
|
|
||||||
|
[para] Packages related to this are [package tcl::chan::memchan] and |
||||||
|
[package tcl::chan::string]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::variable] [arg varname]] |
||||||
|
|
||||||
|
This command creates a new variable channel and returns its handle. |
||||||
|
The content of the channel is stored in the associated namespace |
||||||
|
variable [arg varname]. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,45 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::zero n 1.1] |
||||||
|
[keywords /dev/zero] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[keywords zero] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Zero channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::zero [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::zero] package provides a command creating zero |
||||||
|
channels, i.e. read-only channels which return an infinite stream of null |
||||||
|
characters upon reading. This is equivalent to the zero channels |
||||||
|
provided by the package [package Memchan], except that this is written |
||||||
|
in pure Tcl, not C. On the other hand, [package Memchan] is usable with |
||||||
|
Tcl 8.4 and before, whereas this package requires Tcl 8.5 or higher, |
||||||
|
and TclOO. |
||||||
|
|
||||||
|
[para] Packages related to this are [package tcl::chan::null] and |
||||||
|
[package tcl::chan::nullzero]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::zero]] |
||||||
|
|
||||||
|
This command creates a new zero channel and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,39 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::textwindow n 1.1] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {text widget}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords Tk] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Textwindow channel}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[require tcl::chan::textwindow [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::textwindow] package provides a command creating |
||||||
|
write-only channels connected to text widgets. Anything written to the |
||||||
|
channel is printed into the associated widget. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the channel |
||||||
|
handler is a sub-class of the [package tcl::chan::events] framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::textwindow] [arg widget]] |
||||||
|
|
||||||
|
This command creates a new textwindow channel and returns its handle. |
||||||
|
Data written to this channel will appear in the associated [arg widget]. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,74 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::textwindow 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::credit To Bryan Oakley for rotext, see |
||||||
|
# Meta as::credit http://wiki.tcl.tk/22036. His code was |
||||||
|
# Meta as::credit used here as template for the text |
||||||
|
# Meta as::credit widget portions of the channel. |
||||||
|
# Meta description Implementation of a text window |
||||||
|
# Meta description channel, using Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new |
||||||
|
# Meta description channels. No arguments. Result is the |
||||||
|
# Meta description handle of the new channel. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::textwindow {w} { |
||||||
|
set chan [::chan create {write} [textwindow::implementation new $w]] |
||||||
|
fconfigure $chan -encoding utf-8 -buffering none |
||||||
|
return $chan |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::textwindow::implementation { |
||||||
|
superclass ::tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
constructor {w} { |
||||||
|
set widget $w |
||||||
|
next |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable widget |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow write |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
# NOTE: How is encoding convertfrom dealing with a partial |
||||||
|
# utf-8 character at the end of the buffer ? Should be saved |
||||||
|
# up for the next buffer. No idea if we can. |
||||||
|
|
||||||
|
$widget insert end [encoding convertfrom utf-8 $data] |
||||||
|
$widget see end |
||||||
|
return [string length $data] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::textwindow 1.1 |
||||||
|
return |
@ -0,0 +1,181 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::variable 1.0.5 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of a channel representing |
||||||
|
# Meta description an in-memory read-write random-access |
||||||
|
# Meta description file. Based on Tcl 8.5's channel reflection |
||||||
|
# Meta description support. Exports a single command for the |
||||||
|
# Meta description creation of new channels. No arguments. |
||||||
|
# Meta description Result is the handle of the new channel. |
||||||
|
# Meta description Similar to -> tcl::chan::memchan, except |
||||||
|
# Meta description that the variable holding the content |
||||||
|
# Meta description exists outside of the channel itself, in |
||||||
|
# Meta description some namespace, and as such is not a part |
||||||
|
# Meta description of the channel. Seekable beyond the end |
||||||
|
# Meta description of the data, implies appending of 0x00 |
||||||
|
# Meta description bytes. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::variable {varname} { |
||||||
|
return [::chan create {read write} [variable::implementation new $varname]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::variable::implementation { |
||||||
|
superclass ::tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
constructor {thevarname} { |
||||||
|
set varname $thevarname |
||||||
|
set at 0 |
||||||
|
|
||||||
|
upvar #0 $varname content |
||||||
|
if {![info exists content]} { |
||||||
|
set content {} |
||||||
|
} |
||||||
|
next |
||||||
|
} |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow write |
||||||
|
my Events |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
variable varname at |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
# Bring connected variable for content into scope. |
||||||
|
|
||||||
|
upvar #0 $varname content |
||||||
|
|
||||||
|
# First determine the location of the last byte to read, |
||||||
|
# relative to the current location, and limited by the maximum |
||||||
|
# location we are allowed to access per the size of the |
||||||
|
# content. |
||||||
|
|
||||||
|
set last [expr {min($at + $n,[string length $content])-1}] |
||||||
|
|
||||||
|
# Then extract the relevant range from the content, move the |
||||||
|
# seek location behind it, and return the extracted range. Not |
||||||
|
# to forget, switch readable events based on the seek |
||||||
|
# location. |
||||||
|
|
||||||
|
set res [string range $content $at $last] |
||||||
|
set at $last |
||||||
|
incr at |
||||||
|
|
||||||
|
my Events |
||||||
|
return $res |
||||||
|
} |
||||||
|
|
||||||
|
method write {c newbytes} { |
||||||
|
# Bring connected variable for content into scope. |
||||||
|
|
||||||
|
upvar #0 $varname content |
||||||
|
|
||||||
|
# Return immediately if there is nothing is to write. |
||||||
|
set n [string length $newbytes] |
||||||
|
if {$n == 0} { |
||||||
|
return $n |
||||||
|
} |
||||||
|
|
||||||
|
# Determine where and how to write. There are three possible cases. |
||||||
|
# (1) Append at/after the end. |
||||||
|
# (2) Starting in the middle, but extending beyond the end. |
||||||
|
# (3) Replace in the middle. |
||||||
|
|
||||||
|
set max [string length $content] |
||||||
|
if {$at >= $max} { |
||||||
|
# Ad 1. |
||||||
|
append content $newbytes |
||||||
|
set at [string length $content] |
||||||
|
} else { |
||||||
|
set last [expr {$at + $n - 1}] |
||||||
|
if {$last >= $max} { |
||||||
|
# Ad 2. |
||||||
|
set content [string replace $content $at end $newbytes] |
||||||
|
set at [string length $content] |
||||||
|
} else { |
||||||
|
# Ad 3. |
||||||
|
set content [string replace $content $at $last $newbytes] |
||||||
|
set at $last |
||||||
|
incr at |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
my Events |
||||||
|
return $n |
||||||
|
} |
||||||
|
|
||||||
|
method seek {c offset base} { |
||||||
|
# offset == 0 && base == current |
||||||
|
# <=> Seek nothing relative to current |
||||||
|
# <=> Report current location. |
||||||
|
|
||||||
|
if {!$offset && ($base eq "current")} { |
||||||
|
return $at |
||||||
|
} |
||||||
|
|
||||||
|
# Bring connected variable for content into scope. |
||||||
|
|
||||||
|
upvar #0 $varname content |
||||||
|
|
||||||
|
# Compute the new location per the arguments. |
||||||
|
|
||||||
|
set max [string length $content] |
||||||
|
switch -exact -- $base { |
||||||
|
start { set newloc $offset} |
||||||
|
current { set newloc [expr {$at + $offset }] } |
||||||
|
end { set newloc [expr {$max + $offset }] } |
||||||
|
} |
||||||
|
|
||||||
|
# Check if the new location is beyond the range given by the |
||||||
|
# content. |
||||||
|
|
||||||
|
if {$newloc < 0} { |
||||||
|
return -code error "Cannot seek before the start of the channel" |
||||||
|
} elseif {$newloc > $max} { |
||||||
|
# We can seek beyond the end of the current contents, add |
||||||
|
# a block of zeros. |
||||||
|
append content [binary format @[expr {$newloc - $max}]] |
||||||
|
} |
||||||
|
|
||||||
|
# Commit to new location, switch readable events, and report. |
||||||
|
set at $newloc |
||||||
|
|
||||||
|
my Events |
||||||
|
return $at |
||||||
|
} |
||||||
|
|
||||||
|
method Events {} { |
||||||
|
# Always readable -- Even if the seek location is at the end |
||||||
|
# (or beyond). In that case the readable events are fired |
||||||
|
# endlessly until the eof indicated by the seek location is |
||||||
|
# properly processed by the event handler. Like for regular |
||||||
|
# files -- Ticket [864a0c83e3]. |
||||||
|
my allow read |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::variable 1.0.5 |
||||||
|
return |
@ -0,0 +1,102 @@ |
|||||||
|
# ------------------------------------------------------------------------- |
||||||
|
# variable.test -*- tcl -*- |
||||||
|
# (C) 2017 Andreas Kupries. BSD licensed. |
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
source [file join \ |
||||||
|
[file dirname [file dirname [file join [pwd] [info script]]]] \ |
||||||
|
devtools testutilities.tcl] |
||||||
|
|
||||||
|
testsNeedTcl 8.5 |
||||||
|
testsNeedTcltest 2.0 |
||||||
|
testsNeed TclOO 1 |
||||||
|
|
||||||
|
support { |
||||||
|
use virtchannel_core/core.tcl tcl::chan::core |
||||||
|
use virtchannel_core/events.tcl tcl::chan::events |
||||||
|
} |
||||||
|
testing { |
||||||
|
useLocal variable.tcl tcl::chan::variable |
||||||
|
} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-variable-1.0 {constructor wrong\#args} -body { |
||||||
|
tcl::chan::variable |
||||||
|
} -returnCodes error \ |
||||||
|
-result {wrong # args: should be "tcl::chan::variable varname"} |
||||||
|
|
||||||
|
test tcl-chan-variable-1.1 {constructor wrong\#args} -body { |
||||||
|
tcl::chan::variable V X |
||||||
|
} -returnCodes error \ |
||||||
|
-result {wrong # args: should be "tcl::chan::variable varname"} |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
|
||||||
|
test tcl-chan-variable-2.0 {tell, initial, empty} -setup { |
||||||
|
set content "" |
||||||
|
set c [tcl::chan::variable content] |
||||||
|
} -body { |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c content |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
test tcl-chan-variable-2.1 {seek from start, expand, tell} -setup { |
||||||
|
set content "" |
||||||
|
set c [tcl::chan::variable content] |
||||||
|
} -body { |
||||||
|
seek $c 10 |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c content |
||||||
|
} -result 10 |
||||||
|
|
||||||
|
test tcl-chan-variable-2.2 {seek from end, eof, empty, tell} -setup { |
||||||
|
set content "" |
||||||
|
set c [tcl::chan::variable content] |
||||||
|
} -body { |
||||||
|
seek $c 0 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c content |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
test tcl-chan-variable-2.3 {seek from end, eof, non-empty, tell} -setup { |
||||||
|
set content "" |
||||||
|
set c [tcl::chan::variable content] |
||||||
|
puts $c Hello |
||||||
|
} -body { |
||||||
|
seek $c 0 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c content |
||||||
|
} -result 6 |
||||||
|
|
||||||
|
test tcl-chan-variable-2.4 {seek from end, non-eof, non-empty, tell} -setup { |
||||||
|
set content "" |
||||||
|
set c [tcl::chan::variable content] |
||||||
|
puts $c Hello |
||||||
|
} -body { |
||||||
|
seek $c -6 end |
||||||
|
tell $c |
||||||
|
} -cleanup { |
||||||
|
close $c |
||||||
|
unset c content |
||||||
|
} -result 0 |
||||||
|
|
||||||
|
# ------------------------------------------------------------------------- |
||||||
|
# Explicit cleanup of loaded support classes. |
||||||
|
rename tcl::chan::events {} |
||||||
|
rename tcl::chan::core {} |
||||||
|
testsuiteCleanup |
||||||
|
return |
||||||
|
|
||||||
|
# Local Variables: |
||||||
|
# mode: tcl |
||||||
|
# indent-tabs-mode: nil |
||||||
|
# End: |
@ -0,0 +1,54 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::zero 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Re-implementation of Memchan's zero |
||||||
|
# Meta description channel. Based on Tcl 8.5's channel |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command for the creation of new |
||||||
|
# Meta description channels. No arguments. Result is the |
||||||
|
# Meta description handle of the new channel. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require tcl::chan::events |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::events |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::chan {} |
||||||
|
|
||||||
|
proc ::tcl::chan::zero {} { |
||||||
|
return [::chan create {read} [zero::implementation new]] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::zero::implementation { |
||||||
|
superclass tcl::chan::events ; # -> initialize, finalize, watch |
||||||
|
|
||||||
|
method initialize {args} { |
||||||
|
my allow read |
||||||
|
next {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
# Generate and return a block of N null bytes, as requested. |
||||||
|
# Zero device. |
||||||
|
|
||||||
|
method read {c n} { |
||||||
|
return [binary format @$n] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::chan::zero 1.1 |
||||||
|
return |
@ -0,0 +1,39 @@ |
|||||||
|
2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.15 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.14 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2011-02-21 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* pkgIndex.tcl: Removed the superfluous [list] command in the |
||||||
|
ifneeded script. |
||||||
|
|
||||||
|
2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.13 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2010-07-28 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* core.man: New files, documentation for the packages in |
||||||
|
* events.man: this module. |
||||||
|
* transformcore.man: |
||||||
|
|
||||||
|
2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.12 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2009-12-01 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* New module 'virtchannel_core', with core classes for virtual |
||||||
|
channels aka reflected channels. TclOO based. |
@ -0,0 +1,5 @@ |
|||||||
|
|
||||||
|
core, events |
||||||
|
|
||||||
|
Support packages for initialization, finalization, and |
||||||
|
timer-driven event support. |
@ -0,0 +1,72 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::core n 1.1] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Basic reflected/virtual channel support}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::core [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::core] package provides a [package TclOO] |
||||||
|
class implementing common behaviour needed by virtually every |
||||||
|
reflected or virtual channel (initialization, finalization). |
||||||
|
|
||||||
|
[para] This class expects to be used as either superclass of a concrete |
||||||
|
channel class, or to be mixed into such a class. |
||||||
|
|
||||||
|
[section {Class API}] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::core] [arg objectName]] |
||||||
|
|
||||||
|
This command creates a new channel core object with an associated |
||||||
|
global Tcl command whose name is [emph objectName]. This command may |
||||||
|
be used to invoke various operations on the object, as described in |
||||||
|
the section for the [sectref {Instance API}]. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[section {Instance API}] |
||||||
|
|
||||||
|
The API of channel core instances provides only two methods, both |
||||||
|
corresponding to channel handler commands (For reference see |
||||||
|
[uri http:/tip.tcl.tk/219 {TIP 219}]). They expect to be called |
||||||
|
from whichever object instance the channel core was made a part of. |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [arg objectName] [method initialize] [arg thechannel] [arg mode]] |
||||||
|
|
||||||
|
This method implements standard behaviour for the [method initialize] |
||||||
|
method of channel handlers. Using introspection it finds the handler |
||||||
|
methods supported by the instance and returns a list containing their |
||||||
|
names, as expected by the support for reflected channels in the Tcl |
||||||
|
core. |
||||||
|
|
||||||
|
[para] It further remembers the channel handle in an instance variable |
||||||
|
for access by sub-classes. |
||||||
|
|
||||||
|
[call [arg objectName] [method finalize] [arg thechannel]] |
||||||
|
|
||||||
|
This method implements standard behaviour for the [method finalize] |
||||||
|
method of channel handlers. It simply destroys itself. |
||||||
|
|
||||||
|
[call [arg objectName] [method destroy]] |
||||||
|
|
||||||
|
Destroying the channel core instance closes the channel it was |
||||||
|
initialized for, see the method [method initialize]. When destroyed |
||||||
|
from within a call of [method finalize] this does not happen, under |
||||||
|
the assumption that the channel is being destroyed by Tcl. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,73 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::core 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Support package handling a core |
||||||
|
# Meta description aspect of reflected base channels |
||||||
|
# Meta description (initialization, finalization). |
||||||
|
# Meta description It is expected that this class |
||||||
|
# Meta description is used as either one superclass of the |
||||||
|
# Meta description class C for a specific channel, or is |
||||||
|
# Meta description mixed into C. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::core { |
||||||
|
destructor { |
||||||
|
if {$channel eq {}} return |
||||||
|
close $channel |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method initialize {thechannel mode} { |
||||||
|
set methods [info object methods [self] -all] |
||||||
|
|
||||||
|
# Note: Checking of the mode against the supported methods is |
||||||
|
# done by the caller. |
||||||
|
|
||||||
|
set channel $thechannel |
||||||
|
set supported {} |
||||||
|
foreach m { |
||||||
|
initialize finalize watch read write seek configure cget |
||||||
|
cgetall blocking |
||||||
|
} { |
||||||
|
if {$m in $methods} { |
||||||
|
lappend supported $m |
||||||
|
} |
||||||
|
} |
||||||
|
return $supported |
||||||
|
} |
||||||
|
|
||||||
|
method finalize {c} { |
||||||
|
set channel {} ; # Prevent destroctor from calling close. |
||||||
|
my destroy |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable channel |
||||||
|
|
||||||
|
# channel The channel the handler belongs to. |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### |
||||||
|
package provide tcl::chan::core 1.1 |
||||||
|
return |
@ -0,0 +1,79 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::chan::events n 1.1] |
||||||
|
[keywords {event management}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Event support for reflected/virtual channels}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::chan::core [opt 1.1]] |
||||||
|
[require tcl::chan::events [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::chan::events] package provides a [package TclOO] |
||||||
|
class implementing common behaviour needed by virtually every |
||||||
|
reflected or virtual channel supporting event driven IO. It is a |
||||||
|
sub-class of [package tcl::chan::core], inheriting all of its behaviour. |
||||||
|
|
||||||
|
[para] This class expects to be used as either superclass of a concrete |
||||||
|
channel class, or to be mixed into such a class. |
||||||
|
|
||||||
|
[section {Class API}] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::chan::events] [arg objectName]] |
||||||
|
|
||||||
|
This command creates a new channel event core object with an associated |
||||||
|
global Tcl command whose name is [emph objectName]. This command may |
||||||
|
be used to invoke various operations on the object, as described in |
||||||
|
the section for the [sectref {Instance API}]. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[section {Instance API}] |
||||||
|
|
||||||
|
The API of channel event core instances provides only four methods, two |
||||||
|
corresponding to channel handler commands (For reference see |
||||||
|
[uri http:/tip.tcl.tk/219 {TIP 219}]), and the other two for use by |
||||||
|
sub-classes to control event generation. They former expect to be called |
||||||
|
from whichever object instance the channel event core was made a part of. |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [arg objectName] [method finalize] [arg thechannel]] |
||||||
|
|
||||||
|
This method implements standard behaviour for the [method finalize] |
||||||
|
method of channel handlers. It overrides the behaviour inherited from |
||||||
|
[package tcl::chan::core] and additionally disables any and all event |
||||||
|
generation before destroying itself. |
||||||
|
|
||||||
|
[call [arg objectName] [method watch] [arg thechannel] [arg eventmask]] |
||||||
|
|
||||||
|
This method implements standard behaviour for the [method watch] |
||||||
|
method of channel handlers. Called by the IO system whenever the |
||||||
|
interest in event changes it updates the instance state to activate |
||||||
|
and/or suppress the generation of the events of (non-)interest. |
||||||
|
|
||||||
|
[call [arg objectName] [method allow] [arg eventname]...] |
||||||
|
[call [arg objectName] [method disallow] [arg eventname]...] |
||||||
|
|
||||||
|
These two methods are exported to sub-classes, so that their instances |
||||||
|
can notify their event core of the events the channel they implement |
||||||
|
can (allow) or cannot (disallow) generate. |
||||||
|
|
||||||
|
Together with the information about the events requested by Tcl's IO |
||||||
|
system coming in through the [method watch] method the event core is |
||||||
|
able to determine which events it should (not) generate and act |
||||||
|
accordingly. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,154 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::chan::events 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Support package handling a core |
||||||
|
# Meta description aspect of reflected base channels |
||||||
|
# Meta description (timer |
||||||
|
# Meta description driven file event support). Controls a |
||||||
|
# Meta description timer generating the expected read/write |
||||||
|
# Meta description events. It is expected that this class |
||||||
|
# Meta description is used as either one superclass of the |
||||||
|
# Meta description class C for a specific channel, or is |
||||||
|
# Meta description mixed into C. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::chan::core |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require {Tcl 8.5} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# TODO :: set/get accessor methods for the timer delay |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.5 9 |
||||||
|
package require TclOO |
||||||
|
package require tcl::chan::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
oo::class create ::tcl::chan::events { |
||||||
|
superclass ::tcl::chan::core ; # -> initialize, finalize, destructor |
||||||
|
|
||||||
|
constructor {} { |
||||||
|
array set allowed { |
||||||
|
read 0 |
||||||
|
write 0 |
||||||
|
} |
||||||
|
set requested {} |
||||||
|
set delay 10 |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method finalize {c} { |
||||||
|
my disallow read write |
||||||
|
next $c |
||||||
|
} |
||||||
|
|
||||||
|
# Allow/disallow the posting of events based on the |
||||||
|
# events requested by Tcl's IO system, and the mask of |
||||||
|
# events the instance's channel can handle, per all |
||||||
|
# preceding calls of allow and disallow. |
||||||
|
|
||||||
|
method watch {c requestmask} { |
||||||
|
if {$requestmask eq $requested} return |
||||||
|
set requested $requestmask |
||||||
|
my Update |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
# Declare that the named events are handled by the |
||||||
|
# channel. This may start a timer to periodically post |
||||||
|
# these events to the instance's channel. |
||||||
|
|
||||||
|
method allow {args} { |
||||||
|
my Allowance $args yes |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# Declare that the named events are not handled by the |
||||||
|
# channel. This may stop the periodic posting of events |
||||||
|
# to the instance's channel. |
||||||
|
|
||||||
|
method disallow {args} { |
||||||
|
my Allowance $args no |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
# Event System State - Timer driven |
||||||
|
|
||||||
|
variable timer allowed requested posting delay |
||||||
|
|
||||||
|
# channel = The channel to post events to - provided by superclass |
||||||
|
# timer = Timer controlling the posting. |
||||||
|
# allowed = Set of events allowed to post. |
||||||
|
# requested = Set of events requested by core. |
||||||
|
# posting = Set of events we are posting. |
||||||
|
# delay = Millisec interval between posts. |
||||||
|
|
||||||
|
# 'allowed' is an Array (event name -> boolean). The |
||||||
|
# value is true if the named event is allowed to be |
||||||
|
# posted. |
||||||
|
|
||||||
|
# Common code used by both allow and disallow to enter |
||||||
|
# the state change. |
||||||
|
|
||||||
|
method Allowance {events enable} { |
||||||
|
set changed no |
||||||
|
foreach event $events { |
||||||
|
if {$allowed($event) == $enable} continue |
||||||
|
set allowed($event) $enable |
||||||
|
set changed yes |
||||||
|
} |
||||||
|
if {!$changed} return |
||||||
|
my Update |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# Merge the current event allowance and the set of |
||||||
|
# requested events into one datum, the set of events to |
||||||
|
# post. From that then derive whether we need a timer or |
||||||
|
# not and act accordingly. |
||||||
|
|
||||||
|
method Update {} { |
||||||
|
catch { after cancel $timer } |
||||||
|
set posting {} |
||||||
|
foreach event $requested { |
||||||
|
if {!$allowed($event)} continue |
||||||
|
lappend posting $event |
||||||
|
} |
||||||
|
if {[llength $posting]} { |
||||||
|
set timer [after $delay \ |
||||||
|
[namespace code [list my Post]]] |
||||||
|
} else { |
||||||
|
catch { unset timer } |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# Post the current set of events, then reschedule to |
||||||
|
# make this periodic. |
||||||
|
|
||||||
|
method Post {} { |
||||||
|
my variable channel |
||||||
|
set timer [after $delay \ |
||||||
|
[namespace code [list my Post]]] |
||||||
|
chan postevent $channel $posting |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### |
||||||
|
package provide tcl::chan::events 1.1 |
||||||
|
return |
@ -0,0 +1,8 @@ |
|||||||
|
if {![package vsatisfies [package provide Tcl] 8.5 9]} {return} |
||||||
|
|
||||||
|
package ifneeded tcl::chan::core 1.1 [list source [file join $dir core.tcl]] |
||||||
|
package ifneeded tcl::chan::events 1.1 [list source [file join $dir events.tcl]] |
||||||
|
|
||||||
|
if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} |
||||||
|
|
||||||
|
package ifneeded tcl::transform::core 1.1 [list source [file join $dir transformcore.tcl]] |
@ -0,0 +1,72 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::core n 1.1] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 219}] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Basic reflected/virtual channel transform support}] |
||||||
|
[require Tcl "8.5 9"] |
||||||
|
[require TclOO] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::core] package provides a [package TclOO] |
||||||
|
class implementing common behaviour needed by virtually every |
||||||
|
reflected or virtual channel transformation (initialization, finalization). |
||||||
|
|
||||||
|
[para] This class expects to be used as either superclass of a concrete |
||||||
|
channel class, or to be mixed into such a class. |
||||||
|
|
||||||
|
[section {Class API}] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::core] [arg objectName]] |
||||||
|
|
||||||
|
This command creates a new transform core object with an associated |
||||||
|
global Tcl command whose name is [emph objectName]. This command may |
||||||
|
be used to invoke various operations on the object, as described in |
||||||
|
the section for the [sectref {Instance API}]. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[section {Instance API}] |
||||||
|
|
||||||
|
The API of transform core instances provides only two methods, both |
||||||
|
corresponding to transform handler commands (For reference see |
||||||
|
[uri http:/tip.tcl.tk/230 {TIP 230}]). They expect to be called |
||||||
|
from whichever object instance the transform core was made a part of. |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [arg objectName] [method initialize] [arg thechannel] [arg mode]] |
||||||
|
|
||||||
|
This method implements standard behaviour for the [method initialize] |
||||||
|
method of transform handlers. Using introspection it finds the handler |
||||||
|
methods supported by the instance and returns a list containing their |
||||||
|
names, as expected by the support for reflected transformation in the |
||||||
|
Tcl core. |
||||||
|
|
||||||
|
[para] It further remembers the channel handle in an instance variable |
||||||
|
for access by sub-classes. |
||||||
|
|
||||||
|
[call [arg objectName] [method finalize] [arg thechannel]] |
||||||
|
|
||||||
|
This method implements standard behaviour for the [method finalize] |
||||||
|
method of channel handlers. It simply destroys itself. |
||||||
|
|
||||||
|
[call [arg objectName] [method destroy]] |
||||||
|
|
||||||
|
Destroying the transform core instance closes the channel and transform |
||||||
|
it was initialized for, see the method [method initialize]. When destroyed |
||||||
|
from within a call of [method finalize] this does not happen, under |
||||||
|
the assumption that the channel and transform are being destroyed by Tcl. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,71 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::core 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Support package handling a core |
||||||
|
# Meta description aspect of reflected transform channels |
||||||
|
# Meta description (initialization, finalization). |
||||||
|
# Meta description It is expected that this class |
||||||
|
# Meta description is used as either one superclass of the |
||||||
|
# Meta description class C for a specific channel, or is |
||||||
|
# Meta description mixed into C. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require TclOO |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::core { |
||||||
|
destructor { |
||||||
|
if {$channel eq {}} return |
||||||
|
close $channel |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method initialize {thechannel mode} { |
||||||
|
set methods [info object methods [self] -all] |
||||||
|
|
||||||
|
# Note: Checking of the mode against the supported methods is |
||||||
|
# done by the caller. |
||||||
|
|
||||||
|
set channel $thechannel |
||||||
|
set supported {} |
||||||
|
foreach m { |
||||||
|
initialize finalize read write drain flush limit? |
||||||
|
} { |
||||||
|
if {$m in $methods} { |
||||||
|
lappend supported $m |
||||||
|
} |
||||||
|
} |
||||||
|
return $supported |
||||||
|
} |
||||||
|
|
||||||
|
method finalize {c} { |
||||||
|
set channel {} ; # Prevent destroctor from calling close. |
||||||
|
my destroy |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable channel |
||||||
|
|
||||||
|
# channel The channel the handler belongs to. |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### |
||||||
|
package provide tcl::transform::core 1.1 |
||||||
|
return |
@ -0,0 +1,53 @@ |
|||||||
|
2013-03-04 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* zlib.man: Renamed, clashes with Tcl core manpage. |
||||||
|
* tcllib_zlib.man: New name. |
||||||
|
|
||||||
|
2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.15 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.14 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2011-02-21 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* pkgIndex.tcl: Removed the superfluous [list] command in the |
||||||
|
ifneeded script. |
||||||
|
|
||||||
|
2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.13 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2010-08-04 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* adler32.man: New files, documentation for the packages in |
||||||
|
* base64.man: this module. |
||||||
|
* counter.man: |
||||||
|
* crc32.man: |
||||||
|
* hex.man: |
||||||
|
* identity.man: |
||||||
|
* limitsize.man: |
||||||
|
* observe.man: |
||||||
|
* otp.man: |
||||||
|
* rot.man: |
||||||
|
* spacer.man: |
||||||
|
* zlib.man: |
||||||
|
|
||||||
|
2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net> |
||||||
|
|
||||||
|
* |
||||||
|
* Released and tagged Tcllib 1.12 ======================== |
||||||
|
* |
||||||
|
|
||||||
|
2009-12-01 Andreas Kupries <andreask@activestate.com> |
||||||
|
|
||||||
|
* New module 'virtchannel_transform, providing classes implementing |
||||||
|
various channel transformation. TclOO based. |
@ -0,0 +1,38 @@ |
|||||||
|
base64, hex |
||||||
|
|
||||||
|
Base64 and hex de- and encoding of data flowing |
||||||
|
through a channel. |
||||||
|
|
||||||
|
Encodes on write, decodes on read. |
||||||
|
|
||||||
|
identity |
||||||
|
|
||||||
|
No transformation |
||||||
|
|
||||||
|
counter |
||||||
|
|
||||||
|
Identity, counting bytes. |
||||||
|
|
||||||
|
adler32, adler32pure, crc32 |
||||||
|
|
||||||
|
Compute checksums and write to external variables. |
||||||
|
|
||||||
|
observe |
||||||
|
|
||||||
|
Divert copy of the data to additional channels. |
||||||
|
|
||||||
|
limitsize |
||||||
|
|
||||||
|
Force EOF after reading N bytes, N configurable. |
||||||
|
|
||||||
|
spacer |
||||||
|
|
||||||
|
Inserts separator string every n bytes. |
||||||
|
|
||||||
|
otp |
||||||
|
|
||||||
|
One-Time-Pad encryption. |
||||||
|
|
||||||
|
zlib |
||||||
|
|
||||||
|
zlib (de)compression (deflate, inflate). |
@ -0,0 +1,70 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::adler32 n 1.1] |
||||||
|
[keywords adler32] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords checksum] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Adler32 transformation}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::adler32 [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::adler32] package provides a command |
||||||
|
creating a channel transformation which passes the read and written |
||||||
|
bytes through unchanged (like [package tcl::transform::identity]), but |
||||||
|
additionally continuously computes the adler32 checksums of the data |
||||||
|
it has seen for each direction and stores them in Tcl variables |
||||||
|
specified at construction time. |
||||||
|
|
||||||
|
[para] Related transformations in this module are |
||||||
|
[package tcl::transform::counter], |
||||||
|
[package tcl::transform::crc32], |
||||||
|
[package tcl::transform::identity], and |
||||||
|
[package tcl::transform::observe]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::adler32] [arg chan] [option -option] [arg value]...] |
||||||
|
|
||||||
|
This command creates an adler32 checksumming transformation on top of |
||||||
|
the channel [arg chan] and returns its handle. The accepted options are |
||||||
|
|
||||||
|
[list_begin options] |
||||||
|
[opt_def -read-variable varname] |
||||||
|
|
||||||
|
The value of the option is the name of a global or namespaced |
||||||
|
variable, the location where the transformation has to store the |
||||||
|
adler32 checksum of the data read from the channel. |
||||||
|
|
||||||
|
[para] If not specified, or the empty string, the checksum of the read |
||||||
|
direction is not saved. |
||||||
|
|
||||||
|
[opt_def -write-variable varname] |
||||||
|
|
||||||
|
The value of the option is the name of a global or namespaced |
||||||
|
variable, the location where the transformation has to store the |
||||||
|
adler32 checksum of the data written to the channel. |
||||||
|
|
||||||
|
[para] If not specified, or the empty string, the checksum of the |
||||||
|
write direction is not saved. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,103 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::adler32 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes For other observers see crc32, counter, |
||||||
|
# Meta as::notes identity, and observer (stream copy). |
||||||
|
# Meta description Implementation of an adler32 checksum |
||||||
|
# Meta description transformation. Based on Tcl 8.6's |
||||||
|
# Meta description transformation reflection support (TIP |
||||||
|
# Meta description 230), and its zlib support (TIP 234) for |
||||||
|
# Meta description the adler32 functionality. An observer |
||||||
|
# Meta description instead of a transformation. For details |
||||||
|
# Meta description on the adler checksum see |
||||||
|
# Meta description http://en.wikipedia.org/wiki/Adler-32 . |
||||||
|
# Meta description The observer saves the checksums into two |
||||||
|
# Meta description namespaced external variables specified |
||||||
|
# Meta description at construction time. Exports a single |
||||||
|
# Meta description command adding a new transformation of |
||||||
|
# Meta description this type to a channel. One argument, |
||||||
|
# Meta description the channel to extend, plus options to |
||||||
|
# Meta description specify the variables for the checksums. |
||||||
|
# Meta description No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::adler32 {chan args} { |
||||||
|
::chan push $chan [adler32::implementation new {*}$args] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::adler32::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
# This transformation continuously computes a checksum from the |
||||||
|
# data it sees. This data may be arbitrary parts of the input or |
||||||
|
# output if the channel is seeked while the transform is |
||||||
|
# active. This may not be what is wanted and the desired behaviour |
||||||
|
# may require the destruction of the transform before seeking. |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
my Adler32 -write-variable $data |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
my Adler32 -read-variable $data |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {args} { |
||||||
|
array set options { |
||||||
|
-read-variable {} |
||||||
|
-write-variable {} |
||||||
|
} |
||||||
|
# todo: validity checking of options (legal names, legal |
||||||
|
# values, etc.) |
||||||
|
array set options $args |
||||||
|
my Init -read-variable |
||||||
|
my Init -write-variable |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable options |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method Init {o} { |
||||||
|
if {$options($o) eq ""} return |
||||||
|
upvar #0 $options($o) adler |
||||||
|
set adler 1 |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method Adler32 {o data} { |
||||||
|
if {$options($o) eq ""} return |
||||||
|
upvar #0 $options($o) adler |
||||||
|
set adler [zlib adler32 $data $adler] |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::adler32 1.1 |
||||||
|
return |
@ -0,0 +1,111 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::base64 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes Possibilities for extension: Currently |
||||||
|
# Meta as::notes the mapping between read/write and |
||||||
|
# Meta as::notes decode/encode is fixed. Allow it to be |
||||||
|
# Meta as::notes configured at construction time. |
||||||
|
# Meta description Implementation of a base64 |
||||||
|
# Meta description transformation (RFC 4648). Based on Tcl |
||||||
|
# Meta description 8.6's transformation reflection support |
||||||
|
# Meta description (TIP 230) and binary en/decode (TIP 317). |
||||||
|
# Meta description Exports a single command adding a new |
||||||
|
# Meta description transformation of this type to a channel. |
||||||
|
# Meta description One argument, the channel to extend. No |
||||||
|
# Meta description result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::base64 {chan} { |
||||||
|
::chan push $chan [base64::implementation new] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::base64::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
my Code encodebuf encode $data 3 |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
my Code decodebuf decode $data 4 |
||||||
|
} |
||||||
|
|
||||||
|
method flush {c} { |
||||||
|
set data [binary encode base64 $encodebuf] |
||||||
|
set encodebuf {} |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method drain {c} { |
||||||
|
set data [binary decode base64 $decodebuf] |
||||||
|
set decodebuf {} |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method clear {c} { |
||||||
|
set decodebuf {} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {} { |
||||||
|
set encodebuf {} |
||||||
|
set decodebuf {} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable encodebuf decodebuf |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method Code {bufvar op data n} { |
||||||
|
upvar 1 $bufvar buffer |
||||||
|
|
||||||
|
append buffer $data |
||||||
|
|
||||||
|
set n [my Complete $buffer $n] |
||||||
|
if {$n < 0} { |
||||||
|
return {} |
||||||
|
} |
||||||
|
|
||||||
|
set result \ |
||||||
|
[binary $op base64 \ |
||||||
|
[string range $buffer 0 $n]] |
||||||
|
incr n |
||||||
|
set buffer \ |
||||||
|
[string range $buffer $n end] |
||||||
|
|
||||||
|
return $result |
||||||
|
} |
||||||
|
|
||||||
|
method Complete {buffer n} { |
||||||
|
set len [string length $buffer] |
||||||
|
return [expr {(($len / $n) * $n)-1}] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::base64 1.1 |
||||||
|
return |
@ -0,0 +1,94 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::counter 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes For other observers see adler32, crc32, |
||||||
|
# Meta as::notes identity, and observer (stream copy). |
||||||
|
# Meta as::notes Possibilities for extension: Separate |
||||||
|
# Meta as::notes counters per byte value. Count over |
||||||
|
# Meta as::notes fixed time-intervals = channel speed. |
||||||
|
# Meta as::notes Use callbacks or traces to save changes |
||||||
|
# Meta as::notes in the counters, etc. as time-series. |
||||||
|
# Meta as::notes Compute statistics over the time-series. |
||||||
|
# Meta description Implementation of a counter |
||||||
|
# Meta description transformation. Based on Tcl 8.6's |
||||||
|
# Meta description transformation reflection support (TIP |
||||||
|
# Meta description 230). An observer instead of a |
||||||
|
# Meta description transformation, it counts the number of |
||||||
|
# Meta description bytes read and written. The observer |
||||||
|
# Meta description saves the counts into two external |
||||||
|
# Meta description namespaced variables specified at |
||||||
|
# Meta description construction time. Exports a single |
||||||
|
# Meta description command adding a new transformation of |
||||||
|
# Meta description this type to a channel. One argument, |
||||||
|
# Meta description the channel to extend, plus options to |
||||||
|
# Meta description specify the variables for the counters. |
||||||
|
# Meta description No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::counter {chan args} { |
||||||
|
::chan push $chan [counter::implementation new {*}$args] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::counter::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
my Count -write-variable $data |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
my Count -read-variable $data |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
# No partial data, nor state => no flush, drain, nor clear needed. |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {args} { |
||||||
|
array set options { |
||||||
|
-read-variable {} |
||||||
|
-write-variable {} |
||||||
|
} |
||||||
|
# todo: validity checking of options (legal names, legal |
||||||
|
# values, etc.) |
||||||
|
array set options $args |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable options |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method Count {o data} { |
||||||
|
if {$options($o) eq ""} return |
||||||
|
upvar #0 $options($o) counter |
||||||
|
incr counter [string length $data] |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::counter 1.1 |
||||||
|
return |
@ -0,0 +1,103 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::crc32 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes For other observers see adler32, counter, |
||||||
|
# Meta as::notes identity, and observer (stream copy). |
||||||
|
# Meta description Implementation of a crc32 checksum |
||||||
|
# Meta description transformation. Based on Tcl 8.6's |
||||||
|
# Meta description transformation reflection support (TIP |
||||||
|
# Meta description 230), and its zlib support (TIP 234) for |
||||||
|
# Meta description the crc32 functionality. An observer |
||||||
|
# Meta description instead of a transformation. For details |
||||||
|
# Meta description on the crc checksum see |
||||||
|
# Meta description http://en.wikipedia.org/wiki/Cyclic_redundancy_check#Commonly_used_and_standardised_CRCs . |
||||||
|
# Meta description The observer saves the checksums into two |
||||||
|
# Meta description namespaced external variables specified |
||||||
|
# Meta description at construction time. Exports a single |
||||||
|
# Meta description command adding a new transformation of |
||||||
|
# Meta description this type to a channel. One argument, |
||||||
|
# Meta description the channel to extend, plus options to |
||||||
|
# Meta description specify the variables for the checksums. |
||||||
|
# Meta description No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::crc32 {chan args} { |
||||||
|
::chan push $chan [crc32::implementation new {*}$args] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::crc32::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
# This transformation continuously computes a checksum from the |
||||||
|
# data it sees. This data may be arbitrary parts of the input or |
||||||
|
# output if the channel is seeked while the transform is |
||||||
|
# active. This may not be what is wanted and the desired behaviour |
||||||
|
# may require the destruction of the transform before seeking. |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
my Crc32 -write-variable $data |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
my Crc32 -read-variable $data |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {args} { |
||||||
|
array set options { |
||||||
|
-read-variable {} |
||||||
|
-write-variable {} |
||||||
|
} |
||||||
|
# todo: validity checking of options (legal names, legal |
||||||
|
# values, etc.) |
||||||
|
array set options $args |
||||||
|
my Init -read-variable |
||||||
|
my Init -write-variable |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable options |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method Init {o} { |
||||||
|
if {$options($o) eq ""} return |
||||||
|
upvar #0 $options($o) crc |
||||||
|
set crc 0 |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
method Crc32 {o data} { |
||||||
|
if {$options($o) eq ""} return |
||||||
|
upvar #0 $options($o) crc |
||||||
|
set crc [zlib crc32 $data $crc] |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::crc32 1.1 |
||||||
|
return |
@ -0,0 +1,43 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::hex n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords hexadecimal] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Hexadecimal encoding transformation}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::hex [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::hex] package provides a command creating |
||||||
|
a channel transformation which hex encodes data written to it, and |
||||||
|
decodes the data read from it. |
||||||
|
|
||||||
|
[para] A related transformations in this module is |
||||||
|
[package tcl::transform::base64]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::hex] [arg chan]] |
||||||
|
|
||||||
|
This command creates a hex transformation on top of the channel |
||||||
|
[arg chan] and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,58 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::hex 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of a hex transformation, |
||||||
|
# Meta description using Tcl 8.6's transformation |
||||||
|
# Meta description reflection support. Uses the binary |
||||||
|
# Meta description command to implement the transformation. |
||||||
|
# Meta description Exports a single command adding a new |
||||||
|
# Meta description transform of this type to a channel. One |
||||||
|
# Meta description argument, the channel to extend. No |
||||||
|
# Meta description result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::hex {chan} { |
||||||
|
::chan push $chan [hex::implementation new] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::hex::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
# bytes -> hex |
||||||
|
binary scan $data H* hex |
||||||
|
return $hex |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
# hex -> bytes |
||||||
|
return [binary format H* $data] |
||||||
|
} |
||||||
|
|
||||||
|
# No partial data, nor state => no flush, drain, nor clear needed. |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::hex 1.1 |
||||||
|
return |
@ -0,0 +1,50 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::identity n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords identity] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Identity transformation}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::identity [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::identity] package provides a command |
||||||
|
creating an identity channel transformation, which does nothing but |
||||||
|
pass the read and written bytes through it unchanged. Not really |
||||||
|
useful in an application, however as the prototypical observer |
||||||
|
transformation its code is a useful starting point for any other |
||||||
|
observers people may wish to write. |
||||||
|
|
||||||
|
[para] The transformations in this module which derived from |
||||||
|
identity's code are |
||||||
|
[package tcl::transform::adler32], |
||||||
|
[package tcl::transform::counter], |
||||||
|
[package tcl::transform::crc32], and |
||||||
|
[package tcl::transform::observe]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::identity] [arg chan]] |
||||||
|
|
||||||
|
This command creates an identity transformation on top of the channel |
||||||
|
[arg chan] and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,59 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::identity 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes The prototypical observer transformation. |
||||||
|
# Meta as::notes To observers what null is to reflected |
||||||
|
# Meta as::notes base channels. For other observers see |
||||||
|
# Meta as::notes adler32, crc32, counter, and observer |
||||||
|
# Meta as::notes (stream copy). |
||||||
|
# Meta description Implementation of an identity |
||||||
|
# Meta description transformation, i.e one which does not |
||||||
|
# Meta description change the data in any way, shape, or |
||||||
|
# Meta description form. Based on Tcl 8.6's transformation |
||||||
|
# Meta description reflection support. Exports a single |
||||||
|
# Meta description command adding a new transform of this |
||||||
|
# Meta description type to a channel. One argument, the |
||||||
|
# Meta description channel to extend. No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::identity {chan} { |
||||||
|
::chan push $chan [identity::implementation new] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::identity::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
# No partial data, nor state => no flush, drain, nor clear needed. |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::identity 1.1 |
||||||
|
return |
@ -0,0 +1,46 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::limitsize n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords limitsize] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {size limit}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {limiting input}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::limitsize [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::limitsize] package provides a command |
||||||
|
creating a channel transformation which limits the number of |
||||||
|
characters which can be read from the channel. A generator for an |
||||||
|
artificial EOF. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::limitsize] [arg chan] [arg max]] |
||||||
|
|
||||||
|
This command creates a size limiting transformation on top of the |
||||||
|
channel [arg chan] and returns its handle. |
||||||
|
|
||||||
|
[para] [arg max] is the number of bytes which can be read from the |
||||||
|
channel before EOF is signaled by the transformation. Note that |
||||||
|
popping the transformation clears the EOF it generated as well. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,88 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::limitsize 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes Possibilities for extension: Trigger the |
||||||
|
# Meta as::notes EOF when finding specific patterns in |
||||||
|
# Meta as::notes the input. Trigger the EOF based on some |
||||||
|
# Meta as::notes external signal routed into the limiter. |
||||||
|
# Meta as::notes Make the limit reconfigurable. |
||||||
|
# Meta description Implementation of a transformation |
||||||
|
# Meta description limiting the number of bytes read |
||||||
|
# Meta description from its channel. An observer instead of |
||||||
|
# Meta description a transformation, forcing an artificial |
||||||
|
# Meta description EOF marker. Based on Tcl 8.6's |
||||||
|
# Meta description transformation reflection support. |
||||||
|
# Meta description Exports a single command adding a new |
||||||
|
# Meta description transform of this type to a channel. One |
||||||
|
# Meta description argument, the channel to extend, and the |
||||||
|
# Meta description number of bytes to allowed to be read. |
||||||
|
# Meta description No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# This may help with things like zlib compression of messages. Have |
||||||
|
# the message format a length at the front, followed by a payload of |
||||||
|
# that size. Now we may compress messages. On the read side we can use |
||||||
|
# the limiter to EOF on a message, then reset the limit for the |
||||||
|
# next. This is a half-baked idea. |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::limitsize {chan max} { |
||||||
|
::chan push $chan [limitsize::implementation new $max] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::limitsize::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
# Reduce the limit of bytes allowed in the future according to |
||||||
|
# the number of bytes we have seen already. |
||||||
|
|
||||||
|
if {$max > 0} { |
||||||
|
incr max -[string length $data] |
||||||
|
if {$max < 0} { |
||||||
|
set max 0 |
||||||
|
} |
||||||
|
} |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method limit? {c} { |
||||||
|
return $max |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {themax} { |
||||||
|
set max $themax |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
variable max |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::limitsize 1.1 |
||||||
|
return |
@ -0,0 +1,50 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::observe n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords observer] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {stream copy}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Observer transformation, stream copy}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::observe [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::observer] package provides a command |
||||||
|
creating a channel transformation which passes the read and written |
||||||
|
bytes through unchanged (like [package tcl::transform::identity]), but |
||||||
|
additionally copies the data it has seen for each direction into |
||||||
|
channels specified at construction time. |
||||||
|
|
||||||
|
[para] Related transformations in this module are |
||||||
|
[package tcl::transform::adler32], |
||||||
|
[package tcl::transform::counter], |
||||||
|
[package tcl::transform::crc32], and |
||||||
|
[package tcl::transform::identity]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::observe] [arg chan] [arg logw] [arg logr]] |
||||||
|
|
||||||
|
This command creates an observer transformation on top of the channel |
||||||
|
[arg chan] and returns its handle. The channel handles [arg logr] and |
||||||
|
[arg logw] are there the data is copied to. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,80 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::observe 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes For other observers see adler32, crc32, |
||||||
|
# Meta as::notes identity, and counter. |
||||||
|
# Meta as::notes Possibilities for extension: Save the |
||||||
|
# Meta as::notes observed bytes to variables instead of |
||||||
|
# Meta as::notes channels. Use callbacks to save the |
||||||
|
# Meta as::notes observed bytes. |
||||||
|
# Meta description Implementation of an observer |
||||||
|
# Meta description transformation copying the bytes going |
||||||
|
# Meta description through it into two channels configured |
||||||
|
# Meta description at construction time. Based on Tcl 8.6's |
||||||
|
# Meta description transformation reflection support. |
||||||
|
# Meta description Exports a single command adding a new |
||||||
|
# Meta description transformation of this type to a channel. |
||||||
|
# Meta description Three arguments, the channel to extend, |
||||||
|
# Meta description plus the channels to write the bytes to. |
||||||
|
# Meta description No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::observe {chan logw logr} { |
||||||
|
::chan push $chan [observe::implementation new $logw $logr] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::observe::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
if {$logw ne {}} { |
||||||
|
puts -nonewline $logw $data |
||||||
|
} |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
if {$logr ne {}} { |
||||||
|
puts -nonewline $logr $data |
||||||
|
} |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
# No partial data, nor state => no flush, drain, nor clear needed. |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {lw lr} { |
||||||
|
set logr $lr |
||||||
|
set logw $lw |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable logr logw |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::observe 1.1 |
||||||
|
return |
@ -0,0 +1,98 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::otp 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of an onetimepad |
||||||
|
# Meta description encryption transformation. Based on Tcl |
||||||
|
# Meta description 8.6's transformation reflection support. |
||||||
|
# Meta description The key bytes are read from two channels |
||||||
|
# Meta description configured at construction time. Exports |
||||||
|
# Meta description a single command adding a new |
||||||
|
# Meta description transformation of this type to a channel. |
||||||
|
# Meta description Three arguments, the channel to extend, |
||||||
|
# Meta description plus the channels to read the keys from. |
||||||
|
# Meta description No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::otp {chan keychanw keychanr} { |
||||||
|
::chan push $chan [otp::implementation new $keychanw $keychanr] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::otp::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
# This transformation is intended for streaming operation. Seeking |
||||||
|
# the channel while it is active may cause undesirable |
||||||
|
# output. Proper behaviour may require the destruction of the |
||||||
|
# transform before seeking. |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
return [my Xor $data $keychanw] |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
return [my Xor $data $keychanr] |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {keyw keyr} { |
||||||
|
set keychanr $keyr |
||||||
|
set keychanw $keyw |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable keychanr keychanw |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
# A very convoluted way to perform the XOR would be to use TIP |
||||||
|
# #317's hex encoding to convert the bytes into strings, then zip |
||||||
|
# key and data into an interleaved string (nibble wise), then |
||||||
|
# perform the xor as a 'string map' of the whole thing, and at |
||||||
|
# last 'binary decode hex' the string back into bytes. Even so |
||||||
|
# most ops would run on the whole message at C level. Except for |
||||||
|
# the interleave. :( |
||||||
|
|
||||||
|
method Xor {data keychan} { |
||||||
|
# xor is done byte-wise. to keep IO down we read the key bytes |
||||||
|
# once, before the loop handling the bytes. Note that we are |
||||||
|
# having binary data at this point, making it necessary to |
||||||
|
# convert into numbers (scan), and back (binary format). |
||||||
|
|
||||||
|
set keys [read $keychan [string length $data]] |
||||||
|
set result {} |
||||||
|
foreach d [split $data {}] k [split $keys {}] { |
||||||
|
append result \ |
||||||
|
[binary format c \ |
||||||
|
[expr { |
||||||
|
[scan $d %c] ^ |
||||||
|
[scan $k %c] |
||||||
|
}]] |
||||||
|
} |
||||||
|
return $result |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::otp 1.1 |
||||||
|
return |
@ -0,0 +1,14 @@ |
|||||||
|
if {![package vsatisfies [package provide Tcl] 8.6 9]} {return} |
||||||
|
|
||||||
|
package ifneeded tcl::transform::adler32 1.1 [list source [file join $dir adler32.tcl]] |
||||||
|
package ifneeded tcl::transform::base64 1.1 [list source [file join $dir base64.tcl]] |
||||||
|
package ifneeded tcl::transform::counter 1.1 [list source [file join $dir counter.tcl]] |
||||||
|
package ifneeded tcl::transform::crc32 1.1 [list source [file join $dir crc32.tcl]] |
||||||
|
package ifneeded tcl::transform::hex 1.1 [list source [file join $dir hex.tcl]] |
||||||
|
package ifneeded tcl::transform::identity 1.1 [list source [file join $dir identity.tcl]] |
||||||
|
package ifneeded tcl::transform::limitsize 1.1 [list source [file join $dir limitsize.tcl]] |
||||||
|
package ifneeded tcl::transform::observe 1.1 [list source [file join $dir observe.tcl]] |
||||||
|
package ifneeded tcl::transform::otp 1.1 [list source [file join $dir otp.tcl]] |
||||||
|
package ifneeded tcl::transform::rot 1.1 [list source [file join $dir rot.tcl]] |
||||||
|
package ifneeded tcl::transform::spacer 1.1 [list source [file join $dir spacer.tcl]] |
||||||
|
package ifneeded tcl::transform::zlib 1.0.2 [list source [file join $dir zlib.tcl]] |
@ -0,0 +1,57 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::rot n 1.1] |
||||||
|
[keywords {caesar cipher}] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords cipher] |
||||||
|
[keywords decryption] |
||||||
|
[keywords encryption] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords rot] |
||||||
|
[keywords rot13] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {rot-encryption}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::rot [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::rot] package provides a command creating |
||||||
|
a channel transformation which performs primitive encryption (on |
||||||
|
writing) and decryption (on reading) on the alphabetic characters. The |
||||||
|
algorithm is the Caesar-cipher, a specific variant of which is rot13. |
||||||
|
|
||||||
|
[para] A related transformations in this module is |
||||||
|
[package tcl::transform::otp]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::rot] [arg chan] [arg key]] |
||||||
|
|
||||||
|
This command creates a rot encryption transformation on top of the |
||||||
|
channel [arg chan] and returns its handle. |
||||||
|
|
||||||
|
[para] The "[arg key]" specifies how far characters are rotated in the |
||||||
|
alphabet, and is wrapped to the range "0...25". |
||||||
|
|
||||||
|
[para] Note that this transformation affects only bytes in the ranges |
||||||
|
ASCII 65...90, and 97...122, i.e. the upper- and lower-case alphabetic |
||||||
|
characters, i.e. "A...Z" and "a...z". All other bytes are passed |
||||||
|
through unchanged. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,95 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::rot 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of a rot |
||||||
|
# Meta description encryption transformation. Based on Tcl |
||||||
|
# Meta description 8.6's transformation reflection support. |
||||||
|
# Meta description The key byte is |
||||||
|
# Meta description configured at construction time. Exports |
||||||
|
# Meta description a single command adding a new |
||||||
|
# Meta description transformation of this type to a channel. |
||||||
|
# Meta description Two arguments, the channel to extend, |
||||||
|
# Meta description plus the key byte. |
||||||
|
# Meta description No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::rot {chan key} { |
||||||
|
::chan push $chan [rot::implementation new $key] |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::rot::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
# This transformation is intended for streaming operation. Seeking |
||||||
|
# the channel while it is active may cause undesirable |
||||||
|
# output. Proper behaviour may require the destruction of the |
||||||
|
# transform before seeking. |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
return [my Rot $data $key] |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
return [my Rot $data $ikey] |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {thekey} { |
||||||
|
set key [expr {$thekey % 26}] |
||||||
|
set ikey [expr {26 - $key}] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable key ikey |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
method Rot {data key} { |
||||||
|
# rot'ation is done byte-wise. Note that we are having binary |
||||||
|
# data at this point, making it necessary to convert into |
||||||
|
# numbers (scan), and back (binary format). |
||||||
|
|
||||||
|
set result {} |
||||||
|
foreach d [split $data {}] { |
||||||
|
set dx [scan $d %c] |
||||||
|
if {(65 <= $dx) && ($dx <= 90)} { |
||||||
|
set n [binary format c \ |
||||||
|
[expr { (($dx - 65 + $key) % 26) + 65 }]] |
||||||
|
} elseif {(97 <= $dx) && ($dx <= 122)} { |
||||||
|
set n [binary format c \ |
||||||
|
[expr { (($dx - 97 + $key) % 26) + 97 }]] |
||||||
|
} else { |
||||||
|
set n $d |
||||||
|
} |
||||||
|
|
||||||
|
append result $n |
||||||
|
|
||||||
|
} |
||||||
|
return $result |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::rot 1.1 |
||||||
|
return |
@ -0,0 +1,45 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::spacer n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords spacing] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Space insertation and removal}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::spacer [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::spacer] package provides a command |
||||||
|
creating a channel transformation which adds spacing to the data |
||||||
|
written to it, and removes such spacing from the data read from it. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::spacer] [arg chan] [arg n] [opt [arg space]]] |
||||||
|
|
||||||
|
This command creates a spacer transformation on top of the channel |
||||||
|
[arg chan] and returns its handle. |
||||||
|
|
||||||
|
[para] The [arg space] character sequence will be added every [arg n] |
||||||
|
bytes of data written, and on the read side the same is done in |
||||||
|
reverse, removing the spacing. If [arg space] is not specified it |
||||||
|
defaults to a single space character (ASCII 32). |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,151 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::spacer 1.1 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta description Implementation of a spacer |
||||||
|
# Meta description transformation, using Tcl 8.6's |
||||||
|
# Meta description transformation reflection support. Uses |
||||||
|
# Meta description counters to implement the transformation, |
||||||
|
# Meta description i.e. decide where to insert the spacing. |
||||||
|
# Meta description Exports a single command adding a new |
||||||
|
# Meta description transform of this type to a channel. One |
||||||
|
# Meta description argument, the channel to extend. No |
||||||
|
# Meta description result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::spacer {chan n {space { }}} { |
||||||
|
::chan push $chan [spacer::implementation new $n $space] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::spacer::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
# This transformation is intended for streaming operation. Seeking |
||||||
|
# the channel while it is active may cause undesirable |
||||||
|
# output. Proper behaviour may require the destruction of the |
||||||
|
# transform before seeking. |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
# add spacing, data is split into groups of delta chars. |
||||||
|
set result {} |
||||||
|
set len [string length $data] |
||||||
|
|
||||||
|
if {$woffset} { |
||||||
|
# The beginning of the buffer is the remainder of the |
||||||
|
# partial group found at the end of the buffer in the last |
||||||
|
# call. It may still be partial, if the current buffer is |
||||||
|
# short enough. |
||||||
|
|
||||||
|
if {($woffset + $len) < $delta} { |
||||||
|
# Yes, the group is still not fully covered. |
||||||
|
# Move the offset forward, and return the whole |
||||||
|
# buffer. spacing is not needed yet. |
||||||
|
incr woffset $len |
||||||
|
return $data |
||||||
|
} |
||||||
|
|
||||||
|
# The buffer completes the group. Add it and the following |
||||||
|
# spacing, then fix the offset to start the processing of |
||||||
|
# the groups coming after at the proper location. |
||||||
|
|
||||||
|
set stop [expr {$delta - $woffset - 1}] |
||||||
|
|
||||||
|
append result [string range $data 0 $stop] |
||||||
|
append result $spacing |
||||||
|
|
||||||
|
set woffset $stop |
||||||
|
incr woffset |
||||||
|
} |
||||||
|
|
||||||
|
# Process full groups in the middle of the incoming buffer. |
||||||
|
|
||||||
|
set at $woffset |
||||||
|
set stop [expr {$at + $delta - 1}] |
||||||
|
while {$stop < $len} { |
||||||
|
append result [string range $data $at $stop] |
||||||
|
append result $spacing |
||||||
|
incr at $delta |
||||||
|
incr stop $delta |
||||||
|
} |
||||||
|
|
||||||
|
# Process partial group at the end of the buffer and remember |
||||||
|
# the offset, for the processing of the group remainder in the |
||||||
|
# next call. |
||||||
|
|
||||||
|
if {($at < $len) && ($stop >= $len)} { |
||||||
|
append result [string range $data $at end] |
||||||
|
} |
||||||
|
set woffset [expr {$len - $at}] |
||||||
|
return $result |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
# remove spacing from groups of delta+sdelta chars, keeping |
||||||
|
# the first delta in each group. |
||||||
|
set result {} |
||||||
|
set iter [expr {$delta + $sdelta}] |
||||||
|
set at 0 |
||||||
|
if {$roffset} { |
||||||
|
if {$roffset < $delta} { |
||||||
|
append result [string range $data 0 ${roffset}-1] |
||||||
|
} |
||||||
|
incr at [expr {$iter - $roffset}] |
||||||
|
} |
||||||
|
set len [string length $data] |
||||||
|
set end [expr {$at + $delta - 1}] |
||||||
|
set stop [expr {$at + $iter - 1}] |
||||||
|
while {$stop < $len} { |
||||||
|
append result [string range $data $at $end] |
||||||
|
incr at $iter |
||||||
|
incr end $iter |
||||||
|
incr stop $iter |
||||||
|
} |
||||||
|
if {$end < $len} { |
||||||
|
append result [string range $data $at $end] |
||||||
|
set roffset [expr {$len - $end + 1}] |
||||||
|
} elseif {$at < $len} { |
||||||
|
append result [string range $data $at end] |
||||||
|
set roffset [expr {$len - $at}] |
||||||
|
} |
||||||
|
return [list $result $roffset] |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {n space} { |
||||||
|
set roffset 0 |
||||||
|
set woffset 0 |
||||||
|
set delta $n |
||||||
|
set spacing $space |
||||||
|
set sdelta [string length $spacing] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable roffset woffset delta spacing sdelta |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::spacer 1.1 |
||||||
|
return |
@ -0,0 +1,46 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::zlib n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords compression] |
||||||
|
[keywords decompression] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords {tip 234}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[keywords zlib] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {zlib (de)compression}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::zlib [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::zlib] package provides a command creating |
||||||
|
a channel transformation which zlib compresses the written data, and |
||||||
|
decompresses on reading. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::zlib] [arg chan] [opt [arg level]]] |
||||||
|
|
||||||
|
This command creates a zlib compressor transformation on top of the |
||||||
|
channel [arg chan] and returns its handle. |
||||||
|
|
||||||
|
[para] The [arg level] specifies how much effort is put into the |
||||||
|
compression, from [const 0] to [const 9], and defaults to [const 4]. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,44 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::base64 n 1.1] |
||||||
|
[keywords base64] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords {tip 317}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Base64 encoding transformation}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::base64 [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::base64] package provides a command |
||||||
|
creating a channel transformation which base64 encodes data written to |
||||||
|
it, and decodes the data read from it. |
||||||
|
|
||||||
|
[para] A related transformations in this module is |
||||||
|
[package tcl::transform::hex]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::base64] [arg chan]] |
||||||
|
|
||||||
|
This command creates a base64 transformation on top of the channel |
||||||
|
[arg chan] and returns its handle. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,68 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::counter n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords counter] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Counter transformation}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::counter [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::counterr] package provides a command |
||||||
|
creating a channel transformation which passes the read and written |
||||||
|
bytes through unchanged (like [package tcl::transform::identity]), but |
||||||
|
additionally counts the bytes it has seen for each direction and |
||||||
|
stores these counts in Tcl variables specified at construction time. |
||||||
|
|
||||||
|
[para] Related transformations in this module are |
||||||
|
[package tcl::transform::adler32], |
||||||
|
[package tcl::transform::crc32], |
||||||
|
[package tcl::transform::identity], and |
||||||
|
[package tcl::transform::observe]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::counter] [arg chan] [option -option] [arg value]...] |
||||||
|
|
||||||
|
This command creates a counter transformation on top of the channel |
||||||
|
[arg chan] and returns its handle. The accepted options are |
||||||
|
|
||||||
|
[list_begin options] |
||||||
|
[opt_def -read-variable varname] |
||||||
|
|
||||||
|
The value of the option is the name of a global or namespaced |
||||||
|
variable, the location where the transformation has to store the |
||||||
|
byte count of the data read from the channel. |
||||||
|
|
||||||
|
[para] If not specified, or the empty string, the counter of the read |
||||||
|
direction is not saved. |
||||||
|
|
||||||
|
[opt_def -write-variable varname] |
||||||
|
|
||||||
|
The value of the option is the name of a global or namespaced |
||||||
|
variable, the location where the transformation has to store the |
||||||
|
byte count of the data written to the channel. |
||||||
|
|
||||||
|
[para] If not specified, or the empty string, the counter of the |
||||||
|
write direction is not saved. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,70 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::crc32 n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords checksum] |
||||||
|
[keywords crc32] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Crc32 transformation}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::crc32 [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::crc32] package provides a command |
||||||
|
creating a channel transformation which passes the read and written |
||||||
|
bytes through unchanged (like [package tcl::transform::identity]), but |
||||||
|
additionally continuously computes the crc32 checksums of the data it |
||||||
|
has seen for each direction and stores them in Tcl variables specified |
||||||
|
at construction time. The checksum in question is zlib's crc32. |
||||||
|
|
||||||
|
[para] Related transformations in this module are |
||||||
|
[package tcl::transform::adler32], |
||||||
|
[package tcl::transform::counter], |
||||||
|
[package tcl::transform::identity], and |
||||||
|
[package tcl::transform::observe]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::crc32] [arg chan] [option -option] [arg value]...] |
||||||
|
|
||||||
|
This command creates a crc32 checksumming transformation on top of |
||||||
|
the channel [arg chan] and returns its handle. The accepted options are |
||||||
|
|
||||||
|
[list_begin options] |
||||||
|
[opt_def -read-variable varname] |
||||||
|
|
||||||
|
The value of the option is the name of a global or namespaced |
||||||
|
variable, the location where the transformation has to store the |
||||||
|
crc32 checksum of the data read from the channel. |
||||||
|
|
||||||
|
[para] If not specified, or the empty string, the checksum of the read |
||||||
|
direction is not saved. |
||||||
|
|
||||||
|
[opt_def -write-variable varname] |
||||||
|
|
||||||
|
The value of the option is the name of a global or namespaced |
||||||
|
variable, the location where the transformation has to store the |
||||||
|
crc32 checksum of the data written to the channel. |
||||||
|
|
||||||
|
[para] If not specified, or the empty string, the checksum of the |
||||||
|
write direction is not saved. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,53 @@ |
|||||||
|
[comment {-*- tcl -*- doctools manpage}] |
||||||
|
[manpage_begin tcl::transform::otp n 1.1] |
||||||
|
[keywords {channel transformation}] |
||||||
|
[keywords cipher] |
||||||
|
[keywords decryption] |
||||||
|
[keywords encryption] |
||||||
|
[keywords {one time pad}] |
||||||
|
[keywords otp] |
||||||
|
[keywords {reflected channel}] |
||||||
|
[keywords {tip 230}] |
||||||
|
[keywords transformation] |
||||||
|
[keywords {virtual channel}] |
||||||
|
[keywords xor] |
||||||
|
[copyright {2009 Andreas Kupries <andreas_kupries@users.sourceforge.net>}] |
||||||
|
[moddesc {Reflected/virtual channel support}] |
||||||
|
[category Channels] |
||||||
|
[titledesc {Encryption via one-time pad}] |
||||||
|
[require Tcl "8.6 9"] |
||||||
|
[require tcl::transform::core [opt 1.1]] |
||||||
|
[require tcl::transform::otp [opt 1.1]] |
||||||
|
[description] |
||||||
|
[para] |
||||||
|
|
||||||
|
The [package tcl::transform::otp] package provides a command creating |
||||||
|
a channel transformation which uses externally provided one-time pads |
||||||
|
to perform encryption (on writing) and decryption (on reading). |
||||||
|
|
||||||
|
[para] A related transformations in this module is |
||||||
|
[package tcl::transform::rot]. |
||||||
|
|
||||||
|
[para] The internal [package TclOO] class implementing the transform |
||||||
|
handler is a sub-class of the [package tcl::transform::core] |
||||||
|
framework. |
||||||
|
|
||||||
|
[section API] |
||||||
|
|
||||||
|
[list_begin definitions] |
||||||
|
|
||||||
|
[call [cmd ::tcl::transform::otp] [arg chan] [arg keychanw] [arg keychanr]] |
||||||
|
|
||||||
|
This command creates a one-time pad based encryption transformation on |
||||||
|
top of the channel [arg chan] and returns its handle. |
||||||
|
|
||||||
|
[para] The two channels [arg keychanw] and [arg keychanr] contain the |
||||||
|
one-time pads for the write and read directions, respectively. Their |
||||||
|
contents are reads and xored with the bytes written to and read from |
||||||
|
the channel. |
||||||
|
|
||||||
|
[list_end] |
||||||
|
|
||||||
|
[vset CATEGORY virtchannel] |
||||||
|
[include ../common-text/feedback.inc] |
||||||
|
[manpage_end] |
@ -0,0 +1,100 @@ |
|||||||
|
# -*- tcl -*- |
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
# (C) 2009 Andreas Kupries |
||||||
|
|
||||||
|
# @@ Meta Begin |
||||||
|
# Package tcl::transform::zlib 1.0.2 |
||||||
|
# Meta as::author {Andreas Kupries} |
||||||
|
# Meta as::copyright 2009 |
||||||
|
# Meta as::license BSD |
||||||
|
# Meta as::notes Possibilities for extension: Currently |
||||||
|
# Meta as::notes the mapping between read/write and |
||||||
|
# Meta as::notes de/compression is fixed. Allow it to be |
||||||
|
# Meta as::notes configured at construction time. |
||||||
|
# Meta description Implementation of a zlib (de)compressor. |
||||||
|
# Meta description Based on Tcl 8.6's transformation |
||||||
|
# Meta description reflection support (TIP 230) and zlib |
||||||
|
# Meta description support (TIP 234). Compresses on write. |
||||||
|
# Meta description Exports a single command adding a new |
||||||
|
# Meta description transformation of this type to a channel. |
||||||
|
# Meta description Two arguments, the channel to extend, |
||||||
|
# Meta description and the compression level. No result. |
||||||
|
# Meta platform tcl |
||||||
|
# Meta require tcl::transform::core |
||||||
|
# Meta require {Tcl 8.6} |
||||||
|
# @@ Meta End |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
package require Tcl 8.6 9 |
||||||
|
package require tcl::transform::core |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
namespace eval ::tcl::transform {} |
||||||
|
|
||||||
|
proc ::tcl::transform::zlib {chan {level 4}} { |
||||||
|
::chan push $chan [zlib::implementation new $level] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
oo::class create ::tcl::transform::zlib::implementation { |
||||||
|
superclass tcl::transform::core ;# -> initialize, finalize, destructor |
||||||
|
|
||||||
|
# This transformation is intended for streaming operation. Seeking |
||||||
|
# the channel while it is active may cause undesirable |
||||||
|
# output. Proper behaviour may require the destruction of the |
||||||
|
# transform before seeking. |
||||||
|
|
||||||
|
method initialize {c mode} { |
||||||
|
set compressor [zlib stream deflate -level $level] |
||||||
|
set decompressor [zlib stream inflate] |
||||||
|
|
||||||
|
next $c $mode |
||||||
|
} |
||||||
|
|
||||||
|
method finalize {c} { |
||||||
|
$compressor close |
||||||
|
$decompressor close |
||||||
|
|
||||||
|
next $c |
||||||
|
} |
||||||
|
|
||||||
|
method write {c data} { |
||||||
|
$compressor put $data |
||||||
|
return [$compressor get] |
||||||
|
} |
||||||
|
|
||||||
|
method read {c data} { |
||||||
|
$decompressor put $data |
||||||
|
return [$decompressor get] |
||||||
|
} |
||||||
|
|
||||||
|
method flush {c} { |
||||||
|
$compressor flush |
||||||
|
return [$compressor get] |
||||||
|
} |
||||||
|
|
||||||
|
method drain {c} { |
||||||
|
$decompressor flush |
||||||
|
return [$decompressor get] |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
constructor {thelevel} { |
||||||
|
# Should validate input (level in (0 ...9)) |
||||||
|
set level $thelevel |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
|
||||||
|
variable level compressor decompressor |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
} |
||||||
|
|
||||||
|
# # ## ### ##### ######## ############# |
||||||
|
package provide tcl::transform::zlib 1.0.2 |
||||||
|
return |
Loading…
Reference in new issue