source: tol/tolbaseBLT/lib/trycatch/trycatch.tcl @ 56ade3b

1941-docker-image-to-testdevel
Last change on this file since 56ade3b was 56ade3b, checked in by Jorge Pérez <josp.jorge@…>, 10 years ago

fixes #1932, se ha creado la rama trunk/tolbaseBLT copia de trunk/tolbase

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@7330 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 8.6 KB
Line 
1#---------------------------------------------------------------------
2# TITLE:
3#       trycatch.tcl
4#
5# AUTHOR:
6#       Will Duquette
7#
8# DESCRIPTION:
9#       This package implements an exception handler control structure
10#       on top of the [catch] command.  See trycatch.ehtml for user
11#       documentation.
12#
13#       Copyright (C) 2001 by William H. Duquette.  See license.txt
14#       for license information.
15
16#---------------------------------------------------------------------
17# Package definition
18
19package provide trycatch 2.0
20
21#---------------------------------------------------------------------
22# Namespace definition
23
24namespace eval ::trycatch:: {
25    # Exported Commands
26    namespace export try throw onerr
27}
28
29#---------------------------------------------------------------------
30# Command definitions
31
32#---------------------------------------------------------------------
33# FUNCTION:
34#       try {tryScript}
35#       try {tryScript} catch ?options? {catchScript}
36#       try {tryScript} finally {finallyScript}
37#
38# INPUTS:
39#       tryScript       Script to execute, catching errors.
40#       args            catch or finally clauses
41#
42# OUTPUTS:
43#       none
44#
45# RETURNS:
46#       The value (and return code) of tryScript or catchScript
47#
48# DESCRIPTION:
49#       Evaluates tryScript in the context of the caller, catching the
50#       result and the return code (see [return]).  If the return code
51#       indicates no error, then try returns tryScripts result and
52#       return code.  messageVar is unchanged in this case.
53#
54#       If tryScript fails, then catchScript is evaluated in the context of the
55#       caller, and catchScript's result and return code are returned.
56
57proc ::trycatch::try {tryScript args} {
58    global errorCode errorInfo
59
60    set usage "syntax: try {...} catch ?opts? {...}, try {...} finally {...}"
61    set optionsUsage "valid options: -msg msgVar -code codeVar -info infoVar"
62   
63
64    # FIRST, if this is the trivial case, just do it.
65    if {[llength $args] == 0} {
66        # FIRST, evaluate the tryScript.
67        set returnCode [catch {uplevel 1 $tryScript} result]
68           
69        # NEXT, on error return something innocuous
70        if {$returnCode == 1} {
71            set returnCode 0
72            set result ""
73        }
74
75        # NEXT, return it.
76        return -code $returnCode $result
77    }
78
79    # NEXT, do what makes sense based on the first token in args
80    if {"catch" == [Next $args]} {
81        # FIRST, get any option values and the catch script
82        Pop args
83       
84        while {[string match "-*" [Next $args]]} {
85            set option [Pop args]
86            set var [Pop args]
87
88            if {"" == $var} {
89                error $optionsUsage
90            }
91
92            switch -- $option {
93                -msg  {upvar $var theMsg}
94                -code {upvar $var theCode}
95                -info {upvar $var theInfo}
96                default {error $optionsUsage}
97            }
98        }
99       
100        if {[llength $args] == 0} {
101            error $usage
102        }
103
104        set catchScript [Pop args]
105
106        if {[llength $args] != 0} {
107            error $usage
108        }
109
110        # NEXT, execute the try script, saving its return value.
111        set returnCode [catch {uplevel 1 $tryScript} result]
112
113        # NEXT, if there was an error, execute the
114        # catchScript in the context of the caller.
115        if {$returnCode == 1} {
116            # If the appropriate options were passed, then upvar has
117            # aliased these to the user's variables.  Otherwise, they
118            # are just local.
119       
120            set theMsg $result
121            set theCode $errorCode
122            set theInfo $errorInfo
123
124            set returnCode [catch {uplevel 1 $catchScript} result]
125        }
126
127        # NEXT, return the result and result code.  If there was an error
128        # we need to propagate the error information as well, so go ahead
129        # and include them; they'll be ignored if there was no error.
130        return -code $returnCode \
131                -errorcode $errorCode -errorinfo \
132                $errorInfo \
133                $result
134    } elseif {"finally" == [Next $args]} {
135        # FIRST, validate the args, and get the finally script.
136        Pop args
137
138        if {[llength $args] != 1} {
139            error $usage
140        }
141        set finallyScript [Pop args]
142
143        # NEXT, evaluate the tryScript, saving its return values
144        set returnCode [catch {uplevel 1 $tryScript} result]
145       
146        # NEXT, evaluate the finally script.  Throw an error
147        # if the result is anything but "ok"
148        set finallyCode [catch {uplevel 1 $finallyScript} finallyResult]
149
150        if {$finallyCode == 1} {
151            return -code $finallyCode \
152                    -errorcode $errorCode -errorinfo \
153                    $errorInfo \
154                    $finallyResult
155        } elseif {$finallyCode != 0} {
156            error "break, return, or continue in finally script"
157        }
158
159        # NEXT, return the result and result code.  If there was an error
160        # we need to propagate the error information as well, so go ahead
161        # and include them; they'll be ignored if there was no error.
162        return -code $returnCode \
163                -errorcode $errorCode -errorinfo \
164                $errorInfo \
165                $result
166    } else {
167        error $usage
168    }
169}
170
171#---------------------------------------------------------------------
172# FUNCTION:
173#       throw code message
174#
175# INPUTS:
176#       code            An error code; it should be list.
177#       message         A human-readable error message
178#
179# OUTPUTS:
180#       none
181#
182# RETURNS:
183#       Throws an error.
184#
185# DESCRIPTION:
186#       Equivalent to
187#
188#           error $message "" $code
189#
190#       It's provided for code that makes explicit use of error codes.
191
192proc ::trycatch::throw {code message} {
193    error $message "" $code
194}
195
196#---------------------------------------------------------------------
197# FUNCTION:
198#       onerr ?-code code? pattern script pattern script...
199#
200# INPUTS:
201#       args            Command arguments
202#
203# OUTPUTS:
204#       none
205#
206# RETURNS:
207#       Return value of executed script, if any.
208#
209# DESCRIPTION:
210#       Matches either the global errorCode or the specified code
211#       against each pattern in turn (using Match) until a match is
212#       found or the patterns are exhausted.  If a match is found, the
213#       the matching script is executed.
214
215proc ::trycatch::onerr {args} {
216    global errorCode
217    global errorInfo
218
219    set usage "syntax: onerr ?-code errorCode? pattern script ..."
220
221    # FIRST, see if a code has been specified; otherwise, use the
222    # global errorCode.
223
224    if {[string match "-*" [Next $args]]} {
225        set opt [Pop args]
226        if {"-code" != $opt || [llength $args] == 0} {
227            error $usage
228        }
229
230        set code [Pop args]
231    } else {
232        set code $errorCode
233    }
234
235    # NEXT, match each in turn until a match is found.
236   
237    if {[llength $args] % 2 != 0} {
238        error $usage
239    }
240
241    foreach {pattern script} $args {
242        # Does it Match?
243        if {[Match $pattern $code]} {
244            # FIRST, execute the script
245            set returnCode [catch {uplevel 1 $script} result]
246           
247            # NEXT, return the results.  The error data will be
248            # ignored if the return code is not an error.
249           
250            return -code $returnCode \
251                    -errorcode $errorCode -errorinfo $errorInfo \
252                    $result
253        }
254    }
255
256    return
257}
258
259#---------------------------------------------------------------------
260# FUNCTION:
261#       Next
262#
263# INPUTS:
264#       list
265#
266# OUTPUTS:
267#       none
268#
269# RETURNS:
270#       Next arg in the list
271#
272# DESCRIPTION:
273#       Returns the next arg in a list
274
275proc ::trycatch::Next {list} {
276    return [lindex $list 0]
277}
278
279#---------------------------------------------------------------------
280# FUNCTION:
281#       Pop
282#
283# INPUTS:
284#       listVar
285#
286# OUTPUTS:
287#       none
288#
289# RETURNS:
290#       The first arg
291#
292# DESCRIPTION:
293#       Removes the first arg from the list
294
295proc ::trycatch::Pop {listVar} {
296    upvar $listVar theList
297    set result [lindex $theList 0]
298    set theList [lrange $theList 1 end]
299
300    return $result
301}
302
303#---------------------------------------------------------------------
304# FUNCTION:
305#       Match patternList code
306#
307# INPUTS:
308#       patternList             A list of glob-patterns
309#       code                    An errorCode value
310#
311# OUTPUTS:
312#       none
313#
314# RETURNS:
315#       1 or 0
316#
317# DESCRIPTION:
318#       Matches the patterns in patternList against the tokens of
319#       code.  If a pattern doesn't match, or there are more patterns than
320#       tokens, the function returns 0.  Otherwise, it returns 1.
321
322proc ::trycatch::Match {patternList code} {
323    set len [llength $patternList]
324
325    if {[llength $code] < $len} {
326        return 0
327    }
328
329    for {set i 0} {$i < $len} {incr i} {
330        set pattern [lindex $patternList $i]
331        set token [lindex $code $i]
332
333        if {![string match $pattern $token]} {
334            return 0
335        }
336    }
337
338    return 1
339}
340
341
342
343
344
345
346
347
348
349
350
351
Note: See TracBrowser for help on using the repository browser.