* http://zarutian.cjb.net/ is my web page (seriusly out of date) * [Flow Based Programming] * [SEXP] * [Zarutian's Thingy Package] * [Zarutian's SEXP Package] * [serializable Safe Slave Interp] * http://www.cacr.math.uwaterloo.ca/hac/index.html * http://erights.org/ everything about object-capabilities * http://www.erights.org/elib/distrib/pipeline.html Promise Pipelining * http://www.fpx.de/Combat/ CORBA implemented in Tcl * http://news.bbc.co.uk/2/hi/technology/4145184.stm Interesting way to write on PDAs and Mobile devices * http://livedocs.macromedia.com/flashremoting/mx/Using_Flash_Remoting_MX/intro2.htm Action Message Format * http://opencroquet.org/ * http://jlombardi.blogspot.com/2004/10/what-is-croquet_11.html Julian Lombardi's Croquet Blog * http://linuxdevices.com/news/NS8377820601.html * http://www.strille.net/tutorials/part1_scrolling.php * http://www.tonypa.pri.ee/tbw/tut15.html * http://www.hhhh.org/perseant/lfs.html * http://www.informit.com/articles/article.asp?p=437097&rl=1 * http://video.google.com/videoplay?docid=7278544055668715642&q=bigtable * http://www.sfsu.edu/~doit/helpdesk/mdevapp.htm * [http://www.ece.cmu.edu/~koopman/stack_computers/sec7_1.html] <- var h�r a� lesa How the hell do you pronounce my nick? In four syllabels: Za-ru-ti-an I am also active on wikipedia under the same nick. (Both the English one and the Icelandic one) Stuff I am thinking about implementing/doing (DONT PUT PRESURE ON ME PLEASE!): * write a simple Tcl interpreter purely in Lua. * publishing my bindiff procedures and binpatch procedure. (that would be awesome! Please do) That might take a while because I have to dig the up from my old CRT iMac. (29.mars 2006) Which I still havent got around to do (14. oktober 2006) * write multiplexing and demultiplexing stuff to learn some tricks with [rechan] * - One is to have dual sided memchan (aka one handle to write to and another one to read from) * investigate what whould be the best way to write a bytecode compiler for Tcl ''in'' pure-Tcl (related to [Scripted Compiler]) * - Arent Syntax Dictionary Encoded code better cross platform than bytecodes? * change the unknown procedure to lookup a procedure in the parent namespaces up to the global namespace instead in just current and global. * wikit additions: * - post to the Tcler's chatroom when a page has been edited. (Some sort of flood preventation would be a good idea) * - add reversion deltas. (Current version and back-deltas to earlier versions are saved in two files) * ? autosave like in Gmail compose === scrachpad 2 == package require Tcl 8.5 package require zarutian/thingy 1.3 # see [[Zarutian's Thingy Package]] proc @ {name} { upvar [set name] [set name] return [set [set name]] } proc repeat {body keyword condition} { if {[string equal $keyword "until"]} { set condition "!([set condition])" } elseif {[string equal $keyword "while"]} { # left empty on purpose } else { error "expected: until or while as a keyword between the body and the condition" } uplevel 1 $body while {[uplevel 1 [list expr $condition]]} { uplevel 1 $body } } thingy picol_interp picol_interp variable code {} picol_interp variable code_pointer 0 picol_interp variable results {} picol_interp variable invocation {} picol_interp variable frame_type normal; # can be one of: "normal", "catcher", "loop" picol_interp variable frame_special {} picol_interp variable run_quota 1024 picol_interp variable running yes picol_interp variable definitions {} picol_interp variable returnstack {} picol_interp proc run {} { # part of interface variable run_quota variable running yes variable code variable code_pointer variable results while {(0 < [@ run_quota]) && [@ running]} { dict set results [@ code_pointer] [execute [spliceIn [lindex [@ code] [@ code_pointer]] [@ results]]] if {[llength [@ code]] <= [@ code_pointer]} { popReturnstack } incr code_pointer +1 incr run_quota -1 } } picol_interp proc popReturnstack {} { variable returnstack if {[llength [@ returnstack]] == 0} { # nothing more to run variable running no return } variable code variable code_pointer variable results if {[llength [@ code]] < [@ code_pointer]} { set code_pointer [llength [@ code]] } set value [dict [@ results] [expr [@ code_pointer] - 1]] set frame [lindex [@ returnstack] end] set returnstack [lrange [@ returnstack] 0 end-1] foreach {k v} [@ frame] { variable [@ k] [@ v] } # code_pointer points to this command dict set results [expr [@ code_pointer] - 1] [@ value] return } picol_interp proc pushReturnstack {{extra {}} { variable returnstack variable code variable code_pointer variable results variable invocation variable frame_type variable frame_special set frame [list code [@code] \ code_pointer [@ code_pointer] \ results [@ results] \ invocation [@ invocation] \ frame_type [@ frame_type] \ frame_special [@ frame_special]] foreach {k v} [@ extra] { lappend frame [@ k] lappend frame [@ v] } lappend returnstack [@ frame] return } picol_interp proc newFrame {call daCode} { pushReturnstack variable invocation [@ call] variable code_pointer -1; # because of the auto increasementer in method run variable results {} variable code [@ daCode] } picol_interp proc execute {call} { variable definitions set command [lindex [@ call] 0] if {[dict exists [@ definitions] [@ command]]} { set def [dict get [@ definitions] [@ command]] if {![dict exists [@ def] type]} { bgerror "type of definition missing"; return } if {[string equal "script" [dict get [@ def] type]]} { if {![dict exists [@ def] code]} { bgerror "code missing from an definition"; return } if {![dict exists [@ def] execlist]} { if {![dict exists [@ def] code]} { bgerror "code missing from an definition"; return } dict set definitions [@ command] execlist [translate [dict get [@ def] code]] } newFrame [dict get [@ definitions] [@ command] execlist] } elseif {[string equal "primitive" [dict get [@ def] type]]} { if {![dict exists [@ def] identifier]} { bgerror "identifier missing from an definition"; return } switch -exact -- [dict get [@ def] identifier] { "NOOP" {} "string" {} "string bytelength" {} "string compare" {} "string equal" {} "string first" {} "string index" {} "string is" {} "string last" {} "string length" {} "string map" {} "string match" {} "string range" {} "string repeat" {} "string replace" {} "string tolower" {} "string toupper" {} "string totitle" {} "string trim" {} "string trimleft" {} "string trimright" {} "string wordend" {} "string wordstart" {} "dict" {} "dict append" {} "dict create" {} "dict exists" {} "dict filter" {} "dict for" {} "dict get" {} "dict incr" {} "dict info" {} "dict keys" {} "dict lappend" {} "dict merge" {} "dict remove" {} "dict replace" {} "dict set" {} "dict size" {} "dict unset" {} "dict update" {} "dict values" {} "dict with" {} "if" { if {([llength [@ call]] != 3) && ([llength [@ call]] != 5)} { execute [list error "if: wrong number of arguments should be: if \[else \]"] return } set predicate [lindex [@ call] 1] set true-body [lindex [@ call] 2] set false-body {} if {([llength [@call]] == 5) && [string equal "else" [lindex [@ call] 3]]} { set false-body [lindex [@ call] 4] } # reverse lookup to find the __branch primitive foreach def [dict keys [@ definitions]] { if {[string equal [dict get [@ definitions] type] "primitive"]} { if {[string equal [dict get [@ definitions] identifier] "__branch"]} { set __branch [@ def] } if {[string equal [dict get [@ definitions] identifier] "__jump"]} { set __jump [@ def] } } } if {![info exists __branch]} { bgerror "__branch primitive not found!"; return } if {![info exists __jump]} { bgerror "__jump primitive not found!"; return } set daCode [translate [@ predicate]] set slot1 [llength [@ daCode]] lappend daCode "<<<__branch primitive comes here>>>" foreach item [translate [@ true-body] [llength [@ daCode]]] { lappend daCode [@ item] } if {![string equal [@ false-body] {}]} { set slot2 [llength [@ daCode]] lappend daCode "<<<__jump primitive comes here>>>" } lset daCode [@ slot1] [list [@ __branch] [expr [@ slot1] -1] [llength [@ daCode]]] if {![string equal [@ false-body] {}]} { foreach item [translate [@ false-body] [llength [@ daCode]]] { lappend daCode [@ item] } lset daCode [@ slot2] [list [@ __jump] [llength [@ daCode]]] } } "while" {} "break" {} "continue" {} "proc" {} "routine" {} "return" {} "+" {} "-" {} "/" {} "*" {} "^" {} "|" {} "&" {} "and" {} "or" {} "round" {} "sqrt" {} "sin" {} "log10" {} "hypot" {} "atan" {} "bool" {} "abs" {} "acos" {} "atan2" {} "entier" {} "sinh" {} "log" {} "floor" {} "tanh" {} "tan" {} "int" {} "asin" {} "min" {} "max" {} "ceil" {} "cos" {} "pow" {} "fmod" {} "negate" {} "set" {} "get" {} "variable" {} "actor" {} "actor send_message" {} "actor any_messages?" {} "actor next_message" {} "actor beget" {} "actor die" {} "actor drop_address" {} "actor gain" {} "lappend" {} "lassign" {} "lindex" {} "linsert" {} "list" {} "llength" {} "lrange" {} "lrepeat" {} "lreplace" {} "lsearch" {} "lsort" {} "eval" {} "uplevel" {} "__jump" { if {[llength [@ call] != 2} { bgerror "primitive __jump: wrong # of args"; return } set destination [lindex [@ call] 1] if {![string is digit [@ destination]]} { bgerror "primitive __jump: destination is not a number" } variable code_pointer [@ destination] return } "__branch" { # branch if predicate is {} if {[llength [@ call] != 3} { bgerror "primitive __branch: wrong # of args"; return } set predicate [lindex [@ call] 1] set destination [lindex [@ call] 2] if {![string is digit [@ destination]]} { bgerror "primitive __branch: destination is not a number"; return } variable results if {[string equal [dict get [@ results] [@ predicate]] {}]} { variable code_pointer [@ destination] } return } } } else { error "unknown definition type" } } else { if {[dict exists [@ definitions] unknown]} { return [execute [list unknown [@ call]] } else { if {[dict exists [@ definitions] error]} { return [execute [list error "no unknown proc exists"]] } else { bgerror "no error proc/command defined" } } } } picol_interp proc spliceIn {template values} { set result "" set index 0 while {[@ index] < [string length [@ template]]} { set char [string index [@ template] [@ index] incr index if {[string equal "\\" [@ char]]} { set char [string index [@ template] [@ index] incr index if {[string equal "u" [@ char]]} { set value [string range [@ template] [@ index] [incr index 3]] incr index append result [format "%c" [expr 0x[@ value]]] } elseif {[string equal "x" [@ char]]} { set value [string range [@ template] [@ index] [incr index]] incr index append result [format "%c" [expr 0x[@ value]]] } elseif {[string equal "t" [@ char]]} { append result "\t" } elseif {[string equal "r" [@ char]]} { append result "\r" } elseif {[string equal "n" [@ char]]} { append result "\n" } elseif {[string equal "b" [@ char]]} { append result "\b" } else { append result [@ char] } } elseif {[string equal "\[" [@ char]]} { set symbol "" repeat { set char [string index [@ template] [@ index]] if {![string equal "\]" [@ char]]} { append symbol [@ char] } } until {[string equal "\]" [@ char]]} if {![dict exists [@ values] [@ symbol]]} { bgerror "symbol not in values" ; return } append result [list [dict get [@ values] [@ symbol]] } elseif {[string equal "\{" [@ char]]} { append reuslt "\{" set level 1 repeat { set char [string index [@ template] [@ index]] incr index append result [@ char] if {[string equal "\{" [@ char]]} { incr level +1 } elseif {[string equal "\}" [@ char]]} { incr level -1 } elseif {[string equal "\\" [@ char]]} { set char [string index [@ template] [@ index]] incr index append result [@ char] } } until {[@ level] == 0} } else { append result [@ char] } } return [@ result] } thingy picol_translator picol_translator variable entries {} picol_translator variable lastUsed {} picol_translator proc translate {code {offset 0}} { variable entries variable lastUsed # have we translated this piece of code already? if {[dict exists [@ entries] [info level 0]]} { # yes dict set lastUsed [info level 0] [clock millisec] return [dict get [@ entries] [info level 0]] } # no # but do we have enaugh space? if {1000 < [dict size [@ entries]]} { # nope, discard all but around top 100 most used set top100 [lrange [lsort -decreasing -unique [dict values [@ lastUsed]] 0 100] foreach item [dict keys [@ lastUsed]] { if {[lsearch -exact [@ top100] [dict get [@ lastUsed] [@ item]]] == -1} { dict unset lastUsed [@ item] dict unset entries [@ item] } } } # translate the code into execlist set result [list] set counter [@ offset] set level 0 dict set stack [@ level] {} set index 0 set length [string length [@ code]] set braced? no set quoted? no while {[@ index] < [@ length]} { set char [string index [@ code] [@ index]] incr index if {[string equal "\$" [@ char]] && ![@ braced?]} { # not thpught all the way through yet set varname "" repeat { set char [string index [@ code] [@ index]] incr index if {![string is space [@ char]] && ![string equal [@ char] "\""]} { append varname [@ char] } } until {[string is space [@ char]] || [string equal [@ char] "\""]} dict append stack [@ level] "\[var_[@ varname]\]" } elseif {[string equal "\"" [@ char]] && ![@ braced?]} { if {[@ quoted?]} { set quoted? no } else { set quoted? yes } } elseif {[string equal "\\" [@ char]]} { dict append stack [@ level] "\\" dict append stack [@ level] [string index [@ code] [@ index]] incr index } elseif {[string equal "\[" [@ char]] && ![@ braced?]]} { incr level +1 dict set stack [@ level] {} } elseif {[string equal "\]" [@ char]] && ![@ braced?]]} { lappend result [dict get [@ stack] [@ level]] dict unset stack [@ level] incr level -1 if {[@ level] < 0} { error "too many \[ or too few \]" } dict append stack [@ level] "\[[@ counter]\]" incr counter } elseif {[string equal "\n" [@ char]] && ![@ braced?]]} { if {[@ level] != 0} { error "unquoted \\n inside an command" } if {![string is space [dict get [@ stack] 0]]} { lappend result [dict get [@ stack] 0] incr counter dict set stack 0 {} } } elseif {[string equal "\{" [@ char]]} { if {![@ braced?]} { set braced? 1 } else { incr braced? +1 } dict append stack [@ level] [@ char] } elseif {[string equal "\}" [@ char]]} { if {![@ braced?]} { error "missing \{ somewhere or too many \}" } else { incr braced? -1 } dict append stack [@ level] [@ char] } else { dict append stack [@ level] [@ char] } } dict set entries [info level 0] [@ result] dict set lastUsed [info level 0] [clock millisec] return [@ result] } picol_interp proc translate {code} { return [picol_translator translate [@ code]]} === scratchpad === package require Tcl 8.5 # Tcl 8.5 required because of usage of dict proc run {} { variable state while {[dict get $state running]} { switch -exact -- [string index [dict get $state code] [dict get $state index]] { "\{" { set item "\{" set brace-level 1 dict incr state index +1 while {$brace-level > 0} { set char [string index [dict get $state code] [dict get $state index]] if {$char == "\\"} { append item $char dict incr state index +1 append item [string index [dict get $state code] [dict get $state index]] } elseif {$char == "\{"} { append item $char incr brace-level +1 } elseif {$char == "\}"} { append item $char incr brace-level -1 } else { append item $char } dict incr state index +1 } dict append state stack [dict get $state stack-level] command $item } "\[" { dict incr state stack-level +1 dict set state stack [dict get $state stack-level] start-index [dict get $state index] } "\]" { set frame [dict get $state stack [dict get $state stack-level]] dict unset state stack [dict get $state stack-level] dict incr state stack-level -1 dict append state stack [dict get $state stack-level] command [execute $frame] } "\n" { set frame [dict get $state stack [dict get $state stack-level]] dict unset state stack [dict get $state stack-level] execute $frame } default { dict append state stack [dict get $state stack-level] command [string index [dict get $state code] [dict get $state index]] } } if {[dict get $state index] >= [string length [dict get $state code]]} { popReturnstack } dict incr state index +1 } } proc exacute {frame} { variable state dict incr state run_quota -1 if {[dict get state run_quota] == 1} { dict set state running no } set command_name [lindex [dict get $frame command] 0] if {[dict exists $state definitions $command_name]} { if {[string equal "primitive" [dict get $state definitions $command_name type]]} { set opcode [dict get $state definitions $command_name contents] switch -exact -- $opcode { } } elseif {[string equal "combined" [dict get $state definitions $command_name type]]} { pushReturnstack initFrame [list code [dict get $state definitions $command_name contents]] } } else { if {[string equal $command_name "unknown"]} { execute [list command [list error "unknown command not found"]] } else { execute [dict merge $frame [list command [list unknown [dict get $frame command]]]] } } } proc popReturnstack {} { variable state dict set state [dict merge $state [dict get $state returnStack]] } proc pushReturnstack {} { variable state dict set state returnStack $state } proc initFrame {presets} { variable state dict set state index -1 dict set state code {} dict set state stack-level 0 dict set state stack 0 {} dict set state [dict merge $state $presets] } === codeStart === proc textDelta {strA strB} { # strA should always be longer than strB if {[string length $strA] < [string length $strB]} { set tmp $strA set strA $strB set strB $tmp unset tmp } set indexA 0 set indexB 0 set theChange_text "" set theChange_end undefined set theChange_start undefined while {$indexA < [string length $strA]} { set charA [string index $strA $indexA] set charB [string index $strB $indexB] if {$charA == $charB} { incr indexB if {$theChange_start != "undefined"} { set theChange_end $indexA } } else { append theChange_text $charA if {$theChange_start == "undefined"} { set theChange_start $indexA } } incr indexA } if {$theChange_end == "undefined"} { set theChange_end $theChange_start } return [list $theChange_text $theChange_start $theChange_end] } proc namedArgs {} { upvar args args foreach {name value} $args { upvar $name tmp set tmp $value } } if 0 { Zarutian: The following is deprecated. } package ifneeded zarutian.memchan 1.0 { package require rechan 1.0 namespace eval ::zarutian::memchan {} proc ::zarutian::memchan::handler args { log [info level 0] set cmd [lindex $args 0] set chan [lindex $args 1] variable buffers variable write_read if {$cmd == "write"} { if {[lsearch [array names write_read] $chan] == -1} { error "$chan is only open for reading" } } append buffers($write_read($chan)) [lindex $args 2] return [string length [lindex $args 2]] } elseif {$cmd == "read"} { if {[lsearch [array names write_read] $chan] != -1} { error "$chan is only open for writing" } set data [string range $buffers($chan) 0 [lindex $args 2]] set buffers($chan) [string range $buffers($chan) [expr [lindex $args 2] +1] end] return $data } elseif {$cmd == "close"} { if {[lsearch [array names write_read] [lindex $args 1]] != -1} { close $write_read($chan) unset buffers($write_read($chan)) unset write_read($chan) } } } proc ::zarutian::memchan::new {} { log [info level 0] variable write_read set write [rechan ::zarutian::memchan::handler 4] set read [rechan ::zarutian::memchan::handler 2] set write_read($write) $read return [list $write $read] } package provide zarutian.memchan 1.0 } package ifneeded zarutian.demultiplexing 1.0 { package require zarutian.memchan 1.0 namespace eval ::zarutian::demultiplexing {} proc ::zarutian::demultiplexing::readChan {incoming_channel} { variable channels if {[eof $incoming_channel]} { foreach item [array names channels] { if {[string match "[set incoming_channel]_*" $item]} { foreach chan [set channels($item)] { close $chan } } } close $incoming_channel return } fconfigure $incoming_channel -encoding unicode -blocking 1 -translation auto gets $incoming_channel line set cmd [lindex $line 0] if {$cmd == "data"} { set chanId [lindex $line 1] set length [lindex $line 2] fconfigure $incoming_channel -encoding binary -blocking 1 -translation binary set data [read $incoming_channel $length] foreach chan $channels("[set incoming_channel]_[set chanId]") { puts $chan $data } return } elseif {$cmd == "eof"} { set chanId [lindex $line 1] foreach chan $channels("[set incoming_channel]_[set chanId]") { close $chan } return } elseif {$cmd == "flush"} { set chanId [lindex $line 1] foreach chan $channels("[set incoming_channel]_[set chanId]") { flush $chan } return } } proc ::zarutian::demultiplexing::addChan {channel chanid {listenChannel {}}} { variable channels if {$listenChannel != {}} { set write $listenChannel set read $listenChannel } else { set temp [::zarutian::memchan::new] set write [lindex $temp 0] set read [lindex $temp 1] } lappend channels("[set channel]_[set chanid]") $write return $read } proc ::zarutian::demultiplexing::setup {incoming_channel} { fileevent $incoming_channel [list ::zarutian::demultiplexing::readChan $incoming_channel] } package provide zarutian.demultiplexing 1.0 } package ifneeded zarutain.multiplexing 1.0 { package require zarutian.memchan 1.0 namespace eval ::zarutian::multiplexing {} proc ::zarutian::multiplexing::readChan {channel} { variable outgoing_channelsId variable outgoing_channelsMainChan if {[eof $channel]} { puts $outgoing_channelsMainChan($channel) "eof [set outgoing_channelsId($channel)]" flush $outgoing_channelsMainChan($channel) return } set rememberBlocking [fconfigure $channel -blocking] set rememberTranslation [fconfigure $channel -translation] fconfigure $channel -blocking 1 -translation binary set data [read $channel] set length [string bytelength $data] fconfigure $channel -blocking $rememberBlocking -translation $rememberTranslation puts $outgoing_channelsMainChan($channel) "data [set outgoing_channelsId($channel)] $length" fconfigure $outgoing_channelsMainChan($channel) -encoding binary -translation binary puts $outgoing_channelsMainChan($channel) $data flush $outgoing_channelsMainChan($channel) fconfigure $outgoing_channelsMainChan($channel) -encoding unicode -translation auto return } proc ::zarutian::multiplexing::addChan {mainchannel chanId channel} { variable outgoing_channelsId set outgoing_channelsId($channel) $chanId set outgoing_channelsMainChan($channel) $mainchannel fileevent $channel readable [list ::zarutian::multiplexing::readChan $channel] } package provide zarutain.multiplexing 1.0 } package ifneeded zarutain.leftShiftingRegister 1.0 { package require rechan 1.0 namespace eval ::zarutian::leftShiftingRegister {} proc ::zarutian::leftShiftingRegister::handler args { variable states variable polynominals variable lengths set cmd [lindex $args 0] set instance [lindex $args 1] if {$cmd == "write"} { error "this chanel is only open for reading" } elseif {$cmd == "close"} { unset states($instance) unset polynominals($instance) unset lengths($instance) } elseif {$cmd == "read"} { set reqlength [expr [lindex $args 2] * 8] set buffer $states($instance) set polyA [lindex $polynominals($instance) 0] set polyB [lindex $polynominals($instance) 1] if {($polyA < 0) || ($polyB <0)} { error "a polynominal is under zero" } if {($polyA > $lengths($instance)) || ($polyB > $lengths($instance))} { error "a polynominal addresses out of bound for the register" } if {$polyA == $polyB} { error "the polynominals must not be same" } for {} {$reqlength > 0} {incr reqlength -1} { append buffer [XOR [string index $states($instance) $polyA] [string index $states($instance) $polyB]] } set states($instance) [string range $buffer end-[expr $lengths($instance) +1] end] return [binary format B* $buffer)] } } proc ::zarutian::leftShiftingRegister::XOR {a b} { #IS: �etta er bara sanntafla. #EN: This is just an truthtable. if {$a && $b} { return 0 } elseif {$a && (!$b)} { return 1 } elseif {(!$a) && $b} { return 1 } elseif {(!$a) && (!$b)} { return 0 } } proc ::zarutian::leftShiftingRegister::new {startingState length polynominal} { variable states variable polynominals variable lengths set instance [rechan ::zarutian::leftShiftingRegister::handler 6] if {[llength $polynominal] != 2} { error "$polynomnial must be two positive numbers" } set states($instance) $startingState set polynominals($instance) $polynominal set lengths($instance) $length return $instance } package provide zarutain.leftShiftingRegister 1.0 } package ifneeded zarutian.bitSelector 0.1 { package require rechan 1.0 namespace eval ::zarutian::bitSelector {} proc ::zarutain::bitSelector::handler args { variable channelAs variable channelSs set cmd [lindex $args 0] set chan [lindex $args 1] if{$cmd == "read"} { set reqlength [lindex $args 2] set rememberChannelConfigurationA [fconfigure $channelAs($chan)] set rememberChannelConfigurationB [fconfigure $channelSs($chan)] fconfigure $channelAs($chan) -translation binary -encoding binary fconfigure $channelSs($chan) -translation binary -encoding binary set bufferS [read $channelSs($chan) $reqlength] binary scan $bufferS B* bufferS set bufferA "" # �a� er �ruglega einhver villa h�r inn� -byrjun- # hef �a� � tilfininguni a� �g �tti ekki a� nota gildi breytunar # temp1 sem index � breytuna byte for {set temp2 1} {$temp2 <= $reqlength} {incr temp2} { binary scan [read $channelAs($chan) 1] byte for {set temp1 1} {$temp1 <= 8} {incr temp1} { set temp3 [expr ($temp2 * 8) + $temp1] if {[string index $bufferS $temp3]} { append bufferA [string index $byte $temp1] } } } # �a� er �ruglega einhver villa h�r inn� -lok- fconfigure $channelAs($chan) [join $rememberChannelConfigurationA " "] fconfigure $channelSs($chan) [join $rememberChannelConfigurationB " "] return [binary format B* $bufferA] } elseif {$cmd == "write"} {} # lesa fyrsta af r�s S einn bita yfir � breytu x # ef x er 1 �� lesa einn bita af r�s A yfir � breytu y # b�ta y vi� buffer } proc ::zarutian::bitSelector::new {channelA channelS} { # channelA is the victim # channelS is the torturer variable instances if {[info exists instances("[set channelA]_[set channelS]")]} { return $instances("[set channelA]_[set channelS]") } set instance [rechan ::zarutain::bitSelector::handler 6] lappend instances $instance variable channelAs variable channelSs set channelAs($instance) $channelA set channelSs($instance) $channelS return $instance } package provide zarutian.bitSelector 0.1 } comment { other possible Tcl Core implementation thoughts Basic datatypes: * boolean (true/false) * bytestring (can be any binarydata that can be contained in octects) * table (like in Lua) floating points will be represented as a table containing something like this: "type": "float" "base": "exponent": } package ifneeded zarutian.app.synchRemoteEval 0.1 { proc getCallstack {} { set calls [list] set me [expr [info level] -1] for {set i $me} {$i > 0} {incr i -1} { lappend calls [info level $i] } return $calls } proc syncRemoteEval {channel} { set calls [getCallstack] set cmd [lindex $calls 2] set d [info level] if {$d > 2} { set u2 [lindex $calls 3] if {[lindex $u2 0] == "syncRemoteEval"} { return } } # info feedback prevention aka dont send back what we recived. set ok 1 foreach call $calls { if {[lindex $call 0] == "fileevent_for_synchRemoteEval"} { set ok 0; break } } if {$ok} { putsAndFlush $channel "callstack [list $calls]" } set val {} catch {set val [eval $cmd]} res if {$res != $val} { putsAndFlush $channel "error [list $res]" } else { putsAndFlush $channel "result [list $res]" } return -code return $res } proc fileevent_for_syncRemoteEval {chan} { } proc putsAndFlush {chan data} { catch { puts $chan $data flush $chan } } package provide zarutian.app.synchRemoteEval 0.1 } package ifneed zarutian.app.synchRemoteEvalVersionB 0.1 { # same as above but using execution traces package require Tcl 8.4 proc getCallstack {} { set calls [list] set me [expr [info level] -1] for {set i $me} {$i > 0} {incr i -1} { lappend calls [info level $i] } return $calls } proc was_called_anytime_by? {cmdname} { set calls [lrange [getCallstack] 1 end] foreach call $calls { if {[lindex $call 0] == $cmdname} { return 1 } } return 0 } proc sendToTheOtherEnd {data} { global remoteEvalSynch_channel catch { fconfigure $channel -encoding unicode ; # make sure that the data on the channel is unicode encoded puts $remoteEvalSynch_channel $data flush $remoteEvalSynch_channel } } proc remoteEvalSynchExecuteCallback args { set cmd [lindex $args 0] set op [lindex $args end] if {$op == "enter"} { if {![was_called_anytime_by? "remoteEvalSynchFileeventCallback"]} { sendToTheOtherEnd "start-eval [list $cmd]" # sendToTheOtherEnd "start-eval [list $cmd [getCallstack]]" } } elseif {$op == "leave"} { set code [lindex $args 1] set result [lindex $args 2] sendToTheOtherEnd "result-update [list $cmd $code $result]" # sendToTheOtherEnd "result-update [list $cmd $code $result [getCallstack]]" } } proc remoteEvalSynchFileeventCallback {channel} { global buffers if {[eof $channel} { # for the time being raise an error when channel is eofed by the other end error "$channel eofed!" } fconfigure $channel -encoding unicode ; # make sure that the data on the channel is unicode encoded append buffers($channel) [gets $channel] if {[info complete $buffers($channel)} { set event [lindex $buffers($channel) 0] set data [lindex $buffers($channel) 1] if {$event == "start-eval"} { set cmd [lindex $data 0] # set callstack [lindex $data 1] catch { eval $cmd } } elseif {$event == "result-update"} { # what should I do with this? # fyrst um sinn: check if code is error and error on it set cmd [lindex $data 0] set code [lindex $data 1] set result [lindex $data 2] # set callstack [lindex $data 3] if {$code == "error"} { error "remote-error: $channel [list $cmd] [list $result ]"} } unset buffers($channel) } } proc remoteEvalSynch {victim channel} { # channel must be two way fileevent $channel readable [list remoteEvalSynchFileeventCallback $channel] trace add execution $victim {enter leave} remoteEvalSynchExecuteCallback } package provide zarutian.app.synchRemoteEvalVersionB 0.1 } [Category Person]