http://www.yak.net/strick/crpl.tcl.2000-02-01.txt
(there may be some errors due to lack of esacaping < & > .... maybe you should 'view source' and copy from there)
# crpl.tcl # # Routines for minimizing typing in tcl # # Author: strick # # Date: December, 1999 # # crpl functions # if ![llength [info command common]] { uplevel #0 { proc crpl {} { return 2000-01-17 } set crpl_common "" proc common args { global crpl_common set crpl_common $args #foreach x $crpl_common { set a($x) 0 } #foreach x $args { set a($x) 0 } #set crpl_common [lsort [array names a]] } rename proc crpl_pre_common_proc crpl_pre_common_proc proc {name vars body} { global crpl_common # optimize -- only global if appears set z {} foreach x $crpl_common { if [string match "*$x*" $body] {lappend z $x} } if [llength $z] { crpl_pre_common_proc $name $vars "[concat global $z];;; $body" } else { crpl_pre_common_proc $name $vars "$body" } } proc crpl_join {args} { join $args } proc unk_equals {c args} { # short simple case: var=cmd if [regexp -nocase {^([a-z0-9_]+)[=]([^=]*)$} $c 0 1 2] { if {$2==""} { proc $c args " upvar 1 [list $1] z set z \[join \$args \] " } else { set cmd [list [list $2]] proc $c args " upvar 1 [list $1] z set z \[uplevel 1 $cmd \$args \] " } return [ uplevel 1 [list $c] $args ] } # short simple case: var(sub)=cmd if [regexp -nocase {^([a-z0-9_]+)[(]([a-z0-9_]*)[)][=]([^=]*)$} $c 0 1 2 3] { if {$3==""} { proc $c args " upvar 1 [list $1] z set z($2) \[join \$args \] " } else { set cmd [list [list $3]] proc $c args " upvar 1 [list $1] z set z($2) \[uplevel 1 $cmd \$args \] " } return [ uplevel 1 [list $c] $args ] } set v [split $c =] set n [llength $v] set cmd [lindex $v end] set z [uplevel 1 [list $cmd] $args] for {set i 0} {$i < $n - 1} {incr i} { set w [lindex $v $i] if {$w == ""} continue if {$n == 2} { # simple single var set x $z } elseif {$i == $n - 2} { set x [lrange $z $i end] } else { set x [lindex $z $i] } if [string match /* $w] { set level #0 #set w [string range $w 1 end] regsub {^/} $w {} w } else { set level 1 } switch -glob -- $w { "*+" {set op incr} "*|" {set op append} "*^" {set op lappend} "*@" {set op @} default {set op set} } if {$op != "set"} { # chop off extra char regsub {.$} $w {} w } if {$op != "@"} { if [regexp {^([^()]*)[(](.*)[)]$} $w 0 1 2] { upvar $level $1 a $op a($2) $x } else { upvar $level $w a $op a $x } } else { upvar $level ${w}n an set an [llength $x] for {set j 0} {$j < $an} {incr j} { upvar $level ${w}$j a set a [lindex $x $j] } } } return $z } proc eval_parens_expr c { regsub -all {[A-Za-z_][A-Za-z0-9_]*} $c {$&} c regsub -all {[^<>!=][=](?![=])} $c {&=} c regsub -all {@([$][A-Za-z_][A-Za-z0-9_]*)} $c {[llength \1]} c regsub -all {#([$][A-Za-z_][A-Za-z0-9_]*)} $c {[string length \1]} c regsub -all {'[$]([A-Za-z_][A-Za-z0-9_]*)} $c {"\1"} c uplevel 1 [list expr $c] } proc () {args} { upvar 1 __cond__ m if $m { return "" } else { uplevel 1 $args } } proc unk_parens {c args} { if [llength $args] { upvar 1 __cond__ m set b [ uplevel 1 [list eval_parens_expr $c] ] if { $b==0 || $b=="" } { set m 0 return "" } else { set m 1 uplevel 1 $args } } else { uplevel 1 [list eval_parens_expr $c] } } proc unk_tilde {c args} { regexp {[~](.*)} $c 0 f set z "" catch {set z [uplevel 1 [list $f] $args ]} return $z } proc unk_bquot {c args} { regexp {[`](.*)} $c 0 f #puts stderr [join [concat [list <<< $f ] $args]] puts stderr [concat [list <<< $f ] $args] if [set v [catch {uplevel 1 [list $f] $args} x]] { global errorCode errorInfo puts stderr ">ERROR>$v> ``$x''" error $x $errorInfo $errorCode } else { puts stderr ">>> ``$x''" } return $x } proc unk_squot {c args} { regexp {['](.*)} $c 0 f set z [uplevel 1 [list $f] $args ] puts stderr "=== ``$z''" return $z } proc unk_bang {c args} { regexp {[!](.*)} $c 0 f set z [uplevel 1 [list $f] $args ] expr { $z=="" || $z==0 } } proc unk_assert {c args} { set z [uplevel 1 $args ] if !$z { error "ASSERTION FAILED: [expr {$c=="@"? $args: $c}]" } } proc unk_apos {c args} { set c [split $c '] uplevel 1 $c $args } proc unk_apos {c args} { set z {} foreach c [split $c '] { set s 0 foreach c [split $c `] { if {$s} { lappend z [lindex $args end] set args [lrange $args 0 [expr {[llength $args]-2}]] } if { $c!="~"} {lappend z $c} set s 1 } } uplevel 1 $z $args } proc unk_comma {c args} { regexp {^([-:\w]+)[,](.*)} $c 0 m f set z [uplevel 1 [list $f] $args ] uplevel 1 [list $m $z] } proc unk_li {c list} { lindex $list $c } proc unk_limi {c list} { regsub {.$} $c {} c lrange $list $c end } proc unk_mili {c list} { lindex $list [expr {[llength $list]+$c}] } proc metacrpl {pat cmd} { global metacrpl lappend metacrpl $pat $cmd } metacrpl {^[0-9]+$} unk_li metacrpl {^[0-9]+-$} unk_limi metacrpl {^-[0-9]+$} unk_mili metacrpl {^[`]} unk_bquot metacrpl {^[']} unk_squot metacrpl {^[~]} unk_tilde metacrpl {^[!]} unk_bang metacrpl {^[@]} unk_assert metacrpl {^([-:\w]+)[,](.*)} unk_comma metacrpl {^[(].*[)]$} unk_parens metacrpl {^.*[=].*$} unk_equals metacrpl {^.*[`'].*$} unk_apos rename unknown crpl_pre_unknown proc unknown {c args} { if {$c=="" || $c==":"} { join $args } else { global metacrpl set f crpl_pre_unknown foreach {p u} $metacrpl { if [regexp $p $c] { set f $u ; break } } uplevel 1 [list $f $c] $args } } #++ Aliases for rsi: proc eq { a b } { expr { ![ string compare $a $b ] } } proc ne { a b } { string compare $a $b } proc zm { a b } { string match $a $b } proc zl { a } { string length $a } proc l args { return $args } proc ll { a } { llength $a } #-- b'th item of list a: proc li { a b } { lindex $a $b } proc zi { a b } { string index $a $b } #-- Everything from b through c in list a: proc lr { a b c } { lrange $a $b $c } proc zr { a b c } { string range $a $b $c } #-- Get the 0'th, first, 2nd item of list: ## ## proc 0 x { ## lindex $x 0 ## } ## ## proc 1 x { ## lindex $x 1 ## } ## ## proc 2 x { ## lindex $x 2 ## } ## proc -1 x { ## lindex $x end ## } ## ## #-- Get everything but the first: ## proc 1- x { ## lrange $x 1 end ## } ## #-- Initialize variables to: #-- ('uplevel' - does it in scope of caller.) #-- [n]ull string: proc n args { foreach x $args { uplevel 1 [ list set $x {} ] } } #-- [z]ero string: proc z args { foreach x $args { uplevel 1 [ list set $x 0 ] } } #-- [e]mpty hash (tcl calls it an array): proc e args { foreach x $args { catch { uplevel 1 [ list unset $x ] } uplevel 1 [ list set "[ get x ](0)" 0 ] uplevel 1 [ list unset "[ get x ](0)" ] } } #-- more useful version of foreach: #-- (sort of like perl map - really like lisp mapcar.) # - v = vector (list of items) - cmd - command to execute on each. #-- Returns a list of all the results. proc map { v cmd } { set z {} foreach x $v { lappend z [ uplevel 1 $cmd [ list $x ] ] } return $z } #-- Adding/multiplying/ANDing/whatever a list of numbers: #-- zero = 0 ; op = + proc reduce_dyadic { zero op list } { set z $zero foreach x $list { set z [ expr "\$z $op \$x" ] } return $z } #++ END carpal section. # p {name args} - defines proc "name" with arguments "args" # (the last argument is the body of the procedure) # # Beginning an argument with certain characters causes special behavior: # ^ promotes to the variable to the caller's scope # / refers to the global variable by that name proc p {name args} { n vars pre n=ll $args foreach x [lr $args 0 [(n-2)]] { switch -glob -- $x { ^* { v=zr $x 1 end vars^= __name__$v pre|= " upvar 1 \$__name__$v $v ;;" } /* { v=zr $x 1 end pre|= "[list global $v];;" } * { vars^= $x } } } body=li $args end proc $name $vars $pre$body } proc pe args { puts stderr "=== $args" return $args } proc ce args { # catch exception set z "" catch { set z [ uplevel 1 $args ] } return $z } proc i0 n { z= for {set i 0} {$i<$n} {incr i} {lappend z $i} return $z } proc io n { z= for {set i 1} {$i<=$n} {incr i} {lappend z $i} return $z } proc do args { puts stderr "<<< $args" if [set v [catch {uplevel 1 $args} x]] { global errorCode errorInfo puts stderr ">ERROR>$v> $x" error $x $errorInfo $errorCode } else { puts stderr ">>> $x" } return $x } proc try {x y {z #}} {upvar 1 _ _ set t [catch {uplevel 1 $x} _] ### case 1 is not quite right -- need another catch! switch $t { 0 {uplevel 1 $z; return $_} 1 {uplevel 1 $z; uplevel 1 $y} 2 {uplevel 1 $z; uplevel 1 {return $_}} 3 {error BREAK-IN-TRY; break} 4 {error CONTINUE-IN-TRY; continue} default {error "try default"} } } } } crpl #TESTS if {$argv0 == "crpl.tcl"} { do crpl do crpl do puts [(3+4)] do a=b=c=z=list 1 2 3 4 5 6 do !ll $z do !ll {} do !list do !list a b c do !!list do !!list a b c do ll,list do ll,list a b c do zl,list do zl,list a b c do ll,zl,list a b c do zl,zl,list a b c do !ll,list a b c do puts [(b*10)] do puts [((a+b)*c)] do a+=b^=c|==list 10 20 30 40 50 do puts [list $a $b $c $z] do a@=list 11 12 13 foreach i [lsort,info var ] { if [zm err* $i] break puts "$i : [~($i)]" ~parray $i } `w(1)=w(2)=w(3)=w(r,!x@,9)=list a b c d e f `array get w `unset w `w(1)=w(2)=w(3)=w(r,!x@,9)= "a b" `array get w `unset w `w(1)=w(2)=w(3)=w(r,!x@,9)= `array get w ce `@ expr 0!=1 ce `@test expr 0!=1 ce `@ expr 0==1 ce `@test expr 0==1 `'`ce list a b c ~`continue ce `break ce `continue ce `return 6 `try {a(x)= y} (8) ce `foreach x [io 9] { try { if {$x==5} break ; pe $x } error } `p c { try {return 5} {error} ; return 9} `c `x=do a=b=c=d=e==list 10 20 30 40 50 `(a) `(c) `(x) `ll,(x) `0,(x) `0,0,(x) `1,(x) `-1,(x) `1-,(x) `1-,1-,(x) `1-,1-,1-,(x) `0,1-,1-,1-,(x) ~do error bogus do (errorCode) ~do break do (errorCode) ~do continue do (errorCode) ~do return do (errorCode) ~do return 3.14 do (errorCode) do (a+b+c+@x+#x) do z=pid do z= pid do z= pid 1 2 3 4 do z= pid {1 2} {3 4} do z= do z=! do z=~! ```'do ce list a b c `~`continue `string'length xyz `string'match'x* xyz `string'match`xyz x* `map {x* y* *y* z *z *} `string'match`xyz `map {x* y* *y* z *z *} "`string'match`~ xyz" `y= ok `(c) (@x) `(!c) (@x) `(c-b-a) (@x) `(!(c-b-a)) (@x) `(c-b-a) (#x) `(!(c-b-a)) (#x) `(@x) ~error bogus `~(@x) error bogus `(y=='ok) (@x) `() : not `(y='ok) (@x) `() : not `(y!='ok) (@x) `() : not do common color size proc a {} { set color red } proc b {} { puts $color } `a `b `p c { try {return 5} {error} ; return 9} `c `p d /y ^n a b { ` $y $n ; y^= $a ; n^= $b ; ` $y $n ; } `p f /y ^n a b { l $a $b $n $y } `info arg d `info arg f `info body d `info body f ` $x `d x lemon lime `f x fruit veg `f y fruit veg 'lsort,info command 'map [lsort,info command *=*] info'body }
424.   Where do you get StrickPants?
  [strick/2007-06-30]
