| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | |
|---|
| 32 | package provide macports_util 1.0 |
|---|
| 33 | |
|---|
| 34 | |
|---|
| 35 | |
|---|
| 36 | namespace eval macports_util { |
|---|
| 37 | |
|---|
| 38 | |
|---|
| 39 | |
|---|
| 40 | proc method_wrap {name} { |
|---|
| 41 | variable argdefault |
|---|
| 42 | |
|---|
| 43 | set name [list $name] |
|---|
| 44 | |
|---|
| 45 | set args [uplevel 1 [subst -nocommands {info args $name}]] |
|---|
| 46 | set arglist {} |
|---|
| 47 | foreach arg $args { |
|---|
| 48 | set argname [list $arg] |
|---|
| 49 | if {[uplevel 1 [subst -nocommands {info default $name $argname argdefault}]]} { |
|---|
| 50 | lappend arglist [list $arg $argdefault] |
|---|
| 51 | } else { |
|---|
| 52 | lappend arglist $arg |
|---|
| 53 | } |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | set arglist [list $arglist] |
|---|
| 57 | set body [uplevel 1 [subst -nocommands {info body $name}]] |
|---|
| 58 | uplevel 1 [subst -nocommands { |
|---|
| 59 | proc $name $arglist { |
|---|
| 60 | if {[set err [catch {$body} result]] && [set err] != 2} { |
|---|
| 61 | if {[set err] == 1} { |
|---|
| 62 | return -code [set err] -errorcode [set ::errorCode] [set result] |
|---|
| 63 | } else { |
|---|
| 64 | return -code [set err] [set result] |
|---|
| 65 | } |
|---|
| 66 | } else { |
|---|
| 67 | return [set result] |
|---|
| 68 | } |
|---|
| 69 | } |
|---|
| 70 | }] |
|---|
| 71 | } |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | |
|---|
| 75 | |
|---|
| 76 | |
|---|
| 77 | |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | |
|---|
| 81 | |
|---|
| 82 | |
|---|
| 83 | |
|---|
| 84 | |
|---|
| 85 | |
|---|
| 86 | |
|---|
| 87 | proc ldindex {varName args} { |
|---|
| 88 | set varName [list $varName] |
|---|
| 89 | if {[llength $args] > 0} { |
|---|
| 90 | set idx [lindex $args 0] |
|---|
| 91 | set size [uplevel 1 [subst -nocommands {llength [set $varName]}]] |
|---|
| 92 | set badrange? 0 |
|---|
| 93 | if {[string is integer -strict $idx]} { |
|---|
| 94 | if {$idx < 0 || $idx >= $size} { |
|---|
| 95 | set badrange? 1 |
|---|
| 96 | } |
|---|
| 97 | } elseif {$idx eq "end"} { |
|---|
| 98 | if {$size == 0} { |
|---|
| 99 | set badrange? 1 |
|---|
| 100 | } |
|---|
| 101 | } elseif {[string match end-* $idx] && [string is integer -strict [string range $idx 4 end]]} { |
|---|
| 102 | set i [expr $size - 1 - [string range $idx 4 end]] |
|---|
| 103 | if {$i < 0 || $i >= $size} { |
|---|
| 104 | set badrange? 1 |
|---|
| 105 | } |
|---|
| 106 | } else { |
|---|
| 107 | error "bad index \"$idx\": must be integer or end?-integer?" |
|---|
| 108 | } |
|---|
| 109 | if {${badrange?}} { |
|---|
| 110 | error "list index out of range" |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | if {[llength $args] > 1} { |
|---|
| 114 | set list [uplevel 1 [subst -nocommands {lindex [set $varName] $idx}]] |
|---|
| 115 | set item [eval ldindex list [lrange $args 1 end]] |
|---|
| 116 | uplevel 1 [subst {lset $varName $idx [list $list]}] |
|---|
| 117 | } else { |
|---|
| 118 | set item [uplevel 1 [subst -nocommands {lindex [set $varName] $idx}]] |
|---|
| 119 | uplevel 1 [subst -nocommands {set $varName [lreplace [set $varName] $idx $idx]}] |
|---|
| 120 | } |
|---|
| 121 | } else { |
|---|
| 122 | set item [uplevel 1 [subst {set $varName}]] |
|---|
| 123 | uplevel 1 [subst {set $varName {}}] |
|---|
| 124 | } |
|---|
| 125 | return $item |
|---|
| 126 | } |
|---|
| 127 | macports_util::method_wrap ldindex |
|---|
| 128 | |
|---|
| 129 | |
|---|
| 130 | |
|---|
| 131 | |
|---|
| 132 | proc lpop {varName} { |
|---|
| 133 | set varName [list $varName] |
|---|
| 134 | set size [uplevel 1 [subst -nocommands {llength [set $varName]}]] |
|---|
| 135 | if {$size != 0} { |
|---|
| 136 | uplevel 1 [subst -nocommands {ldindex $varName end}] |
|---|
| 137 | } |
|---|
| 138 | } |
|---|
| 139 | macports_util::method_wrap lpop |
|---|
| 140 | |
|---|
| 141 | |
|---|
| 142 | |
|---|
| 143 | |
|---|
| 144 | |
|---|
| 145 | proc lpush {varName args} { |
|---|
| 146 | set varName [list $varName] |
|---|
| 147 | uplevel 1 [subst -nocommands {lappend $varName $args}] |
|---|
| 148 | } |
|---|
| 149 | macports_util::method_wrap lpush |
|---|
| 150 | |
|---|
| 151 | |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | proc lshift {varName} { |
|---|
| 155 | set varName [list $varName] |
|---|
| 156 | set size [uplevel 1 [subst -nocommands {llength [set $varName]}]] |
|---|
| 157 | if {$size != 0} { |
|---|
| 158 | uplevel 1 [subst -nocommands {ldindex $varName 0}] |
|---|
| 159 | } |
|---|
| 160 | } |
|---|
| 161 | macports_util::method_wrap lshift |
|---|
| 162 | |
|---|
| 163 | |
|---|
| 164 | |
|---|
| 165 | |
|---|
| 166 | proc lunshift {varName args} { |
|---|
| 167 | set varName [list $varName] |
|---|
| 168 | uplevel 1 [subst -nocommands { |
|---|
| 169 | if {![info exists $varName]} { |
|---|
| 170 | set $varName {} |
|---|
| 171 | } |
|---|
| 172 | }] |
|---|
| 173 | set value [concat $args [uplevel 1 set $varName]] |
|---|
| 174 | uplevel 1 set $varName [list $value] |
|---|
| 175 | } |
|---|
| 176 | macports_util::method_wrap lunshift |
|---|
| 177 | |
|---|
| 178 | |
|---|
| 179 | |
|---|
| 180 | |
|---|
| 181 | |
|---|
| 182 | |
|---|
| 183 | if {![namespace exists ::_trycatch]} { |
|---|
| 184 | namespace eval ::_trycatch { |
|---|
| 185 | variable catchStack {} |
|---|
| 186 | } |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | |
|---|
| 190 | |
|---|
| 191 | |
|---|
| 192 | proc throw {args} { |
|---|
| 193 | if {[llength $args] == 0} { |
|---|
| 194 | |
|---|
| 195 | if {[llength $::_trycatch::catchStack] == 0} { |
|---|
| 196 | return -code error "error: throw with no parameters outside of a catch" |
|---|
| 197 | } else { |
|---|
| 198 | set errorNode [lpop ::_trycatch::catchStack] |
|---|
| 199 | set errCode [lindex $errorNode 0] |
|---|
| 200 | set errMsg [lindex $errorNode 1] |
|---|
| 201 | set errInfo [lindex $errorNode 2] |
|---|
| 202 | return -code error -errorinfo $errInfo -errorcode $errCode $errMsg |
|---|
| 203 | } |
|---|
| 204 | } elseif {[llength $args] > 3} { |
|---|
| 205 | return -code error "wrong # args: should be \"throw ?type? ?message? ?info?\"" |
|---|
| 206 | } else { |
|---|
| 207 | set errCode [lindex $args 0] |
|---|
| 208 | if {[llength $args] > 1} { |
|---|
| 209 | set errMsg [lindex $args 1] |
|---|
| 210 | } else { |
|---|
| 211 | set errMsg "error: $errCode" |
|---|
| 212 | } |
|---|
| 213 | if {[llength $args] > 2} { |
|---|
| 214 | set errInfo [lindex $args 2] |
|---|
| 215 | } else { |
|---|
| 216 | set errInfo $errMsg |
|---|
| 217 | } |
|---|
| 218 | return -code error -errorinfo $errInfo -errorcode $errCode $errMsg |
|---|
| 219 | } |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | |
|---|
| 224 | proc try {args} { |
|---|
| 225 | |
|---|
| 226 | set catchList {} |
|---|
| 227 | if {[llength $args] == 0} { |
|---|
| 228 | return -code error "wrong # args: \ |
|---|
| 229 | should be \"try body ?catch {type-list ?ecvar? ?msgvar? ?infovar?} body ...? ?finally body?\"" |
|---|
| 230 | } |
|---|
| 231 | set body [lshift args] |
|---|
| 232 | while {[llength $args] > 0} { |
|---|
| 233 | set arg [lshift args] |
|---|
| 234 | switch $arg { |
|---|
| 235 | catch { |
|---|
| 236 | set elem [lshift args] |
|---|
| 237 | if {[llength $args] == 0 || [llength $elem] > 4} { |
|---|
| 238 | return -code error "invalid syntax in catch clause: \ |
|---|
| 239 | should be \"catch {type-list ?ecvar? ?msgvar? ?infovar?} body\"" |
|---|
| 240 | } elseif {[llength [lindex $elem 0 0]] == 0} { |
|---|
| 241 | return -code error "invalid syntax in catch clause: type-list must contain at least one type" |
|---|
| 242 | } |
|---|
| 243 | lpush catchList $elem [lshift args] |
|---|
| 244 | } |
|---|
| 245 | finally { |
|---|
| 246 | if {[llength $args] == 0} { |
|---|
| 247 | return -code error "invalid syntax in finally clause: should be \"finally body\"" |
|---|
| 248 | } elseif {[llength $args] > 1} { |
|---|
| 249 | return -code error "trailing args after finally clause" |
|---|
| 250 | } |
|---|
| 251 | set finallyBody [lshift args] |
|---|
| 252 | } |
|---|
| 253 | default { |
|---|
| 254 | return -code error "invalid syntax: \ |
|---|
| 255 | should be \"try body ?catch {type-list ?ecvar? ?msgvar? ?infovar?} body ...? ?finally body?\"" |
|---|
| 256 | } |
|---|
| 257 | } |
|---|
| 258 | } |
|---|
| 259 | |
|---|
| 260 | |
|---|
| 261 | if {[set err [catch {uplevel 1 $body} result]] == 1} { |
|---|
| 262 | set savedErrorCode $::errorCode |
|---|
| 263 | set savedErrorInfo $::errorInfo |
|---|
| 264 | |
|---|
| 265 | set savedErrorInfo [regsub -linestop {(\n \(.*\))?\n invoked from within\n"uplevel 1 \$body"\Z} \ |
|---|
| 266 | $savedErrorInfo ""] |
|---|
| 267 | |
|---|
| 268 | lpush ::_trycatch::catchStack [list $savedErrorCode $result $savedErrorInfo] |
|---|
| 269 | |
|---|
| 270 | foreach {elem catchBody} $catchList { |
|---|
| 271 | set typeList [lshift elem] |
|---|
| 272 | set match? 1 |
|---|
| 273 | set typeList [lrange $typeList 0 [expr [llength $savedErrorCode] - 1]] |
|---|
| 274 | set codeList [lrange $savedErrorCode 0 [expr [llength $typeList] - 1]] |
|---|
| 275 | foreach type $typeList code $codeList { |
|---|
| 276 | if {![string match $type $code]} { |
|---|
| 277 | set match? 0 |
|---|
| 278 | break |
|---|
| 279 | } |
|---|
| 280 | } |
|---|
| 281 | if {${match?}} { |
|---|
| 282 | |
|---|
| 283 | if {[set ecvar [lshift elem]] ne ""} { |
|---|
| 284 | uplevel 1 set [list $ecvar] [list $savedErrorCode] |
|---|
| 285 | } |
|---|
| 286 | if {[set msgvar [lshift elem]] ne ""} { |
|---|
| 287 | uplevel 1 set [list $msgvar] [list $result] |
|---|
| 288 | } |
|---|
| 289 | if {[set infovar [lshift elem]] ne ""} { |
|---|
| 290 | uplevel 1 set [list $infovar] [list $savedErrorInfo] |
|---|
| 291 | } |
|---|
| 292 | if {[set err [catch {uplevel 1 $catchBody} result]] == 1} { |
|---|
| 293 | |
|---|
| 294 | set savedErrorCode $::errorCode |
|---|
| 295 | set savedErrorInfo $::errorInfo |
|---|
| 296 | |
|---|
| 297 | set savedErrorInfo [regsub -linestop \ |
|---|
| 298 | {(\n \(.*\))?\n invoked from within\n"uplevel 1 \$catchBody"\Z} \ |
|---|
| 299 | $savedErrorInfo ""] |
|---|
| 300 | |
|---|
| 301 | set savedErrorInfo [regsub -linestop \ |
|---|
| 302 | {\n invoked from within\n"throw"\Z} $savedErrorInfo ""] |
|---|
| 303 | } |
|---|
| 304 | break |
|---|
| 305 | } |
|---|
| 306 | } |
|---|
| 307 | |
|---|
| 308 | lpop ::_trycatch::catchStack |
|---|
| 309 | } |
|---|
| 310 | |
|---|
| 311 | if {[info exists finallyBody]} { |
|---|
| 312 | |
|---|
| 313 | set savedErr $err |
|---|
| 314 | set savedResult $result |
|---|
| 315 | if {[set err [catch {uplevel 1 $finallyBody} result]] == 1} { |
|---|
| 316 | set savedErrorCode $::errorCode |
|---|
| 317 | set savedErrorInfo $::errorInfo |
|---|
| 318 | |
|---|
| 319 | set savedErrorInfo [regsub -linestop \ |
|---|
| 320 | {(\n \(.*\))?\n invoked from within\n"uplevel 1 \$finallyBody"\Z} \ |
|---|
| 321 | $savedErrorInfo ""] |
|---|
| 322 | } elseif {$err == 0} { |
|---|
| 323 | set err $savedErr |
|---|
| 324 | set result $savedResult |
|---|
| 325 | } |
|---|
| 326 | } |
|---|
| 327 | |
|---|
| 328 | if {$err == 1} { |
|---|
| 329 | return -code $err -errorinfo $savedErrorInfo -errorcode $savedErrorCode $result |
|---|
| 330 | } else { |
|---|
| 331 | return -code $err $result |
|---|
| 332 | } |
|---|
| 333 | } |
|---|