Merge from vendor branch GROFF:
[dragonfly.git] / contrib / sendmail-8.13.4 / libsm / exc.html
1 <html>
2 <head>
3     <title>libsm : Exception Handling</title>
4 </head>
5 <body>
6
7 <a href="index.html">Back to libsm overview</a>
8
9 <center>
10     <h1> libsm : Exception Handling </h1>
11     <br> $Id: exc.html,v 1.12 2001/02/13 21:21:25 gshapiro Exp $
12 </center>
13
14 <h2> Introduction </h2>
15
16 The exception handling package provides the facilities that
17 functions in libsm use to report errors.
18 Here are the basic concepts:
19
20 <ol>
21 <li>
22     When a function detects an exceptional condition at the library level,
23     it does not print an error message, or call syslog, or
24     exit the program.  Instead, it reports the error back to its
25     caller, and lets the caller decide what to do.
26     This improves modularity, because error handling is separated
27     from error reporting.
28     <p>
29 <li>
30     Errors are not represented by a single integer error code,
31     because that you can't represent everything that an error handler
32     might need to know about an error by a single integer.
33     Instead, errors are represented by exception objects.
34     An exception object contains an exception code and an array
35     of zero or more exception arguments.
36     The exception code is a string that specifies what kind of exception
37     this is, and the arguments may be integers, strings or exception objects.
38     <p>
39 <li>
40     Errors are not reported using a special return value,
41     because if you religiously check for error returns from every
42     function call that could fail, then most of your code ends up being
43     error handling code.  Errors are reported by raising an exception.
44     When an exception is raised, we unwind the call stack
45     until we find an exception handler.  If the exception is
46     not handled, then we print the exception on stderr and
47     exit the program.
48 </ol>
49
50 <h2> Synopsis </h2>
51
52 <pre>
53 #include &lt;sm/exc.h&gt;
54
55 typedef struct sm_exc_type SM_EXC_TYPE_T;
56 typedef struct sm_exc SM_EXC_T;
57 typedef union sm_val SM_VAL_T;
58
59 /*
60 **  Exception types
61 */
62
63 extern const char SmExcTypeMagic[];
64
65 struct sm_exc_type
66 {
67         const char      *sm_magic;
68         const char      *etype_category;
69         const char      *etype_argformat;
70         void            (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream);
71         const char      *etype_printcontext;
72 };
73
74 extern const SM_EXC_TYPE_T SmEtypeOs;
75 extern const SM_EXC_TYPE_T SmEtypeErr;
76
77 void
78 sm_etype_printf(
79         SM_EXC_T *exc,
80         SM_FILE_T *stream);
81
82 /*
83 **  Exception objects
84 */
85
86 extern const char SmExcMagic[];
87
88 union sm_val
89 {
90         int             v_int;
91         long            v_long;
92         char            *v_str;
93         SM_EXC_T        *v_exc;
94 };
95
96 struct sm_exc
97 {
98         const char              *sm_magic;
99         size_t                  exc_refcount;
100         const SM_EXC_TYPE_T     *exc_type;
101         SM_VAL_T                *exc_argv;
102 };
103
104 SM_EXC_T *
105 sm_exc_new_x(
106         const SM_EXC_TYPE_T *type,
107         ...);
108
109 SM_EXC_T *
110 sm_exc_addref(
111         SM_EXC_T *exc);
112
113 void
114 sm_exc_free(
115         SM_EXC_T *exc);
116
117 bool
118 sm_exc_match(
119         SM_EXC_T *exc,
120         const char *pattern);
121
122 void
123 sm_exc_print(
124         SM_EXC_T *exc,
125         SM_FILE_T *stream);
126
127 void
128 sm_exc_write(
129         SM_EXC_T *exc,
130         SM_FILE_T *stream);
131
132 void
133 sm_exc_raise_x(
134         SM_EXC_T *exc);
135
136 void
137 sm_exc_raisenew_x(
138         const SM_EXC_TYPE_T *type,
139         ...);
140
141 /*
142 **  Ensure that cleanup code is executed,
143 **  and/or handle an exception.
144 */
145 SM_TRY
146         Block of code that may raise an exception.
147 SM_FINALLY
148         Cleanup code that may raise an exception.
149         This clause is guaranteed to be executed even if an exception is
150         raised by the SM_TRY clause or by an earlier SM_FINALLY clause.
151         You may have 0 or more SM_FINALLY clauses.
152 SM_EXCEPT(exc, pattern)
153         Exception handling code, triggered by an exception
154         whose category matches 'pattern'.
155         You may have 0 or more SM_EXCEPT clauses.
156 SM_END_TRY
157 </pre>
158
159 <h2> Overview </h2>
160
161     An exception is an object which represents an exceptional condition,
162     which might be an error condition like "out of memory", or might be
163     a condition like "end of file".
164 <p>
165     Functions in libsm report errors and other unusual conditions by
166     raising an exception, rather than by returning an error code or
167     setting a global variable such as errno.  If a libsm function is
168     capable of raising an exception, its name ends in "_x".
169     (We do not raise an exception when a bug is detected in the
170     program; instead, we terminate the program using <tt>sm_abort</tt>.
171     See <a href="assert.html">the assertion package</a>
172     for details.)
173 <p>
174     When you are using the libsm exception handling package,
175     you are using a new programming paradigm.
176     You will need to abandon some of the programming idioms
177     you are accustomed to, and switch to new idioms.
178     Here is an overview of some of these idioms.
179 <ol>
180 <li>
181         When a function is unable to complete its task because
182         of an exceptional condition, it reports this condition
183         by raising an exception.
184         <p>
185         Here is an example of how to construct an exception object
186         and raise an exception.
187         In this example, we convert a Unix system error into an exception.
188 <blockquote><pre>
189 fd = open(path, O_RDONLY);
190 if (fd == -1)
191         sm_exc_raise_x(sm_exc_new_x(&SmEtypeOs, errno, "open", "%s", path));
192 </pre></blockquote>
193
194         Because the idiom <tt>sm_exc_raise_x(sm_exc_new_x(...))</tt>
195         is so common, it can be abbreviated as <tt>sm_exc_raisenew_x(...)</tt>.
196 <p>
197 <li>
198         When you detect an error at the application level,
199         you don't call a function like BSD's <tt>errx</tt>,
200         which prints an error message on stderr and exits the program.
201         Instead, you raise an exception.
202         This causes cleanup code in surrounding exception handlers
203         to be run before the program exits.
204         For example, instead of this:
205 <blockquote><pre>
206 errx(1, "%s:%d: syntax error", filename, lineno);
207 </pre></blockquote>
208
209         use this:
210
211 <blockquote><pre>
212 sm_exc_raisenew_x(&SmEtypeErr, "%s:%d: syntax error", filename, lineno);
213 </pre></blockquote>
214
215         The latter code raises an exception, unwinding the call stack
216         and executing cleanup code.
217         If the exception is not handled, then the exception is printed
218         to stderr and the program exits.
219         The end result is substantially the same as a call to <tt>errx</tt>.
220 <p>
221 <li>
222         The SM_TRY ... SM_FINALLY ... control structure
223         ensures that cleanup code is executed and resources are released
224         in the presence of exceptions.
225 <p>
226         For example, suppose that you have written the following code:
227
228 <blockquote><pre>
229 rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
230 ... some code ...
231 sm_rpool_free_x(rpool);
232 </pre></blockquote>
233
234         If any of the functions called within "... some code ..." have
235         names ending in _x, then it is possible that an exception will be
236         raised, and if that happens, then "rpool" will not be freed.
237         And that's a bug.  To fix this bug, change your code so it looks
238         like this:
239
240 <blockquote><pre>
241 rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
242 SM_TRY
243         ... some code that can raise an exception ...
244 SM_FINALLY
245         sm_rpool_free_x(rpool);
246 SM_END_TRY
247 </pre></blockquote>
248
249 <li>
250         The SM_TRY ... SM_EXCEPT ... control structure handles an exception.
251         Unhandled exceptions terminate the program.
252         For example, here is a simple exception handler
253         that traps all exceptions, and prints the exceptions:
254
255 <blockquote><pre>
256 SM_TRY
257         /* code that can raise an exception */
258         ...
259 SM_EXCEPT(exc, "*")
260         /* catch all exceptions */
261         sm_exc_print(exc, stderr);
262 SM_END_TRY
263 </pre></blockquote>
264
265     Exceptions are reference counted.  The SM_END_TRY macro contains a
266     call to sm_exc_free, so you don't normally need to worry about freeing
267     an exception after handling it.  In the rare case that you want an
268     exception to outlive an exception handler, then you increment its
269     reference count by calling sm_exc_addref.
270 <p>
271 <li>
272     The second argument of the SM_EXCEPT macro is a glob pattern
273     which specifies the types of exceptions that are to be handled.
274     For example, you might want to handle an end-of-file exception
275     differently from other exceptions.
276     Here's how you do that:
277
278 <blockquote><pre>
279 SM_TRY
280         /* code that might raise end-of-file, or some other exception */
281         ...
282 SM_EXCEPT(exc, "E:sm.eof")
283         /* what to do if end-of-file is encountered */
284         ...
285 SM_EXCEPT(exc, "*")
286         /* what to do if some other exception is raised */
287         ...
288 SM_END_TRY
289 </pre></blockquote>
290 </ol>
291
292 <h2> Exception Values </h2>
293
294 In traditional C code, errors are usually denoted by a single integer,
295 such as errno.  In practice, errno does not carry enough information
296 to describe everything that an error handler might want to know about
297 an error.  And the scheme is not very extensible: if several different
298 packages want to add additional error codes, it is hard to avoid
299 collisions.
300
301 <p>
302 In libsm, an exceptional condition is described
303 by an object of type SM_EXC_T.
304 An exception object is created by specifying an exception type
305 and a list of exception arguments.
306
307 <p>
308 The exception arguments are an array of zero or more values.
309 The values may be a mixture of ints, longs, strings, and exceptions.
310 In the SM_EXC_T structure, the argument vector is represented
311 by <tt>SM_VAL_T&nbsp;*exc_argv</tt>, where <tt>SM_VAL_T</tt>
312 is a union of the possible argument types.
313 The number and types of exception arguments is determined by
314 the exception type.
315
316 <p>
317 An exception type is a statically initialized const object
318 of type SM_EXC_TYPE_T, which has the following members:
319
320 <dl>
321 <dt>
322 <tt> const char *sm_magic </tt>
323 <dd>
324         A pointer to <tt>SmExcTypeMagic</tt>.
325         <p>
326 <dt>
327 <tt> const char *etype_category </tt>
328 <dd>
329         This is a string of the form
330         <tt>"</tt><i>class</i><tt>:</tt><i>name</i><tt>"</tt>.
331         <p>
332         The <i>class</i> is used to assign the exception type to
333         one of a number of broad categories of exceptions on which an
334         exception handler might want to discriminate.
335         I suspect that what we want is a hierarchical taxonomy,
336         but I don't have a full design for this yet.
337         For now, I am recommending the following classes:
338         <dl>
339         <dt><tt>"F"</tt>
340         <dd>A fatal error has occurred.
341             This is an error that prevents the application
342             from making any further progress, so the only
343             recourse is to raise an exception, execute cleanup code
344             as the stack is unwound, then exit the application.
345             The out-of-memory exception raised by sm_malloc_x
346             has category "F:sm.heap" because sendmail commits suicide
347             (after logging the error and cleaning up) when it runs out
348             of memory.
349
350         <dt><tt>"E"</tt>
351         <dd>The function could not complete its task because an error occurred.
352             (It might be useful to define subclasses of this category,
353             in which case our taxonony becomes a tree, and 'F' becomes
354             a subclass of 'E'.)
355
356         <dt><tt>"J"</tt>
357         <dd>This exception is being raised in order to effect a
358             non-local jump.  No error has occurred; we are just
359             performing the non-local equivalent of a <tt>continue</tt>,
360             <tt>break</tt> or <tt>return</tt>.
361
362         <dt><tt>"S"</tt>
363         <dd>The function was interrupted by a signal.
364             Signals are not errors because they occur asynchronously,
365             and they are semantically unrelated to the function that
366             happens to be executing when the signal arrives.
367             Note that it is extremely dangerous to raise an exception
368             from a signal handler.  For example, if you are in the middle
369             of a call to malloc, you might corrupt the heap.
370         </dl>
371         Eric's libsm paper defines <tt>"W"</tt>, <tt>"D"</tt> and <tt>"I"</tt>
372         for Warning, Debug and Informational:
373         I suspect these categories only make sense in the context of
374         Eric's 1985 exception handling system which allowed you to
375         raise conditions without terminating the calling function.
376         <p>
377         The <i>name</i> uniquely identifies the exception type.
378         I recommend a string of the form
379         <i>library</i><tt>.</tt><i>package</i><tt>.</tt><i>detail</i>.
380         <p>
381 <dt>
382 <tt> const char *etype_argformat </tt>
383 <dd>
384         This is an array of single character codes.
385         Each code indicates the type of one of the exception arguments.
386         <tt>sm_exc_new_x</tt> uses this string to decode its variable
387         argument list into an exception argument vector.
388         The following type codes are supported:
389         <dl>
390         <dt><tt>i</tt>
391         <dd>
392                 The exception argument has type <tt>int</tt>.
393         <dt><tt>l</tt>
394         <dd>
395                 The exception argument has type <tt>long</tt>.
396         <dt><tt>e</tt>
397         <dd>
398                 The exception argument has type <tt>SM_EXC_T*</tt>.
399                 The value may either be <tt>NULL</tt> or a pointer
400                 to an exception.  The pointer value is simply copied
401                 into the exception argument vector.
402         <dt><tt>s</tt>
403         <dd>
404                 The exception argument has type <tt>char*</tt>.
405                 The value may either be <tt>NULL</tt> or a pointer
406                 to a character string.  In the latter case,
407                 <tt>sm_exc_new_x</tt> will make a copy of the string.
408         <dt><tt>r</tt>
409         <dd>
410                 The exception argument has type <tt>char*</tt>.
411                 <tt>sm_exc_new_x</tt> will read a printf-style
412                 format string argument followed by a list of printf
413                 arguments from its variable argument list, and convert
414                 these into a string.
415                 This type code can only occur as the last element
416                 of <tt>exc_argformat</tt>.
417         </dl>
418         <p>
419 <dt>
420 <tt> void (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
421 <dd>
422         This function prints an exception of the specified type
423         onto an output stream.
424         The final character printed is not a newline.
425 </dl>
426
427 <h2> Standard Exceptions and Exception Types </h2>
428
429 Libsm defines one standard exception value, <tt>SmHeapOutOfMemory</tt>.
430 This is a statically initialized const variable, because it seems
431 like a bad idea to dynamically allocate an exception object to
432 report a low memory condition.
433 This exception has category <tt>"F:sm.heap"</tt>.
434 If you need to, you can explicitly raise this exception
435 with <tt>sm_exc_raise_x(&SmHeapOutOfMemory)</tt>.
436
437 <p>
438 Statically initialized exception values cannot contain any
439 run-time parameters, so the normal case is to dynamically allocate
440 a new exception object whenever you raise an exception.
441 Before you can create an exception, you need an exception type.
442 Libsm defines the following standard exception types.
443
444 <dl>
445 <dt>
446 <tt> SmEtypeOs </tt>
447 <dd>
448         This represents a generic operating system error.
449         The category is <tt>"E:sm.os"</tt>.
450         The argformat is <tt>"isr"</tt>,
451         where argv[0] is the value of <tt>errno</tt>
452         after a system call has failed,
453         argv[1] is the name of the function (usually a system call) that failed,
454         and argv[2] is either <tt>NULL</tt>
455         or a character string which describes some of the arguments
456         to the failing system call (usually it is just a file name).
457         Here's an example of raising an exception:
458
459 <blockquote><pre>
460 fd = open(filename, O_RDONLY);
461 if (fd == -1)
462         sm_exc_raisenew_x(&SmEtypeOs, errno, "open", "%s", filename);
463 </pre></blockquote>
464
465         If errno is ENOENT and filename is "/etc/mail/snedmail.cf",
466         then the exception raised by the above code will be printed as
467
468 <blockquote><pre>
469 /etc/mail/snedmail.cf: open failed: No such file or directory
470 </pre></blockquote>
471
472 <dt>
473 <tt> SmEtypeErr </tt>
474 <dd>
475         This represents a generic error.
476         The category is <tt>"E:sm.err"</tt>,
477         and the argformat is <tt>"r"</tt>.
478         You can use it
479         in application contexts where you are raising an exception
480         for the purpose of terminating the program.
481         You know the exception won't be handled,
482         so you don't need to worry about packaging the error for
483         later analysis by an exception handler.
484         All you need to specify is the message string that
485         will be printed to stderr before the program exits.
486         For example,
487
488 <blockquote><pre>
489 sm_exc_raisenew_x(&SmEtypeErr, "name lookup failed: %s", name);
490 </pre></blockquote>
491 </dl>
492
493 <h2> Custom Exception Types </h2>
494
495 If you are writing a library package, and you need to raise
496 exceptions that are not standard Unix system errors,
497 then you need to define one or more new exception types.
498
499 <p>
500 Every new exception type needs a print function.
501 The standard print function <tt>sm_etype_printf</tt>
502 is all you need in the majority of cases.
503 It prints the <tt>etype_printcontext</tt> string of the exception type,
504 substituting occurrences of %0 through %9 with the corresponding
505 exception argument.
506 If exception argument 3 is an int or long,
507 then %3 will print the argument in decimal,
508 and %o3 or %x3 will print it in octal or hex.
509
510 <p>
511 In the following example, I will assume that your library
512 package implements regular expressions, and can raise 5 different exceptions.
513 When compiling a regular expression, 3 different syntax errors
514 can be reported:
515 <ul>
516 <li>unbalanced parenthesis
517 <li>unbalanced bracket
518 <li>missing argument for repetition operator
519 </ul>
520 Whenever one of these errors is reported, you will also report
521 the index of the character within the regex string at which the
522 syntax error was detected.
523 The fourth exception is raised if a compiled regular expression
524 is invalid: this exception has no arguments.
525 The fifth exception is raised if the package runs out of memory:
526 for this, you use the standard <tt>SmHeapOutOfMemory</tt> exception.
527
528 <p>
529 The obvious approach is to define 4 separate exception types.
530 Here they are:
531
532 <blockquote><pre>
533 /* print a regular expression syntax error */
534 void
535 rx_esyntax_print(SM_EXC_T *exc, SM_FILE_T *stream)
536 {
537         sm_io_fprintf(stream, "rx syntax error at character %d: %s",
538                 exc-&gt;exc_argv[0].v_int,
539                 exc-&gt;exc_type-&gt;etype_printcontext);
540 }
541 SM_EXC_TYPE_T RxSyntaxParen = {
542         SmExcTypeMagic,
543         "E:mylib.rx.syntax.paren",
544         "i",
545         rx_esyntax_print,
546         "unbalanced parenthesis"
547 };
548 SM_EXC_TYPE_T RxSyntaxBracket = {
549         SmExcTypeMagic,
550         "E:mylib.rx.syntax.bracket",
551         "i",
552         rx_esyntax_print,
553         "unbalanced bracket"
554 };
555 SM_EXC_TYPE_T RxSyntaxMissingArg = {
556         SmExcTypeMagic,
557         "E:mylib.rx.syntax.missingarg",
558         "i",
559         rx_esyntax_print,
560         "missing argument for repetition operator"
561 };
562
563 SM_EXC_TYPE_T RxRunCorrupt = {
564         SmExcTypeMagic,
565         "E:mylib.rx.run.corrupt",
566         "",
567         sm_etype_printf,
568         "rx runtime error: compiled regular expression is corrupt"
569 };
570 </pre></blockquote>
571
572 <p>
573 With the above definitions, you can raise a syntax error reporting
574 an unbalanced parenthesis at string offset <tt>i</tt> using:
575 <blockquote><pre>
576 sm_exc_raisenew_x(&RxSyntaxParen, i);
577 </pre></blockquote>
578
579 If <tt>i==42</tt> then this exception will be printed as:
580 <blockquote><pre>
581 rx syntax error at character 42: unbalanced parenthesis
582 </pre></blockquote>
583
584 An exception handler can provide special handling for regular
585 expression syntax errors using this code:
586 <blockquote><pre>
587 SM_TRY
588         ... code that might raise an exception ...
589 SM_EXCEPT(exc, "E:mylib.rx.syntax.*")
590         int i = exc-&gt;exc_argv[0].v_int;
591         ... handle a regular expression syntax error ...
592 SM_END_TRY
593 </pre></blockquote>
594
595 <p>
596 External requirements may force you to define an integer code
597 for each error reported by your package.  Or you may be wrapping
598 an existing package that works this way.  In this case, it might
599 make sense to define a single exception type, patterned after SmEtypeOs,
600 and include the integer code as an exception argument.
601
602 <p>
603 Your package might intercept an exception E generated by a lower
604 level package, and then reclassify it as a different expression E'.
605 For example, a package for reading a configuration file might
606 reclassify one of the regular expression syntax errors from the
607 previous example as a configuration file syntax error.
608 When you do this, the new exception E' should include the original
609 exception E as an exception parameter, and the print function for
610 exception E' should print the high level description of the exception
611 (eg, "syntax error in configuration file %s at line %d\n"),
612 then print the subexception that is stored as an exception parameter.
613
614 <h2> Function Reference </h2>
615
616 <dl>
617 <dt>
618 <tt> SM_EXC_T *sm_exc_new_x(const SM_EXC_TYPE_T *type, ...) </tt>
619 <dd>
620         Create a new exception.  Raise an exception on heap exhaustion.
621         The new exception has a reference count of 1.
622         <p>
623
624         A list of zero or more exception arguments follows the exception type;
625         these are copied into the new exception object.
626         The number and types of these arguments is determined
627         by <tt>type-&gt;etype_argformat</tt>.
628         <p>
629
630         Note that there is no rpool argument to sm_exc_new_x.
631         Exceptions are allocated directly from the heap.
632         This is because exceptions are normally raised at low levels
633         of abstraction and handled at high levels.  Because the low
634         level code typically has no idea of how or at what level the
635         exception will be handled, it also has no idea of which resource
636         pool, if any, should own the exception.
637         <p>
638 <dt>
639 <tt> SM_EXC_T *sm_exc_addref(SM_EXC_T *exc) </tt>
640 <dd>
641         Increment the reference count of an exception.
642         Return the first argument.
643         <p>
644 <dt>
645 <tt> void sm_exc_free(SM_EXC_T *exc) </tt>
646 <dd>
647         Decrement the reference count of an exception.
648         If it reaches 0, free the exception object.
649         <p>
650 <dt>
651 <tt> bool sm_exc_match(SM_EXC_T *exc, const char *pattern) </tt>
652 <dd>
653         Compare the exception's category to the specified glob pattern,
654         return true if they match.
655         <p>
656 <dt>
657 <tt> void sm_exc_print(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
658 <dd>
659         Print the exception on the stream
660         as a sequence of one or more newline terminated lines.
661         <p>
662 <dt>
663 <tt> void sm_exc_write(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
664 <dd>
665         Write the exception on the stream without a terminating newline.
666         <p>
667 <dt>
668 <tt> void sm_exc_raise_x(SM_EXC_T *exc) </tt>
669 <dd>
670         Raise the exception.  This function does not return to its caller.
671         <p>
672 <dt>
673 <tt> void sm_exc_raisenew_x(const SM_EXC_TYPE_T *type, ...) </tt>
674 <dd>
675         A short form for <tt>sm_exc_raise_x(sm_exc_new_x(type,...))</tt>.
676 </dl>
677
678 <h2> Macro Reference </h2>
679
680 The SM_TRY ... SM_END_TRY control structure
681 ensures that cleanup code is executed in the presence of exceptions,
682 and permits exceptions to be handled.
683
684 <blockquote><pre>
685 SM_TRY
686         A block of code that may raise an exception.
687 SM_FINALLY
688         Cleanup code that may raise an exception.
689         This code is guaranteed to be executed whether or not
690         an exception was raised by a previous clause.
691         You may have 0 or more SM_FINALLY clauses.
692 SM_EXCEPT(e, pat)
693         Exception handling code, which is triggered by an exception
694         whose category matches the glob pattern 'pat'.
695         The exception value is bound to the local variable 'e'.
696         You may have 0 or more SM_EXCEPT clauses.
697 SM_END_TRY
698 </pre></blockquote>
699
700 First, the SM_TRY clause is executed, then each SM_FINALLY clause is
701 executed in sequence.
702 If one or more of these clauses was terminated by an exception,
703 then the first such exception is remembered, and the other exceptions
704 are lost.
705
706 If no exception was raised, then we are done.
707
708 Otherwise, each of the SM_EXCEPT clauses is examined in sequence.
709 and the first SM_EXCEPT clause whose pattern argument matches the exception
710 (see <tt>sm_exc_match</tt>) is executed.
711 If none of the SM_EXCEPT clauses matched the exception, or if there are
712 no SM_EXCEPT clauses, then the remembered exception is re-raised.
713
714 <p>
715 SM_TRY .. SM_END_TRY clauses may be nested arbitrarily.
716
717 <p>
718 It is illegal to jump out of a SM_TRY or SM_FINALLY clause
719 using goto, break, continue, return or longjmp.
720 If you do this, you will corrupt the internal exception handling stack.
721 You can't use <tt>break</tt> or <tt>continue</tt> in an SM_EXCEPT clause;
722 these are reserved for use by the implementation.
723 It is legal to jump out of an SM_EXCEPT clause using goto or return;
724 however, in this case, you must take responsibility
725 for freeing the exception object.
726
727 <p>
728 The SM_TRY and SM_FINALLY macros contain calls to setjmp,
729 and consequently, they suffer from the limitations imposed on setjmp
730 by the C standard.
731 Suppose you declare an auto variable <tt>i</tt> outside of a
732 SM_TRY ... SM_END_TRY statement, initializing it to 0.
733 Then you modify <tt>i</tt> inside of a SM_TRY or SM_FINALLY clause,
734 setting it to 1.
735 If you reference <tt>i</tt> in a different SM_FINALLY clause, or in
736 an SM_EXCEPT clause, then it is implementation dependent whether <tt>i</tt>
737 will be 0 or 1, unless you have declared <tt>i</tt> to be <tt>volatile</tt>.
738
739 <blockquote><pre>
740 int volatile i = 0;
741
742 SM_TRY
743         i = 1;
744         ...
745 SM_FINALLY
746         /* the following reference to i only works if i is declared volatile */
747         use(i);
748         ...
749 SM_EXCEPT(exc, "*")
750         /* the following reference to i only works if i is declared volatile */
751         use(i);
752         ...
753 SM_END_TRY
754 </pre></blockquote>
755
756 </body>
757 </html>