aio recvfrom was not null terminating the result
[jimtcl.git] / tclcompat.tcl
blob4a0929b87b15f7f02fa81208838c8739340a16c0
1 # (c) 2008 Steve Bennett <steveb@workware.net.au>
3 # Loads some Tcl-compatible features.
4 # case, lassign, parray, errorInfo, ::tcl_platform, ::env
6 package provide tclcompat 1.0
8 # Set up the ::env array
9 set env [env]
11 # Tcl 8.5 lassign
12 proc lassign {list args} {
13 # in case the list is empty...
14 lappend list {}
15 uplevel 1 [list foreach $args $list break]
16 lrange $list [llength $args] end-1
19 # case var ?in? pattern action ?pattern action ...?
20 proc case {var args} {
21 # Skip dummy parameter
22 if {[lindex $args 0] eq "in"} {
23 set args [lrange $args 1 end]
26 # Check for single arg form
27 if {[llength $args] == 1} {
28 set args [lindex $args 0]
31 # Check for odd number of args
32 if {[llength $args] % 2 != 0} {
33 return -code error "extra case pattern with no body"
36 # Internal function to match a value agains a list of patterns
37 local proc case.checker {value pattern} {
38 string match $pattern $value
41 foreach {value action} $args {
42 if {$value eq "default"} {
43 set do_action $action
44 continue
45 } elseif {[lsearch -bool -command case.checker $value $var]} {
46 set do_action $action
47 break
51 if {[info exists do_action]} {
52 set rc [catch [list uplevel 1 $do_action] result opts]
53 if {$rc} {
54 incr opts(-level)
56 return {*}$opts $result
60 # Optional argument is a glob pattern
61 proc parray {arrayname {pattern *}} {
62 upvar $arrayname a
64 set max 0
65 foreach name [array names a $pattern]] {
66 if {[string length $name] > $max} {
67 set max [string length $name]
70 incr max [string length $arrayname]
71 incr max 2
72 foreach name [lsort [array names a $pattern]] {
73 puts [format "%-${max}s = %s" $arrayname\($name\) $a($name)]
77 # Sort of replacement for $::errorInfo
78 # Usage: errorInfo error ?stacktrace?
79 proc errorInfo {error {stacktrace ""}} {
80 if {$stacktrace eq ""} {
81 set stacktrace [info stacktrace]
83 lassign $stacktrace p f l
84 if {$f ne ""} {
85 set result "$f:$l "
87 append result "Runtime Error: $error\n"
88 append result [stackdump $stacktrace]
91 proc {info nameofexecutable} {} {
92 if {[info exists ::jim_argv0]} {
93 if {[string first "/" $::jim_argv0] >= 0} {
94 return $::jim_argv0
96 foreach path [split [env PATH ""] :] {
97 set exec [file join $path $::jim_argv0]
98 if {[file executable $exec]} {
99 return $exec
103 return ""
106 # Implements 'file copy' - single file mode only
107 proc {file copy} {{force {}} source target} {
108 try {
109 if {$force ni {{} -force}} {
110 error "bad option \"$force\": should be -force"
113 set in [open $source]
115 if {$force eq "" && [file exists $target]} {
116 $in close
117 error "error copying \"$source\" to \"$target\": file already exists"
119 set out [open $target w]
120 bio copy $in $out
121 $out close
122 } on error {msg opts} {
123 incr opts(-level)
124 return {*}$opts $msg
125 } finally {
126 catch {$in close}
130 # try/on/finally conceptually similar to Tcl 8.6
132 # Usage: try ?catchopts? script ?onclause ...? ?finallyclause?
134 # Where:
135 # onclause is: on codes {?resultvar? ?optsvar?} script
137 # codes is: a list of return codes (ok, error, etc. or integers), or * for any
139 # finallyclause is: finally script
142 # Where onclause is: on codes {?resultvar? ?optsvar?}
143 proc try {args} {
144 set catchopts {}
145 while {[string match -* [lindex $args 0]]} {
146 set args [lassign $args opt]
147 if {$opt eq "--"} {
148 break
150 lappend catchopts $opt
152 if {[llength $args] == 0} {
153 return -code error {wrong # args: should be "try ?options? script ?argument ...?"}
155 set args [lassign $args script]
156 set code [catch -eval {*}$catchopts [list uplevel 1 $script] msg opts]
158 set handled 0
160 foreach {on codes vars script} $args {
161 switch -- $on \
162 on {
163 if {!$handled && ($codes eq "*" || [info returncode $code] in $codes)} {
164 lassign $vars msgvar optsvar
165 if {$msgvar ne ""} {
166 upvar $msgvar hmsg
167 set hmsg $msg
169 if {$optsvar ne ""} {
170 upvar $optsvar hopts
171 set hopts $opts
173 # Override any body result
174 set code [catch [list uplevel 1 $script] msg opts]
175 incr handled
178 finally {
179 set finalcode [catch [list uplevel 1 $codes] finalmsg finalopts]
180 if {$finalcode} {
181 # Override any body or handler result
182 set code $finalcode
183 set msg $finalmsg
184 set opts $finalopts
186 break
188 default {
189 return -code error "try: expected 'on' or 'finally', got '$on'"
193 if {$code} {
194 incr opts(-level)
195 return {*}$opts $msg
197 return $msg
200 # Generates an exception with the given code (ok, error, etc. or an integer)
201 # and the given message
202 proc throw {code {msg ""}} {
203 return -code $code $msg
206 set ::tcl_platform(platform) unix