xref: /freebsd/contrib/sendmail/libsm/exc.html (revision d39bd2c1388b520fcba9abed1932acacead60fba)
140266059SGregory Neil Shapiro<html>
240266059SGregory Neil Shapiro<head>
340266059SGregory Neil Shapiro    <title>libsm : Exception Handling</title>
440266059SGregory Neil Shapiro</head>
540266059SGregory Neil Shapiro<body>
640266059SGregory Neil Shapiro
740266059SGregory Neil Shapiro<a href="index.html">Back to libsm overview</a>
840266059SGregory Neil Shapiro
940266059SGregory Neil Shapiro<center>
1040266059SGregory Neil Shapiro    <h1> libsm : Exception Handling </h1>
114313cc83SGregory Neil Shapiro    <br> $Id: exc.html,v 1.13 2006-06-20 17:18:16 ca Exp $
1240266059SGregory Neil Shapiro</center>
1340266059SGregory Neil Shapiro
1440266059SGregory Neil Shapiro<h2> Introduction </h2>
1540266059SGregory Neil Shapiro
1640266059SGregory Neil ShapiroThe exception handling package provides the facilities that
1740266059SGregory Neil Shapirofunctions in libsm use to report errors.
1840266059SGregory Neil ShapiroHere are the basic concepts:
1940266059SGregory Neil Shapiro
2040266059SGregory Neil Shapiro<ol>
2140266059SGregory Neil Shapiro<li>
2240266059SGregory Neil Shapiro    When a function detects an exceptional condition at the library level,
2340266059SGregory Neil Shapiro    it does not print an error message, or call syslog, or
2440266059SGregory Neil Shapiro    exit the program.  Instead, it reports the error back to its
2540266059SGregory Neil Shapiro    caller, and lets the caller decide what to do.
2640266059SGregory Neil Shapiro    This improves modularity, because error handling is separated
2740266059SGregory Neil Shapiro    from error reporting.
2840266059SGregory Neil Shapiro    <p>
2940266059SGregory Neil Shapiro<li>
3040266059SGregory Neil Shapiro    Errors are not represented by a single integer error code,
31d0cef73dSGregory Neil Shapiro    because then you can't represent everything that an error handler
3240266059SGregory Neil Shapiro    might need to know about an error by a single integer.
3340266059SGregory Neil Shapiro    Instead, errors are represented by exception objects.
3440266059SGregory Neil Shapiro    An exception object contains an exception code and an array
3540266059SGregory Neil Shapiro    of zero or more exception arguments.
3640266059SGregory Neil Shapiro    The exception code is a string that specifies what kind of exception
3740266059SGregory Neil Shapiro    this is, and the arguments may be integers, strings or exception objects.
3840266059SGregory Neil Shapiro    <p>
3940266059SGregory Neil Shapiro<li>
4040266059SGregory Neil Shapiro    Errors are not reported using a special return value,
4140266059SGregory Neil Shapiro    because if you religiously check for error returns from every
4240266059SGregory Neil Shapiro    function call that could fail, then most of your code ends up being
4340266059SGregory Neil Shapiro    error handling code.  Errors are reported by raising an exception.
4440266059SGregory Neil Shapiro    When an exception is raised, we unwind the call stack
4540266059SGregory Neil Shapiro    until we find an exception handler.  If the exception is
4640266059SGregory Neil Shapiro    not handled, then we print the exception on stderr and
4740266059SGregory Neil Shapiro    exit the program.
4840266059SGregory Neil Shapiro</ol>
4940266059SGregory Neil Shapiro
5040266059SGregory Neil Shapiro<h2> Synopsis </h2>
5140266059SGregory Neil Shapiro
5240266059SGregory Neil Shapiro<pre>
5340266059SGregory Neil Shapiro#include &lt;sm/exc.h&gt;
5440266059SGregory Neil Shapiro
5540266059SGregory Neil Shapirotypedef struct sm_exc_type SM_EXC_TYPE_T;
5640266059SGregory Neil Shapirotypedef struct sm_exc SM_EXC_T;
5740266059SGregory Neil Shapirotypedef union sm_val SM_VAL_T;
5840266059SGregory Neil Shapiro
5940266059SGregory Neil Shapiro/*
6040266059SGregory Neil Shapiro**  Exception types
6140266059SGregory Neil Shapiro*/
6240266059SGregory Neil Shapiro
6340266059SGregory Neil Shapiroextern const char SmExcTypeMagic[];
6440266059SGregory Neil Shapiro
6540266059SGregory Neil Shapirostruct sm_exc_type
6640266059SGregory Neil Shapiro{
6740266059SGregory Neil Shapiro	const char	*sm_magic;
6840266059SGregory Neil Shapiro	const char	*etype_category;
6940266059SGregory Neil Shapiro	const char	*etype_argformat;
7040266059SGregory Neil Shapiro	void 		(*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream);
7140266059SGregory Neil Shapiro	const char	*etype_printcontext;
7240266059SGregory Neil Shapiro};
7340266059SGregory Neil Shapiro
7440266059SGregory Neil Shapiroextern const SM_EXC_TYPE_T SmEtypeOs;
7540266059SGregory Neil Shapiroextern const SM_EXC_TYPE_T SmEtypeErr;
7640266059SGregory Neil Shapiro
7740266059SGregory Neil Shapirovoid
7840266059SGregory Neil Shapirosm_etype_printf(
7940266059SGregory Neil Shapiro	SM_EXC_T *exc,
8040266059SGregory Neil Shapiro	SM_FILE_T *stream);
8140266059SGregory Neil Shapiro
8240266059SGregory Neil Shapiro/*
8340266059SGregory Neil Shapiro**  Exception objects
8440266059SGregory Neil Shapiro*/
8540266059SGregory Neil Shapiro
8640266059SGregory Neil Shapiroextern const char SmExcMagic[];
8740266059SGregory Neil Shapiro
8840266059SGregory Neil Shapirounion sm_val
8940266059SGregory Neil Shapiro{
9040266059SGregory Neil Shapiro	int		v_int;
9140266059SGregory Neil Shapiro	long		v_long;
9240266059SGregory Neil Shapiro	char		*v_str;
9340266059SGregory Neil Shapiro	SM_EXC_T	*v_exc;
9440266059SGregory Neil Shapiro};
9540266059SGregory Neil Shapiro
9640266059SGregory Neil Shapirostruct sm_exc
9740266059SGregory Neil Shapiro{
9840266059SGregory Neil Shapiro	const char		*sm_magic;
9940266059SGregory Neil Shapiro	size_t			exc_refcount;
10040266059SGregory Neil Shapiro	const SM_EXC_TYPE_T	*exc_type;
10140266059SGregory Neil Shapiro	SM_VAL_T		*exc_argv;
10240266059SGregory Neil Shapiro};
10340266059SGregory Neil Shapiro
10440266059SGregory Neil ShapiroSM_EXC_T *
10540266059SGregory Neil Shapirosm_exc_new_x(
10640266059SGregory Neil Shapiro	const SM_EXC_TYPE_T *type,
10740266059SGregory Neil Shapiro	...);
10840266059SGregory Neil Shapiro
10940266059SGregory Neil ShapiroSM_EXC_T *
11040266059SGregory Neil Shapirosm_exc_addref(
11140266059SGregory Neil Shapiro	SM_EXC_T *exc);
11240266059SGregory Neil Shapiro
11340266059SGregory Neil Shapirovoid
11440266059SGregory Neil Shapirosm_exc_free(
11540266059SGregory Neil Shapiro	SM_EXC_T *exc);
11640266059SGregory Neil Shapiro
11740266059SGregory Neil Shapirobool
11840266059SGregory Neil Shapirosm_exc_match(
11940266059SGregory Neil Shapiro	SM_EXC_T *exc,
12040266059SGregory Neil Shapiro	const char *pattern);
12140266059SGregory Neil Shapiro
12240266059SGregory Neil Shapirovoid
12340266059SGregory Neil Shapirosm_exc_print(
12440266059SGregory Neil Shapiro	SM_EXC_T *exc,
12540266059SGregory Neil Shapiro	SM_FILE_T *stream);
12640266059SGregory Neil Shapiro
12740266059SGregory Neil Shapirovoid
12840266059SGregory Neil Shapirosm_exc_write(
12940266059SGregory Neil Shapiro	SM_EXC_T *exc,
13040266059SGregory Neil Shapiro	SM_FILE_T *stream);
13140266059SGregory Neil Shapiro
13240266059SGregory Neil Shapirovoid
13340266059SGregory Neil Shapirosm_exc_raise_x(
13440266059SGregory Neil Shapiro	SM_EXC_T *exc);
13540266059SGregory Neil Shapiro
13640266059SGregory Neil Shapirovoid
13740266059SGregory Neil Shapirosm_exc_raisenew_x(
13840266059SGregory Neil Shapiro	const SM_EXC_TYPE_T *type,
13940266059SGregory Neil Shapiro	...);
14040266059SGregory Neil Shapiro
14140266059SGregory Neil Shapiro/*
14240266059SGregory Neil Shapiro**  Ensure that cleanup code is executed,
14340266059SGregory Neil Shapiro**  and/or handle an exception.
14440266059SGregory Neil Shapiro*/
14540266059SGregory Neil ShapiroSM_TRY
14640266059SGregory Neil Shapiro	Block of code that may raise an exception.
14740266059SGregory Neil ShapiroSM_FINALLY
14840266059SGregory Neil Shapiro	Cleanup code that may raise an exception.
14940266059SGregory Neil Shapiro	This clause is guaranteed to be executed even if an exception is
15040266059SGregory Neil Shapiro	raised by the SM_TRY clause or by an earlier SM_FINALLY clause.
15140266059SGregory Neil Shapiro	You may have 0 or more SM_FINALLY clauses.
15240266059SGregory Neil ShapiroSM_EXCEPT(exc, pattern)
15340266059SGregory Neil Shapiro	Exception handling code, triggered by an exception
15440266059SGregory Neil Shapiro	whose category matches 'pattern'.
15540266059SGregory Neil Shapiro	You may have 0 or more SM_EXCEPT clauses.
15640266059SGregory Neil ShapiroSM_END_TRY
15740266059SGregory Neil Shapiro</pre>
15840266059SGregory Neil Shapiro
15940266059SGregory Neil Shapiro<h2> Overview </h2>
16040266059SGregory Neil Shapiro
16140266059SGregory Neil Shapiro    An exception is an object which represents an exceptional condition,
16240266059SGregory Neil Shapiro    which might be an error condition like "out of memory", or might be
16340266059SGregory Neil Shapiro    a condition like "end of file".
16440266059SGregory Neil Shapiro<p>
16540266059SGregory Neil Shapiro    Functions in libsm report errors and other unusual conditions by
16640266059SGregory Neil Shapiro    raising an exception, rather than by returning an error code or
16740266059SGregory Neil Shapiro    setting a global variable such as errno.  If a libsm function is
16840266059SGregory Neil Shapiro    capable of raising an exception, its name ends in "_x".
16940266059SGregory Neil Shapiro    (We do not raise an exception when a bug is detected in the
17040266059SGregory Neil Shapiro    program; instead, we terminate the program using <tt>sm_abort</tt>.
17140266059SGregory Neil Shapiro    See <a href="assert.html">the assertion package</a>
17240266059SGregory Neil Shapiro    for details.)
17340266059SGregory Neil Shapiro<p>
17440266059SGregory Neil Shapiro    When you are using the libsm exception handling package,
17540266059SGregory Neil Shapiro    you are using a new programming paradigm.
17640266059SGregory Neil Shapiro    You will need to abandon some of the programming idioms
17740266059SGregory Neil Shapiro    you are accustomed to, and switch to new idioms.
17840266059SGregory Neil Shapiro    Here is an overview of some of these idioms.
17940266059SGregory Neil Shapiro<ol>
18040266059SGregory Neil Shapiro<li>
18140266059SGregory Neil Shapiro	When a function is unable to complete its task because
18240266059SGregory Neil Shapiro	of an exceptional condition, it reports this condition
18340266059SGregory Neil Shapiro	by raising an exception.
18440266059SGregory Neil Shapiro	<p>
18540266059SGregory Neil Shapiro	Here is an example of how to construct an exception object
18640266059SGregory Neil Shapiro	and raise an exception.
18740266059SGregory Neil Shapiro	In this example, we convert a Unix system error into an exception.
18840266059SGregory Neil Shapiro<blockquote><pre>
18940266059SGregory Neil Shapirofd = open(path, O_RDONLY);
19040266059SGregory Neil Shapiroif (fd == -1)
19140266059SGregory Neil Shapiro	sm_exc_raise_x(sm_exc_new_x(&SmEtypeOs, errno, "open", "%s", path));
19240266059SGregory Neil Shapiro</pre></blockquote>
19340266059SGregory Neil Shapiro
19440266059SGregory Neil Shapiro	Because the idiom <tt>sm_exc_raise_x(sm_exc_new_x(...))</tt>
19540266059SGregory Neil Shapiro	is so common, it can be abbreviated as <tt>sm_exc_raisenew_x(...)</tt>.
19640266059SGregory Neil Shapiro<p>
19740266059SGregory Neil Shapiro<li>
19840266059SGregory Neil Shapiro	When you detect an error at the application level,
19940266059SGregory Neil Shapiro	you don't call a function like BSD's <tt>errx</tt>,
20040266059SGregory Neil Shapiro	which prints an error message on stderr and exits the program.
20140266059SGregory Neil Shapiro	Instead, you raise an exception.
20240266059SGregory Neil Shapiro	This causes cleanup code in surrounding exception handlers
20340266059SGregory Neil Shapiro	to be run before the program exits.
20440266059SGregory Neil Shapiro	For example, instead of this:
20540266059SGregory Neil Shapiro<blockquote><pre>
20640266059SGregory Neil Shapiroerrx(1, "%s:%d: syntax error", filename, lineno);
20740266059SGregory Neil Shapiro</pre></blockquote>
20840266059SGregory Neil Shapiro
20940266059SGregory Neil Shapiro	use this:
21040266059SGregory Neil Shapiro
21140266059SGregory Neil Shapiro<blockquote><pre>
21240266059SGregory Neil Shapirosm_exc_raisenew_x(&SmEtypeErr, "%s:%d: syntax error", filename, lineno);
21340266059SGregory Neil Shapiro</pre></blockquote>
21440266059SGregory Neil Shapiro
21540266059SGregory Neil Shapiro	The latter code raises an exception, unwinding the call stack
21640266059SGregory Neil Shapiro	and executing cleanup code.
21740266059SGregory Neil Shapiro	If the exception is not handled, then the exception is printed
21840266059SGregory Neil Shapiro	to stderr and the program exits.
21940266059SGregory Neil Shapiro	The end result is substantially the same as a call to <tt>errx</tt>.
22040266059SGregory Neil Shapiro<p>
22140266059SGregory Neil Shapiro<li>
22240266059SGregory Neil Shapiro        The SM_TRY ... SM_FINALLY ... control structure
22340266059SGregory Neil Shapiro	ensures that cleanup code is executed and resources are released
22440266059SGregory Neil Shapiro	in the presence of exceptions.
22540266059SGregory Neil Shapiro<p>
22640266059SGregory Neil Shapiro	For example, suppose that you have written the following code:
22740266059SGregory Neil Shapiro
22840266059SGregory Neil Shapiro<blockquote><pre>
22940266059SGregory Neil Shapirorpool = sm_rpool_new_x(&SmRpoolRoot, 0);
23040266059SGregory Neil Shapiro... some code ...
23140266059SGregory Neil Shapirosm_rpool_free_x(rpool);
23240266059SGregory Neil Shapiro</pre></blockquote>
23340266059SGregory Neil Shapiro
23440266059SGregory Neil Shapiro	If any of the functions called within "... some code ..." have
23540266059SGregory Neil Shapiro	names ending in _x, then it is possible that an exception will be
23640266059SGregory Neil Shapiro	raised, and if that happens, then "rpool" will not be freed.
23740266059SGregory Neil Shapiro	And that's a bug.  To fix this bug, change your code so it looks
23840266059SGregory Neil Shapiro	like this:
23940266059SGregory Neil Shapiro
24040266059SGregory Neil Shapiro<blockquote><pre>
24140266059SGregory Neil Shapirorpool = sm_rpool_new_x(&SmRpoolRoot, 0);
24240266059SGregory Neil ShapiroSM_TRY
24340266059SGregory Neil Shapiro	... some code that can raise an exception ...
24440266059SGregory Neil ShapiroSM_FINALLY
24540266059SGregory Neil Shapiro	sm_rpool_free_x(rpool);
24640266059SGregory Neil ShapiroSM_END_TRY
24740266059SGregory Neil Shapiro</pre></blockquote>
24840266059SGregory Neil Shapiro
24940266059SGregory Neil Shapiro<li>
25040266059SGregory Neil Shapiro	The SM_TRY ... SM_EXCEPT ... control structure handles an exception.
25140266059SGregory Neil Shapiro	Unhandled exceptions terminate the program.
25240266059SGregory Neil Shapiro	For example, here is a simple exception handler
25340266059SGregory Neil Shapiro	that traps all exceptions, and prints the exceptions:
25440266059SGregory Neil Shapiro
25540266059SGregory Neil Shapiro<blockquote><pre>
25640266059SGregory Neil ShapiroSM_TRY
25740266059SGregory Neil Shapiro	/* code that can raise an exception */
25840266059SGregory Neil Shapiro	...
25940266059SGregory Neil ShapiroSM_EXCEPT(exc, "*")
26040266059SGregory Neil Shapiro	/* catch all exceptions */
26140266059SGregory Neil Shapiro	sm_exc_print(exc, stderr);
26240266059SGregory Neil ShapiroSM_END_TRY
26340266059SGregory Neil Shapiro</pre></blockquote>
26440266059SGregory Neil Shapiro
26540266059SGregory Neil Shapiro    Exceptions are reference counted.  The SM_END_TRY macro contains a
26640266059SGregory Neil Shapiro    call to sm_exc_free, so you don't normally need to worry about freeing
26740266059SGregory Neil Shapiro    an exception after handling it.  In the rare case that you want an
26840266059SGregory Neil Shapiro    exception to outlive an exception handler, then you increment its
26940266059SGregory Neil Shapiro    reference count by calling sm_exc_addref.
27040266059SGregory Neil Shapiro<p>
27140266059SGregory Neil Shapiro<li>
27240266059SGregory Neil Shapiro    The second argument of the SM_EXCEPT macro is a glob pattern
27340266059SGregory Neil Shapiro    which specifies the types of exceptions that are to be handled.
27440266059SGregory Neil Shapiro    For example, you might want to handle an end-of-file exception
27540266059SGregory Neil Shapiro    differently from other exceptions.
27640266059SGregory Neil Shapiro    Here's how you do that:
27740266059SGregory Neil Shapiro
27840266059SGregory Neil Shapiro<blockquote><pre>
27940266059SGregory Neil ShapiroSM_TRY
28040266059SGregory Neil Shapiro	/* code that might raise end-of-file, or some other exception */
28140266059SGregory Neil Shapiro	...
28240266059SGregory Neil ShapiroSM_EXCEPT(exc, "E:sm.eof")
28340266059SGregory Neil Shapiro	/* what to do if end-of-file is encountered */
28440266059SGregory Neil Shapiro	...
28540266059SGregory Neil ShapiroSM_EXCEPT(exc, "*")
28640266059SGregory Neil Shapiro	/* what to do if some other exception is raised */
28740266059SGregory Neil Shapiro	...
28840266059SGregory Neil ShapiroSM_END_TRY
28940266059SGregory Neil Shapiro</pre></blockquote>
29040266059SGregory Neil Shapiro</ol>
29140266059SGregory Neil Shapiro
29240266059SGregory Neil Shapiro<h2> Exception Values </h2>
29340266059SGregory Neil Shapiro
29440266059SGregory Neil ShapiroIn traditional C code, errors are usually denoted by a single integer,
29540266059SGregory Neil Shapirosuch as errno.  In practice, errno does not carry enough information
29640266059SGregory Neil Shapiroto describe everything that an error handler might want to know about
29740266059SGregory Neil Shapiroan error.  And the scheme is not very extensible: if several different
29840266059SGregory Neil Shapiropackages want to add additional error codes, it is hard to avoid
29940266059SGregory Neil Shapirocollisions.
30040266059SGregory Neil Shapiro
30140266059SGregory Neil Shapiro<p>
30240266059SGregory Neil ShapiroIn libsm, an exceptional condition is described
30340266059SGregory Neil Shapiroby an object of type SM_EXC_T.
30440266059SGregory Neil ShapiroAn exception object is created by specifying an exception type
30540266059SGregory Neil Shapiroand a list of exception arguments.
30640266059SGregory Neil Shapiro
30740266059SGregory Neil Shapiro<p>
30840266059SGregory Neil ShapiroThe exception arguments are an array of zero or more values.
30940266059SGregory Neil ShapiroThe values may be a mixture of ints, longs, strings, and exceptions.
31040266059SGregory Neil ShapiroIn the SM_EXC_T structure, the argument vector is represented
31140266059SGregory Neil Shapiroby <tt>SM_VAL_T&nbsp;*exc_argv</tt>, where <tt>SM_VAL_T</tt>
31240266059SGregory Neil Shapirois a union of the possible argument types.
31340266059SGregory Neil ShapiroThe number and types of exception arguments is determined by
31440266059SGregory Neil Shapirothe exception type.
31540266059SGregory Neil Shapiro
31640266059SGregory Neil Shapiro<p>
31740266059SGregory Neil ShapiroAn exception type is a statically initialized const object
31840266059SGregory Neil Shapiroof type SM_EXC_TYPE_T, which has the following members:
31940266059SGregory Neil Shapiro
32040266059SGregory Neil Shapiro<dl>
32140266059SGregory Neil Shapiro<dt>
32240266059SGregory Neil Shapiro<tt> const char *sm_magic </tt>
32340266059SGregory Neil Shapiro<dd>
32440266059SGregory Neil Shapiro	A pointer to <tt>SmExcTypeMagic</tt>.
32540266059SGregory Neil Shapiro	<p>
32640266059SGregory Neil Shapiro<dt>
32740266059SGregory Neil Shapiro<tt> const char *etype_category </tt>
32840266059SGregory Neil Shapiro<dd>
32940266059SGregory Neil Shapiro	This is a string of the form
33040266059SGregory Neil Shapiro	<tt>"</tt><i>class</i><tt>:</tt><i>name</i><tt>"</tt>.
33140266059SGregory Neil Shapiro	<p>
33240266059SGregory Neil Shapiro	The <i>class</i> is used to assign the exception type to
33340266059SGregory Neil Shapiro	one of a number of broad categories of exceptions on which an
33440266059SGregory Neil Shapiro	exception handler might want to discriminate.
33540266059SGregory Neil Shapiro	I suspect that what we want is a hierarchical taxonomy,
33640266059SGregory Neil Shapiro	but I don't have a full design for this yet.
33740266059SGregory Neil Shapiro	For now, I am recommending the following classes:
33840266059SGregory Neil Shapiro	<dl>
33940266059SGregory Neil Shapiro	<dt><tt>"F"</tt>
34040266059SGregory Neil Shapiro	<dd>A fatal error has occurred.
34140266059SGregory Neil Shapiro	    This is an error that prevents the application
34240266059SGregory Neil Shapiro	    from making any further progress, so the only
34340266059SGregory Neil Shapiro	    recourse is to raise an exception, execute cleanup code
34440266059SGregory Neil Shapiro	    as the stack is unwound, then exit the application.
34540266059SGregory Neil Shapiro	    The out-of-memory exception raised by sm_malloc_x
34640266059SGregory Neil Shapiro	    has category "F:sm.heap" because sendmail commits suicide
34740266059SGregory Neil Shapiro	    (after logging the error and cleaning up) when it runs out
34840266059SGregory Neil Shapiro	    of memory.
34940266059SGregory Neil Shapiro
35040266059SGregory Neil Shapiro	<dt><tt>"E"</tt>
35140266059SGregory Neil Shapiro	<dd>The function could not complete its task because an error occurred.
35240266059SGregory Neil Shapiro	    (It might be useful to define subclasses of this category,
353*d39bd2c1SGregory Neil Shapiro	    in which case our taxonomy becomes a tree, and 'F' becomes
35440266059SGregory Neil Shapiro	    a subclass of 'E'.)
35540266059SGregory Neil Shapiro
35640266059SGregory Neil Shapiro	<dt><tt>"J"</tt>
35740266059SGregory Neil Shapiro	<dd>This exception is being raised in order to effect a
35840266059SGregory Neil Shapiro	    non-local jump.  No error has occurred; we are just
35940266059SGregory Neil Shapiro	    performing the non-local equivalent of a <tt>continue</tt>,
36040266059SGregory Neil Shapiro	    <tt>break</tt> or <tt>return</tt>.
36140266059SGregory Neil Shapiro
36240266059SGregory Neil Shapiro	<dt><tt>"S"</tt>
36340266059SGregory Neil Shapiro	<dd>The function was interrupted by a signal.
36440266059SGregory Neil Shapiro	    Signals are not errors because they occur asynchronously,
36540266059SGregory Neil Shapiro	    and they are semantically unrelated to the function that
36640266059SGregory Neil Shapiro	    happens to be executing when the signal arrives.
36740266059SGregory Neil Shapiro	    Note that it is extremely dangerous to raise an exception
36840266059SGregory Neil Shapiro	    from a signal handler.  For example, if you are in the middle
36940266059SGregory Neil Shapiro	    of a call to malloc, you might corrupt the heap.
37040266059SGregory Neil Shapiro	</dl>
37140266059SGregory Neil Shapiro	Eric's libsm paper defines <tt>"W"</tt>, <tt>"D"</tt> and <tt>"I"</tt>
37240266059SGregory Neil Shapiro	for Warning, Debug and Informational:
37340266059SGregory Neil Shapiro	I suspect these categories only make sense in the context of
37440266059SGregory Neil Shapiro	Eric's 1985 exception handling system which allowed you to
37540266059SGregory Neil Shapiro	raise conditions without terminating the calling function.
37640266059SGregory Neil Shapiro	<p>
37740266059SGregory Neil Shapiro	The <i>name</i> uniquely identifies the exception type.
37840266059SGregory Neil Shapiro	I recommend a string of the form
37940266059SGregory Neil Shapiro	<i>library</i><tt>.</tt><i>package</i><tt>.</tt><i>detail</i>.
38040266059SGregory Neil Shapiro	<p>
38140266059SGregory Neil Shapiro<dt>
38240266059SGregory Neil Shapiro<tt> const char *etype_argformat </tt>
38340266059SGregory Neil Shapiro<dd>
38440266059SGregory Neil Shapiro	This is an array of single character codes.
38540266059SGregory Neil Shapiro	Each code indicates the type of one of the exception arguments.
38640266059SGregory Neil Shapiro	<tt>sm_exc_new_x</tt> uses this string to decode its variable
38740266059SGregory Neil Shapiro	argument list into an exception argument vector.
38840266059SGregory Neil Shapiro	The following type codes are supported:
38940266059SGregory Neil Shapiro	<dl>
39040266059SGregory Neil Shapiro	<dt><tt>i</tt>
39140266059SGregory Neil Shapiro	<dd>
39240266059SGregory Neil Shapiro		The exception argument has type <tt>int</tt>.
39340266059SGregory Neil Shapiro	<dt><tt>l</tt>
39440266059SGregory Neil Shapiro	<dd>
39540266059SGregory Neil Shapiro		The exception argument has type <tt>long</tt>.
39640266059SGregory Neil Shapiro	<dt><tt>e</tt>
39740266059SGregory Neil Shapiro	<dd>
39840266059SGregory Neil Shapiro		The exception argument has type <tt>SM_EXC_T*</tt>.
39940266059SGregory Neil Shapiro		The value may either be <tt>NULL</tt> or a pointer
40040266059SGregory Neil Shapiro		to an exception.  The pointer value is simply copied
40140266059SGregory Neil Shapiro		into the exception argument vector.
40240266059SGregory Neil Shapiro	<dt><tt>s</tt>
40340266059SGregory Neil Shapiro	<dd>
40440266059SGregory Neil Shapiro		The exception argument has type <tt>char*</tt>.
40540266059SGregory Neil Shapiro		The value may either be <tt>NULL</tt> or a pointer
40640266059SGregory Neil Shapiro		to a character string.  In the latter case,
40740266059SGregory Neil Shapiro		<tt>sm_exc_new_x</tt> will make a copy of the string.
40840266059SGregory Neil Shapiro	<dt><tt>r</tt>
40940266059SGregory Neil Shapiro	<dd>
41040266059SGregory Neil Shapiro		The exception argument has type <tt>char*</tt>.
41140266059SGregory Neil Shapiro		<tt>sm_exc_new_x</tt> will read a printf-style
41240266059SGregory Neil Shapiro		format string argument followed by a list of printf
41340266059SGregory Neil Shapiro		arguments from its variable argument list, and convert
41440266059SGregory Neil Shapiro		these into a string.
41540266059SGregory Neil Shapiro		This type code can only occur as the last element
41640266059SGregory Neil Shapiro		of <tt>exc_argformat</tt>.
41740266059SGregory Neil Shapiro	</dl>
41840266059SGregory Neil Shapiro	<p>
41940266059SGregory Neil Shapiro<dt>
42040266059SGregory Neil Shapiro<tt> void (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
42140266059SGregory Neil Shapiro<dd>
42240266059SGregory Neil Shapiro	This function prints an exception of the specified type
42340266059SGregory Neil Shapiro	onto an output stream.
42440266059SGregory Neil Shapiro	The final character printed is not a newline.
42540266059SGregory Neil Shapiro</dl>
42640266059SGregory Neil Shapiro
42740266059SGregory Neil Shapiro<h2> Standard Exceptions and Exception Types </h2>
42840266059SGregory Neil Shapiro
42940266059SGregory Neil ShapiroLibsm defines one standard exception value, <tt>SmHeapOutOfMemory</tt>.
43040266059SGregory Neil ShapiroThis is a statically initialized const variable, because it seems
43140266059SGregory Neil Shapirolike a bad idea to dynamically allocate an exception object to
43240266059SGregory Neil Shapiroreport a low memory condition.
43340266059SGregory Neil ShapiroThis exception has category <tt>"F:sm.heap"</tt>.
43440266059SGregory Neil ShapiroIf you need to, you can explicitly raise this exception
43540266059SGregory Neil Shapirowith <tt>sm_exc_raise_x(&SmHeapOutOfMemory)</tt>.
43640266059SGregory Neil Shapiro
43740266059SGregory Neil Shapiro<p>
43840266059SGregory Neil ShapiroStatically initialized exception values cannot contain any
43940266059SGregory Neil Shapirorun-time parameters, so the normal case is to dynamically allocate
44040266059SGregory Neil Shapiroa new exception object whenever you raise an exception.
44140266059SGregory Neil ShapiroBefore you can create an exception, you need an exception type.
44240266059SGregory Neil ShapiroLibsm defines the following standard exception types.
44340266059SGregory Neil Shapiro
44440266059SGregory Neil Shapiro<dl>
44540266059SGregory Neil Shapiro<dt>
44640266059SGregory Neil Shapiro<tt> SmEtypeOs </tt>
44740266059SGregory Neil Shapiro<dd>
44840266059SGregory Neil Shapiro	This represents a generic operating system error.
44940266059SGregory Neil Shapiro	The category is <tt>"E:sm.os"</tt>.
45040266059SGregory Neil Shapiro	The argformat is <tt>"isr"</tt>,
45140266059SGregory Neil Shapiro	where argv[0] is the value of <tt>errno</tt>
45240266059SGregory Neil Shapiro	after a system call has failed,
45340266059SGregory Neil Shapiro	argv[1] is the name of the function (usually a system call) that failed,
45440266059SGregory Neil Shapiro	and argv[2] is either <tt>NULL</tt>
45540266059SGregory Neil Shapiro	or a character string which describes some of the arguments
45640266059SGregory Neil Shapiro	to the failing system call (usually it is just a file name).
45740266059SGregory Neil Shapiro	Here's an example of raising an exception:
45840266059SGregory Neil Shapiro
45940266059SGregory Neil Shapiro<blockquote><pre>
46040266059SGregory Neil Shapirofd = open(filename, O_RDONLY);
46140266059SGregory Neil Shapiroif (fd == -1)
46240266059SGregory Neil Shapiro	sm_exc_raisenew_x(&SmEtypeOs, errno, "open", "%s", filename);
46340266059SGregory Neil Shapiro</pre></blockquote>
46440266059SGregory Neil Shapiro
46540266059SGregory Neil Shapiro	If errno is ENOENT and filename is "/etc/mail/snedmail.cf",
46640266059SGregory Neil Shapiro	then the exception raised by the above code will be printed as
46740266059SGregory Neil Shapiro
46840266059SGregory Neil Shapiro<blockquote><pre>
46940266059SGregory Neil Shapiro/etc/mail/snedmail.cf: open failed: No such file or directory
47040266059SGregory Neil Shapiro</pre></blockquote>
47140266059SGregory Neil Shapiro
47240266059SGregory Neil Shapiro<dt>
47340266059SGregory Neil Shapiro<tt> SmEtypeErr </tt>
47440266059SGregory Neil Shapiro<dd>
47540266059SGregory Neil Shapiro	This represents a generic error.
47640266059SGregory Neil Shapiro	The category is <tt>"E:sm.err"</tt>,
47740266059SGregory Neil Shapiro	and the argformat is <tt>"r"</tt>.
47840266059SGregory Neil Shapiro	You can use it
47940266059SGregory Neil Shapiro	in application contexts where you are raising an exception
48040266059SGregory Neil Shapiro	for the purpose of terminating the program.
48140266059SGregory Neil Shapiro	You know the exception won't be handled,
48240266059SGregory Neil Shapiro	so you don't need to worry about packaging the error for
48340266059SGregory Neil Shapiro	later analysis by an exception handler.
48440266059SGregory Neil Shapiro	All you need to specify is the message string that
48540266059SGregory Neil Shapiro	will be printed to stderr before the program exits.
48640266059SGregory Neil Shapiro	For example,
48740266059SGregory Neil Shapiro
48840266059SGregory Neil Shapiro<blockquote><pre>
48940266059SGregory Neil Shapirosm_exc_raisenew_x(&SmEtypeErr, "name lookup failed: %s", name);
49040266059SGregory Neil Shapiro</pre></blockquote>
49140266059SGregory Neil Shapiro</dl>
49240266059SGregory Neil Shapiro
49340266059SGregory Neil Shapiro<h2> Custom Exception Types </h2>
49440266059SGregory Neil Shapiro
49540266059SGregory Neil ShapiroIf you are writing a library package, and you need to raise
49640266059SGregory Neil Shapiroexceptions that are not standard Unix system errors,
49740266059SGregory Neil Shapirothen you need to define one or more new exception types.
49840266059SGregory Neil Shapiro
49940266059SGregory Neil Shapiro<p>
50040266059SGregory Neil ShapiroEvery new exception type needs a print function.
50140266059SGregory Neil ShapiroThe standard print function <tt>sm_etype_printf</tt>
50240266059SGregory Neil Shapirois all you need in the majority of cases.
50340266059SGregory Neil ShapiroIt prints the <tt>etype_printcontext</tt> string of the exception type,
50440266059SGregory Neil Shapirosubstituting occurrences of %0 through %9 with the corresponding
50540266059SGregory Neil Shapiroexception argument.
50640266059SGregory Neil ShapiroIf exception argument 3 is an int or long,
50740266059SGregory Neil Shapirothen %3 will print the argument in decimal,
50840266059SGregory Neil Shapiroand %o3 or %x3 will print it in octal or hex.
50940266059SGregory Neil Shapiro
51040266059SGregory Neil Shapiro<p>
51140266059SGregory Neil ShapiroIn the following example, I will assume that your library
51240266059SGregory Neil Shapiropackage implements regular expressions, and can raise 5 different exceptions.
51340266059SGregory Neil ShapiroWhen compiling a regular expression, 3 different syntax errors
51440266059SGregory Neil Shapirocan be reported:
51540266059SGregory Neil Shapiro<ul>
51640266059SGregory Neil Shapiro<li>unbalanced parenthesis
51740266059SGregory Neil Shapiro<li>unbalanced bracket
51840266059SGregory Neil Shapiro<li>missing argument for repetition operator
51940266059SGregory Neil Shapiro</ul>
52040266059SGregory Neil ShapiroWhenever one of these errors is reported, you will also report
52140266059SGregory Neil Shapirothe index of the character within the regex string at which the
52240266059SGregory Neil Shapirosyntax error was detected.
52340266059SGregory Neil ShapiroThe fourth exception is raised if a compiled regular expression
52440266059SGregory Neil Shapirois invalid: this exception has no arguments.
52540266059SGregory Neil ShapiroThe fifth exception is raised if the package runs out of memory:
52640266059SGregory Neil Shapirofor this, you use the standard <tt>SmHeapOutOfMemory</tt> exception.
52740266059SGregory Neil Shapiro
52840266059SGregory Neil Shapiro<p>
52940266059SGregory Neil ShapiroThe obvious approach is to define 4 separate exception types.
53040266059SGregory Neil ShapiroHere they are:
53140266059SGregory Neil Shapiro
53240266059SGregory Neil Shapiro<blockquote><pre>
53340266059SGregory Neil Shapiro/* print a regular expression syntax error */
53440266059SGregory Neil Shapirovoid
53540266059SGregory Neil Shapirorx_esyntax_print(SM_EXC_T *exc, SM_FILE_T *stream)
53640266059SGregory Neil Shapiro{
53740266059SGregory Neil Shapiro	sm_io_fprintf(stream, "rx syntax error at character %d: %s",
53840266059SGregory Neil Shapiro		exc-&gt;exc_argv[0].v_int,
53940266059SGregory Neil Shapiro		exc-&gt;exc_type-&gt;etype_printcontext);
54040266059SGregory Neil Shapiro}
54140266059SGregory Neil ShapiroSM_EXC_TYPE_T RxSyntaxParen = {
54240266059SGregory Neil Shapiro	SmExcTypeMagic,
54340266059SGregory Neil Shapiro	"E:mylib.rx.syntax.paren",
54440266059SGregory Neil Shapiro	"i",
54540266059SGregory Neil Shapiro	rx_esyntax_print,
54640266059SGregory Neil Shapiro	"unbalanced parenthesis"
54740266059SGregory Neil Shapiro};
54840266059SGregory Neil ShapiroSM_EXC_TYPE_T RxSyntaxBracket = {
54940266059SGregory Neil Shapiro	SmExcTypeMagic,
55040266059SGregory Neil Shapiro	"E:mylib.rx.syntax.bracket",
55140266059SGregory Neil Shapiro	"i",
55240266059SGregory Neil Shapiro	rx_esyntax_print,
55340266059SGregory Neil Shapiro	"unbalanced bracket"
55440266059SGregory Neil Shapiro};
55540266059SGregory Neil ShapiroSM_EXC_TYPE_T RxSyntaxMissingArg = {
55640266059SGregory Neil Shapiro	SmExcTypeMagic,
55740266059SGregory Neil Shapiro	"E:mylib.rx.syntax.missingarg",
55840266059SGregory Neil Shapiro	"i",
55940266059SGregory Neil Shapiro	rx_esyntax_print,
56040266059SGregory Neil Shapiro	"missing argument for repetition operator"
56140266059SGregory Neil Shapiro};
56240266059SGregory Neil Shapiro
56340266059SGregory Neil ShapiroSM_EXC_TYPE_T RxRunCorrupt = {
56440266059SGregory Neil Shapiro	SmExcTypeMagic,
56540266059SGregory Neil Shapiro	"E:mylib.rx.run.corrupt",
56640266059SGregory Neil Shapiro	"",
56740266059SGregory Neil Shapiro	sm_etype_printf,
56840266059SGregory Neil Shapiro	"rx runtime error: compiled regular expression is corrupt"
56940266059SGregory Neil Shapiro};
57040266059SGregory Neil Shapiro</pre></blockquote>
57140266059SGregory Neil Shapiro
57240266059SGregory Neil Shapiro<p>
57340266059SGregory Neil ShapiroWith the above definitions, you can raise a syntax error reporting
57440266059SGregory Neil Shapiroan unbalanced parenthesis at string offset <tt>i</tt> using:
57540266059SGregory Neil Shapiro<blockquote><pre>
57640266059SGregory Neil Shapirosm_exc_raisenew_x(&RxSyntaxParen, i);
57740266059SGregory Neil Shapiro</pre></blockquote>
57840266059SGregory Neil Shapiro
57940266059SGregory Neil ShapiroIf <tt>i==42</tt> then this exception will be printed as:
58040266059SGregory Neil Shapiro<blockquote><pre>
58140266059SGregory Neil Shapirorx syntax error at character 42: unbalanced parenthesis
58240266059SGregory Neil Shapiro</pre></blockquote>
58340266059SGregory Neil Shapiro
58440266059SGregory Neil ShapiroAn exception handler can provide special handling for regular
58540266059SGregory Neil Shapiroexpression syntax errors using this code:
58640266059SGregory Neil Shapiro<blockquote><pre>
58740266059SGregory Neil ShapiroSM_TRY
58840266059SGregory Neil Shapiro	... code that might raise an exception ...
58940266059SGregory Neil ShapiroSM_EXCEPT(exc, "E:mylib.rx.syntax.*")
59040266059SGregory Neil Shapiro	int i = exc-&gt;exc_argv[0].v_int;
59140266059SGregory Neil Shapiro	... handle a regular expression syntax error ...
59240266059SGregory Neil ShapiroSM_END_TRY
59340266059SGregory Neil Shapiro</pre></blockquote>
59440266059SGregory Neil Shapiro
59540266059SGregory Neil Shapiro<p>
59640266059SGregory Neil ShapiroExternal requirements may force you to define an integer code
59740266059SGregory Neil Shapirofor each error reported by your package.  Or you may be wrapping
59840266059SGregory Neil Shapiroan existing package that works this way.  In this case, it might
59940266059SGregory Neil Shapiromake sense to define a single exception type, patterned after SmEtypeOs,
60040266059SGregory Neil Shapiroand include the integer code as an exception argument.
60140266059SGregory Neil Shapiro
60240266059SGregory Neil Shapiro<p>
60340266059SGregory Neil ShapiroYour package might intercept an exception E generated by a lower
60440266059SGregory Neil Shapirolevel package, and then reclassify it as a different expression E'.
60540266059SGregory Neil ShapiroFor example, a package for reading a configuration file might
60640266059SGregory Neil Shapiroreclassify one of the regular expression syntax errors from the
60740266059SGregory Neil Shapiroprevious example as a configuration file syntax error.
60840266059SGregory Neil ShapiroWhen you do this, the new exception E' should include the original
60940266059SGregory Neil Shapiroexception E as an exception parameter, and the print function for
61040266059SGregory Neil Shapiroexception E' should print the high level description of the exception
61140266059SGregory Neil Shapiro(eg, "syntax error in configuration file %s at line %d\n"),
61240266059SGregory Neil Shapirothen print the subexception that is stored as an exception parameter.
61340266059SGregory Neil Shapiro
61440266059SGregory Neil Shapiro<h2> Function Reference </h2>
61540266059SGregory Neil Shapiro
61640266059SGregory Neil Shapiro<dl>
61740266059SGregory Neil Shapiro<dt>
61840266059SGregory Neil Shapiro<tt> SM_EXC_T *sm_exc_new_x(const SM_EXC_TYPE_T *type, ...) </tt>
61940266059SGregory Neil Shapiro<dd>
62040266059SGregory Neil Shapiro	Create a new exception.  Raise an exception on heap exhaustion.
62140266059SGregory Neil Shapiro	The new exception has a reference count of 1.
62240266059SGregory Neil Shapiro	<p>
62340266059SGregory Neil Shapiro
62440266059SGregory Neil Shapiro	A list of zero or more exception arguments follows the exception type;
62540266059SGregory Neil Shapiro	these are copied into the new exception object.
62640266059SGregory Neil Shapiro	The number and types of these arguments is determined
62740266059SGregory Neil Shapiro	by <tt>type-&gt;etype_argformat</tt>.
62840266059SGregory Neil Shapiro	<p>
62940266059SGregory Neil Shapiro
63040266059SGregory Neil Shapiro	Note that there is no rpool argument to sm_exc_new_x.
63140266059SGregory Neil Shapiro	Exceptions are allocated directly from the heap.
63240266059SGregory Neil Shapiro	This is because exceptions are normally raised at low levels
63340266059SGregory Neil Shapiro	of abstraction and handled at high levels.  Because the low
63440266059SGregory Neil Shapiro	level code typically has no idea of how or at what level the
63540266059SGregory Neil Shapiro	exception will be handled, it also has no idea of which resource
63640266059SGregory Neil Shapiro	pool, if any, should own the exception.
63740266059SGregory Neil Shapiro	<p>
63840266059SGregory Neil Shapiro<dt>
63940266059SGregory Neil Shapiro<tt> SM_EXC_T *sm_exc_addref(SM_EXC_T *exc) </tt>
64040266059SGregory Neil Shapiro<dd>
64140266059SGregory Neil Shapiro	Increment the reference count of an exception.
64240266059SGregory Neil Shapiro	Return the first argument.
64340266059SGregory Neil Shapiro	<p>
64440266059SGregory Neil Shapiro<dt>
64540266059SGregory Neil Shapiro<tt> void sm_exc_free(SM_EXC_T *exc) </tt>
64640266059SGregory Neil Shapiro<dd>
64740266059SGregory Neil Shapiro	Decrement the reference count of an exception.
64840266059SGregory Neil Shapiro	If it reaches 0, free the exception object.
64940266059SGregory Neil Shapiro	<p>
65040266059SGregory Neil Shapiro<dt>
65140266059SGregory Neil Shapiro<tt> bool sm_exc_match(SM_EXC_T *exc, const char *pattern) </tt>
65240266059SGregory Neil Shapiro<dd>
65340266059SGregory Neil Shapiro	Compare the exception's category to the specified glob pattern,
65440266059SGregory Neil Shapiro	return true if they match.
65540266059SGregory Neil Shapiro	<p>
65640266059SGregory Neil Shapiro<dt>
65740266059SGregory Neil Shapiro<tt> void sm_exc_print(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
65840266059SGregory Neil Shapiro<dd>
65940266059SGregory Neil Shapiro	Print the exception on the stream
66040266059SGregory Neil Shapiro	as a sequence of one or more newline terminated lines.
66140266059SGregory Neil Shapiro	<p>
66240266059SGregory Neil Shapiro<dt>
66340266059SGregory Neil Shapiro<tt> void sm_exc_write(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
66440266059SGregory Neil Shapiro<dd>
66540266059SGregory Neil Shapiro	Write the exception on the stream without a terminating newline.
66640266059SGregory Neil Shapiro	<p>
66740266059SGregory Neil Shapiro<dt>
66840266059SGregory Neil Shapiro<tt> void sm_exc_raise_x(SM_EXC_T *exc) </tt>
66940266059SGregory Neil Shapiro<dd>
67040266059SGregory Neil Shapiro	Raise the exception.  This function does not return to its caller.
67140266059SGregory Neil Shapiro	<p>
67240266059SGregory Neil Shapiro<dt>
67340266059SGregory Neil Shapiro<tt> void sm_exc_raisenew_x(const SM_EXC_TYPE_T *type, ...) </tt>
67440266059SGregory Neil Shapiro<dd>
67540266059SGregory Neil Shapiro	A short form for <tt>sm_exc_raise_x(sm_exc_new_x(type,...))</tt>.
67640266059SGregory Neil Shapiro</dl>
67740266059SGregory Neil Shapiro
67840266059SGregory Neil Shapiro<h2> Macro Reference </h2>
67940266059SGregory Neil Shapiro
68040266059SGregory Neil ShapiroThe SM_TRY ... SM_END_TRY control structure
68140266059SGregory Neil Shapiroensures that cleanup code is executed in the presence of exceptions,
68240266059SGregory Neil Shapiroand permits exceptions to be handled.
68340266059SGregory Neil Shapiro
68440266059SGregory Neil Shapiro<blockquote><pre>
68540266059SGregory Neil ShapiroSM_TRY
68640266059SGregory Neil Shapiro	A block of code that may raise an exception.
68740266059SGregory Neil ShapiroSM_FINALLY
68840266059SGregory Neil Shapiro	Cleanup code that may raise an exception.
68940266059SGregory Neil Shapiro	This code is guaranteed to be executed whether or not
69040266059SGregory Neil Shapiro	an exception was raised by a previous clause.
69140266059SGregory Neil Shapiro	You may have 0 or more SM_FINALLY clauses.
69240266059SGregory Neil ShapiroSM_EXCEPT(e, pat)
69340266059SGregory Neil Shapiro	Exception handling code, which is triggered by an exception
69440266059SGregory Neil Shapiro	whose category matches the glob pattern 'pat'.
69540266059SGregory Neil Shapiro	The exception value is bound to the local variable 'e'.
69640266059SGregory Neil Shapiro	You may have 0 or more SM_EXCEPT clauses.
69740266059SGregory Neil ShapiroSM_END_TRY
69840266059SGregory Neil Shapiro</pre></blockquote>
69940266059SGregory Neil Shapiro
70040266059SGregory Neil ShapiroFirst, the SM_TRY clause is executed, then each SM_FINALLY clause is
70140266059SGregory Neil Shapiroexecuted in sequence.
70240266059SGregory Neil ShapiroIf one or more of these clauses was terminated by an exception,
70340266059SGregory Neil Shapirothen the first such exception is remembered, and the other exceptions
70440266059SGregory Neil Shapiroare lost.
70540266059SGregory Neil Shapiro
70640266059SGregory Neil ShapiroIf no exception was raised, then we are done.
70740266059SGregory Neil Shapiro
70840266059SGregory Neil ShapiroOtherwise, each of the SM_EXCEPT clauses is examined in sequence.
70940266059SGregory Neil Shapiroand the first SM_EXCEPT clause whose pattern argument matches the exception
71040266059SGregory Neil Shapiro(see <tt>sm_exc_match</tt>) is executed.
71140266059SGregory Neil ShapiroIf none of the SM_EXCEPT clauses matched the exception, or if there are
71240266059SGregory Neil Shapirono SM_EXCEPT clauses, then the remembered exception is re-raised.
71340266059SGregory Neil Shapiro
71440266059SGregory Neil Shapiro<p>
71540266059SGregory Neil ShapiroSM_TRY .. SM_END_TRY clauses may be nested arbitrarily.
71640266059SGregory Neil Shapiro
71740266059SGregory Neil Shapiro<p>
71840266059SGregory Neil ShapiroIt is illegal to jump out of a SM_TRY or SM_FINALLY clause
71940266059SGregory Neil Shapirousing goto, break, continue, return or longjmp.
72040266059SGregory Neil ShapiroIf you do this, you will corrupt the internal exception handling stack.
72140266059SGregory Neil ShapiroYou can't use <tt>break</tt> or <tt>continue</tt> in an SM_EXCEPT clause;
72240266059SGregory Neil Shapirothese are reserved for use by the implementation.
72340266059SGregory Neil ShapiroIt is legal to jump out of an SM_EXCEPT clause using goto or return;
72440266059SGregory Neil Shapirohowever, in this case, you must take responsibility
72540266059SGregory Neil Shapirofor freeing the exception object.
72640266059SGregory Neil Shapiro
72740266059SGregory Neil Shapiro<p>
72840266059SGregory Neil ShapiroThe SM_TRY and SM_FINALLY macros contain calls to setjmp,
72940266059SGregory Neil Shapiroand consequently, they suffer from the limitations imposed on setjmp
73040266059SGregory Neil Shapiroby the C standard.
73140266059SGregory Neil ShapiroSuppose you declare an auto variable <tt>i</tt> outside of a
73240266059SGregory Neil ShapiroSM_TRY ... SM_END_TRY statement, initializing it to 0.
73340266059SGregory Neil ShapiroThen you modify <tt>i</tt> inside of a SM_TRY or SM_FINALLY clause,
73440266059SGregory Neil Shapirosetting it to 1.
73540266059SGregory Neil ShapiroIf you reference <tt>i</tt> in a different SM_FINALLY clause, or in
73640266059SGregory Neil Shapiroan SM_EXCEPT clause, then it is implementation dependent whether <tt>i</tt>
73740266059SGregory Neil Shapirowill be 0 or 1, unless you have declared <tt>i</tt> to be <tt>volatile</tt>.
73840266059SGregory Neil Shapiro
73940266059SGregory Neil Shapiro<blockquote><pre>
74040266059SGregory Neil Shapiroint volatile i = 0;
74140266059SGregory Neil Shapiro
74240266059SGregory Neil ShapiroSM_TRY
74340266059SGregory Neil Shapiro	i = 1;
74440266059SGregory Neil Shapiro	...
74540266059SGregory Neil ShapiroSM_FINALLY
74640266059SGregory Neil Shapiro	/* the following reference to i only works if i is declared volatile */
74740266059SGregory Neil Shapiro	use(i);
74840266059SGregory Neil Shapiro	...
74940266059SGregory Neil ShapiroSM_EXCEPT(exc, "*")
75040266059SGregory Neil Shapiro	/* the following reference to i only works if i is declared volatile */
75140266059SGregory Neil Shapiro	use(i);
75240266059SGregory Neil Shapiro	...
75340266059SGregory Neil ShapiroSM_END_TRY
75440266059SGregory Neil Shapiro</pre></blockquote>
75540266059SGregory Neil Shapiro
75640266059SGregory Neil Shapiro</body>
75740266059SGregory Neil Shapiro</html>
758