396.   I'm lost at sea and I need to navigate to a non-extradition island republic. Can you help?
  [overcode/2003-11-30]
383.   How do I translate to and from Japanese?
  [novalis/2003-09-25]
376.   What are three very useful online dictionaries?
  [jake/2003-09-22]
341.   Can you give me some pointers for using gpg/pgp and other encryption?
  [jake/2002-12-19]
335.   What is Bob?
  [gopherdave/2002-11-04]
295.   How do I get a cheap EPOC R5 (Symbian) handheld?
  [combee/2001-12-07]
283.   What is the beautiful font used in the movie "Bicentennial Man" ?
  [rupe/2001-11-09]
262.   Ricochet is dead for now. What are some alternatives?
  [rupe/2001-08-07]
255.   why is the text on some website(such as kernel.org) unreadable in konqueror at the default font size?
  [jesse/2001-07-09]
246.   why am i getting errors with when reflashing my TINI from a linux box?
  [jesse/2001-06-09]
178.   Why isn't my PCS email working on my Cingular/PB Wireless phone?
  [rupe/2001-02-12]
96.   Where can I find information on in-vehicle computer systems?
  [rupe/2000-05-24]
93.   Where can I find a GPLed Z80 assembler / disassembler for Linux and DOS?
  [rupe/2000-05-11]
57.   How do you make popcorn salad, and is it actually a "salad"?
  [mockturtle/2000-02-12]
32.   What are the 'mailer' flags (on the M lines) inside sendmail.cf ?
  [strick/2000-01-25]
17.   How can I make a didgeridoo for traveling?
  [ult/2002-04-20]
10.   are there ICKY THINGS on the internet?
  [strick/2000-01-17]