summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/libsm/exc.html
blob: a2990363ce8cc66f40e0fe8cde9886ba7f9f224c (plain)
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
<html>
<head>
    <title>libsm : Exception Handling</title>
</head>
<body>

<a href="index.html">Back to libsm overview</a>

<center>
    <h1> libsm : Exception Handling </h1>
    <br> $Id: exc.html,v 1.12 2001/02/13 21:21:25 gshapiro Exp $
</center>

<h2> Introduction </h2>

The exception handling package provides the facilities that
functions in libsm use to report errors.
Here are the basic concepts:

<ol>
<li>
    When a function detects an exceptional condition at the library level,
    it does not print an error message, or call syslog, or
    exit the program.  Instead, it reports the error back to its
    caller, and lets the caller decide what to do.
    This improves modularity, because error handling is separated
    from error reporting.
    <p>
<li>
    Errors are not represented by a single integer error code,
    because that you can't represent everything that an error handler
    might need to know about an error by a single integer.
    Instead, errors are represented by exception objects.
    An exception object contains an exception code and an array
    of zero or more exception arguments.
    The exception code is a string that specifies what kind of exception
    this is, and the arguments may be integers, strings or exception objects.
    <p>
<li>
    Errors are not reported using a special return value,
    because if you religiously check for error returns from every
    function call that could fail, then most of your code ends up being
    error handling code.  Errors are reported by raising an exception.
    When an exception is raised, we unwind the call stack
    until we find an exception handler.  If the exception is
    not handled, then we print the exception on stderr and
    exit the program.
</ol>

<h2> Synopsis </h2>

<pre>
#include &lt;sm/exc.h&gt;

typedef struct sm_exc_type SM_EXC_TYPE_T;
typedef struct sm_exc SM_EXC_T;
typedef union sm_val SM_VAL_T;

/*
**  Exception types
*/

extern const char SmExcTypeMagic[];

struct sm_exc_type
{
	const char	*sm_magic;
	const char	*etype_category;
	const char	*etype_argformat;
	void 		(*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream);
	const char	*etype_printcontext;
};

extern const SM_EXC_TYPE_T SmEtypeOs;
extern const SM_EXC_TYPE_T SmEtypeErr;

void
sm_etype_printf(
	SM_EXC_T *exc,
	SM_FILE_T *stream);

/*
**  Exception objects
*/

extern const char SmExcMagic[];

union sm_val
{
	int		v_int;
	long		v_long;
	char		*v_str;
	SM_EXC_T	*v_exc;
};

struct sm_exc
{
	const char		*sm_magic;
	size_t			exc_refcount;
	const SM_EXC_TYPE_T	*exc_type;
	SM_VAL_T		*exc_argv;
};

SM_EXC_T *
sm_exc_new_x(
	const SM_EXC_TYPE_T *type,
	...);

SM_EXC_T *
sm_exc_addref(
	SM_EXC_T *exc);

void
sm_exc_free(
	SM_EXC_T *exc);

bool
sm_exc_match(
	SM_EXC_T *exc,
	const char *pattern);

void
sm_exc_print(
	SM_EXC_T *exc,
	SM_FILE_T *stream);

void
sm_exc_write(
	SM_EXC_T *exc,
	SM_FILE_T *stream);

void
sm_exc_raise_x(
	SM_EXC_T *exc);

void
sm_exc_raisenew_x(
	const SM_EXC_TYPE_T *type,
	...);

/*
**  Ensure that cleanup code is executed,
**  and/or handle an exception.
*/
SM_TRY
	Block of code that may raise an exception.
SM_FINALLY
	Cleanup code that may raise an exception.
	This clause is guaranteed to be executed even if an exception is
	raised by the SM_TRY clause or by an earlier SM_FINALLY clause.
	You may have 0 or more SM_FINALLY clauses.
SM_EXCEPT(exc, pattern)
	Exception handling code, triggered by an exception
	whose category matches 'pattern'.
	You may have 0 or more SM_EXCEPT clauses.
SM_END_TRY
</pre>

<h2> Overview </h2>

    An exception is an object which represents an exceptional condition,
    which might be an error condition like "out of memory", or might be
    a condition like "end of file".
<p>
    Functions in libsm report errors and other unusual conditions by
    raising an exception, rather than by returning an error code or
    setting a global variable such as errno.  If a libsm function is
    capable of raising an exception, its name ends in "_x".
    (We do not raise an exception when a bug is detected in the
    program; instead, we terminate the program using <tt>sm_abort</tt>.
    See <a href="assert.html">the assertion package</a>
    for details.)
<p>
    When you are using the libsm exception handling package,
    you are using a new programming paradigm.
    You will need to abandon some of the programming idioms
    you are accustomed to, and switch to new idioms.
    Here is an overview of some of these idioms.
<ol>
<li>
	When a function is unable to complete its task because
	of an exceptional condition, it reports this condition
	by raising an exception.
	<p>
	Here is an example of how to construct an exception object
	and raise an exception.
	In this example, we convert a Unix system error into an exception.
<blockquote><pre>
fd = open(path, O_RDONLY);
if (fd == -1)
	sm_exc_raise_x(sm_exc_new_x(&SmEtypeOs, errno, "open", "%s", path));
</pre></blockquote>

	Because the idiom <tt>sm_exc_raise_x(sm_exc_new_x(...))</tt>
	is so common, it can be abbreviated as <tt>sm_exc_raisenew_x(...)</tt>.
<p>
<li>
	When you detect an error at the application level,
	you don't call a function like BSD's <tt>errx</tt>,
	which prints an error message on stderr and exits the program.
	Instead, you raise an exception.
	This causes cleanup code in surrounding exception handlers
	to be run before the program exits.
	For example, instead of this:
<blockquote><pre>
errx(1, "%s:%d: syntax error", filename, lineno);
</pre></blockquote>

	use this:

<blockquote><pre>
sm_exc_raisenew_x(&SmEtypeErr, "%s:%d: syntax error", filename, lineno);
</pre></blockquote>

	The latter code raises an exception, unwinding the call stack
	and executing cleanup code.
	If the exception is not handled, then the exception is printed
	to stderr and the program exits.
	The end result is substantially the same as a call to <tt>errx</tt>.
<p>
<li>
        The SM_TRY ... SM_FINALLY ... control structure
	ensures that cleanup code is executed and resources are released
	in the presence of exceptions.
<p>
	For example, suppose that you have written the following code:

<blockquote><pre>
rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
... some code ...
sm_rpool_free_x(rpool);
</pre></blockquote>

	If any of the functions called within "... some code ..." have
	names ending in _x, then it is possible that an exception will be
	raised, and if that happens, then "rpool" will not be freed.
	And that's a bug.  To fix this bug, change your code so it looks
	like this:

<blockquote><pre>
rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
SM_TRY
	... some code that can raise an exception ...
SM_FINALLY
	sm_rpool_free_x(rpool);
SM_END_TRY
</pre></blockquote>

<li>
	The SM_TRY ... SM_EXCEPT ... control structure handles an exception.
	Unhandled exceptions terminate the program.
	For example, here is a simple exception handler
	that traps all exceptions, and prints the exceptions:

<blockquote><pre>
SM_TRY
	/* code that can raise an exception */
	...
SM_EXCEPT(exc, "*")
	/* catch all exceptions */
	sm_exc_print(exc, stderr);
SM_END_TRY
</pre></blockquote>

    Exceptions are reference counted.  The SM_END_TRY macro contains a
    call to sm_exc_free, so you don't normally need to worry about freeing
    an exception after handling it.  In the rare case that you want an
    exception to outlive an exception handler, then you increment its
    reference count by calling sm_exc_addref.
<p>
<li>
    The second argument of the SM_EXCEPT macro is a glob pattern
    which specifies the types of exceptions that are to be handled.
    For example, you might want to handle an end-of-file exception
    differently from other exceptions.
    Here's how you do that:

<blockquote><pre>
SM_TRY
	/* code that might raise end-of-file, or some other exception */
	...
SM_EXCEPT(exc, "E:sm.eof")
	/* what to do if end-of-file is encountered */
	...
SM_EXCEPT(exc, "*")
	/* what to do if some other exception is raised */
	...
SM_END_TRY
</pre></blockquote>
</ol>

<h2> Exception Values </h2>

In traditional C code, errors are usually denoted by a single integer,
such as errno.  In practice, errno does not carry enough information
to describe everything that an error handler might want to know about
an error.  And the scheme is not very extensible: if several different
packages want to add additional error codes, it is hard to avoid
collisions.

<p>
In libsm, an exceptional condition is described
by an object of type SM_EXC_T.
An exception object is created by specifying an exception type
and a list of exception arguments.

<p>
The exception arguments are an array of zero or more values.
The values may be a mixture of ints, longs, strings, and exceptions.
In the SM_EXC_T structure, the argument vector is represented
by <tt>SM_VAL_T&nbsp;*exc_argv</tt>, where <tt>SM_VAL_T</tt>
is a union of the possible argument types.
The number and types of exception arguments is determined by
the exception type.

<p>
An exception type is a statically initialized const object
of type SM_EXC_TYPE_T, which has the following members:

<dl>
<dt>
<tt> const char *sm_magic </tt>
<dd>
	A pointer to <tt>SmExcTypeMagic</tt>.
	<p>
<dt>
<tt> const char *etype_category </tt>
<dd>
	This is a string of the form
	<tt>"</tt><i>class</i><tt>:</tt><i>name</i><tt>"</tt>.
	<p>
	The <i>class</i> is used to assign the exception type to
	one of a number of broad categories of exceptions on which an
	exception handler might want to discriminate.
	I suspect that what we want is a hierarchical taxonomy,
	but I don't have a full design for this yet.
	For now, I am recommending the following classes:
	<dl>
	<dt><tt>"F"</tt>
	<dd>A fatal error has occurred.
	    This is an error that prevents the application
	    from making any further progress, so the only
	    recourse is to raise an exception, execute cleanup code
	    as the stack is unwound, then exit the application.
	    The out-of-memory exception raised by sm_malloc_x
	    has category "F:sm.heap" because sendmail commits suicide
	    (after logging the error and cleaning up) when it runs out
	    of memory.

	<dt><tt>"E"</tt>
	<dd>The function could not complete its task because an error occurred.
	    (It might be useful to define subclasses of this category,
	    in which case our taxonony becomes a tree, and 'F' becomes
	    a subclass of 'E'.)

	<dt><tt>"J"</tt>
	<dd>This exception is being raised in order to effect a
	    non-local jump.  No error has occurred; we are just
	    performing the non-local equivalent of a <tt>continue</tt>,
	    <tt>break</tt> or <tt>return</tt>.

	<dt><tt>"S"</tt>
	<dd>The function was interrupted by a signal.
	    Signals are not errors because they occur asynchronously,
	    and they are semantically unrelated to the function that
	    happens to be executing when the signal arrives.
	    Note that it is extremely dangerous to raise an exception
	    from a signal handler.  For example, if you are in the middle
	    of a call to malloc, you might corrupt the heap.
	</dl>
	Eric's libsm paper defines <tt>"W"</tt>, <tt>"D"</tt> and <tt>"I"</tt>
	for Warning, Debug and Informational:
	I suspect these categories only make sense in the context of
	Eric's 1985 exception handling system which allowed you to
	raise conditions without terminating the calling function.
	<p>
	The <i>name</i> uniquely identifies the exception type.
	I recommend a string of the form
	<i>library</i><tt>.</tt><i>package</i><tt>.</tt><i>detail</i>.
	<p>
<dt>
<tt> const char *etype_argformat </tt>
<dd>
	This is an array of single character codes.
	Each code indicates the type of one of the exception arguments.
	<tt>sm_exc_new_x</tt> uses this string to decode its variable
	argument list into an exception argument vector.
	The following type codes are supported:
	<dl>
	<dt><tt>i</tt>
	<dd>
		The exception argument has type <tt>int</tt>.
	<dt><tt>l</tt>
	<dd>
		The exception argument has type <tt>long</tt>.
	<dt><tt>e</tt>
	<dd>
		The exception argument has type <tt>SM_EXC_T*</tt>.
		The value may either be <tt>NULL</tt> or a pointer
		to an exception.  The pointer value is simply copied
		into the exception argument vector.
	<dt><tt>s</tt>
	<dd>
		The exception argument has type <tt>char*</tt>.
		The value may either be <tt>NULL</tt> or a pointer
		to a character string.  In the latter case,
		<tt>sm_exc_new_x</tt> will make a copy of the string.
	<dt><tt>r</tt>
	<dd>
		The exception argument has type <tt>char*</tt>.
		<tt>sm_exc_new_x</tt> will read a printf-style
		format string argument followed by a list of printf
		arguments from its variable argument list, and convert
		these into a string.
		This type code can only occur as the last element
		of <tt>exc_argformat</tt>.
	</dl>
	<p>
<dt>
<tt> void (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
<dd>
	This function prints an exception of the specified type
	onto an output stream.
	The final character printed is not a newline.
</dl>

<h2> Standard Exceptions and Exception Types </h2>

Libsm defines one standard exception value, <tt>SmHeapOutOfMemory</tt>.
This is a statically initialized const variable, because it seems
like a bad idea to dynamically allocate an exception object to
report a low memory condition.
This exception has category <tt>"F:sm.heap"</tt>.
If you need to, you can explicitly raise this exception
with <tt>sm_exc_raise_x(&SmHeapOutOfMemory)</tt>.

<p>
Statically initialized exception values cannot contain any
run-time parameters, so the normal case is to dynamically allocate
a new exception object whenever you raise an exception.
Before you can create an exception, you need an exception type.
Libsm defines the following standard exception types.

<dl>
<dt>
<tt> SmEtypeOs </tt>
<dd>
	This represents a generic operating system error.
	The category is <tt>"E:sm.os"</tt>.
	The argformat is <tt>"isr"</tt>,
	where argv[0] is the value of <tt>errno</tt>
	after a system call has failed,
	argv[1] is the name of the function (usually a system call) that failed,
	and argv[2] is either <tt>NULL</tt>
	or a character string which describes some of the arguments
	to the failing system call (usually it is just a file name).
	Here's an example of raising an exception:

<blockquote><pre>
fd = open(filename, O_RDONLY);
if (fd == -1)
	sm_exc_raisenew_x(&SmEtypeOs, errno, "open", "%s", filename);
</pre></blockquote>

	If errno is ENOENT and filename is "/etc/mail/snedmail.cf",
	then the exception raised by the above code will be printed as

<blockquote><pre>
/etc/mail/snedmail.cf: open failed: No such file or directory
</pre></blockquote>

<dt>
<tt> SmEtypeErr </tt>
<dd>
	This represents a generic error.
	The category is <tt>"E:sm.err"</tt>,
	and the argformat is <tt>"r"</tt>.
	You can use it
	in application contexts where you are raising an exception
	for the purpose of terminating the program.
	You know the exception won't be handled,
	so you don't need to worry about packaging the error for
	later analysis by an exception handler.
	All you need to specify is the message string that
	will be printed to stderr before the program exits.
	For example,

<blockquote><pre>
sm_exc_raisenew_x(&SmEtypeErr, "name lookup failed: %s", name);
</pre></blockquote>
</dl>

<h2> Custom Exception Types </h2>

If you are writing a library package, and you need to raise
exceptions that are not standard Unix system errors,
then you need to define one or more new exception types.

<p>
Every new exception type needs a print function.
The standard print function <tt>sm_etype_printf</tt>
is all you need in the majority of cases.
It prints the <tt>etype_printcontext</tt> string of the exception type,
substituting occurrences of %0 through %9 with the corresponding
exception argument.
If exception argument 3 is an int or long,
then %3 will print the argument in decimal,
and %o3 or %x3 will print it in octal or hex.

<p>
In the following example, I will assume that your library
package implements regular expressions, and can raise 5 different exceptions.
When compiling a regular expression, 3 different syntax errors
can be reported:
<ul>
<li>unbalanced parenthesis
<li>unbalanced bracket
<li>missing argument for repetition operator
</ul>
Whenever one of these errors is reported, you will also report
the index of the character within the regex string at which the
syntax error was detected.
The fourth exception is raised if a compiled regular expression
is invalid: this exception has no arguments.
The fifth exception is raised if the package runs out of memory:
for this, you use the standard <tt>SmHeapOutOfMemory</tt> exception.

<p>
The obvious approach is to define 4 separate exception types.
Here they are:

<blockquote><pre>
/* print a regular expression syntax error */
void
rx_esyntax_print(SM_EXC_T *exc, SM_FILE_T *stream)
{
	sm_io_fprintf(stream, "rx syntax error at character %d: %s",
		exc-&gt;exc_argv[0].v_int,
		exc-&gt;exc_type-&gt;etype_printcontext);
}
SM_EXC_TYPE_T RxSyntaxParen = {
	SmExcTypeMagic,
	"E:mylib.rx.syntax.paren",
	"i",
	rx_esyntax_print,
	"unbalanced parenthesis"
};
SM_EXC_TYPE_T RxSyntaxBracket = {
	SmExcTypeMagic,
	"E:mylib.rx.syntax.bracket",
	"i",
	rx_esyntax_print,
	"unbalanced bracket"
};
SM_EXC_TYPE_T RxSyntaxMissingArg = {
	SmExcTypeMagic,
	"E:mylib.rx.syntax.missingarg",
	"i",
	rx_esyntax_print,
	"missing argument for repetition operator"
};

SM_EXC_TYPE_T RxRunCorrupt = {
	SmExcTypeMagic,
	"E:mylib.rx.run.corrupt",
	"",
	sm_etype_printf,
	"rx runtime error: compiled regular expression is corrupt"
};
</pre></blockquote>

<p>
With the above definitions, you can raise a syntax error reporting
an unbalanced parenthesis at string offset <tt>i</tt> using:
<blockquote><pre>
sm_exc_raisenew_x(&RxSyntaxParen, i);
</pre></blockquote>

If <tt>i==42</tt> then this exception will be printed as:
<blockquote><pre>
rx syntax error at character 42: unbalanced parenthesis
</pre></blockquote>

An exception handler can provide special handling for regular
expression syntax errors using this code:
<blockquote><pre>
SM_TRY
	... code that might raise an exception ...
SM_EXCEPT(exc, "E:mylib.rx.syntax.*")
	int i = exc-&gt;exc_argv[0].v_int;
	... handle a regular expression syntax error ...
SM_END_TRY
</pre></blockquote>

<p>
External requirements may force you to define an integer code
for each error reported by your package.  Or you may be wrapping
an existing package that works this way.  In this case, it might
make sense to define a single exception type, patterned after SmEtypeOs,
and include the integer code as an exception argument.

<p>
Your package might intercept an exception E generated by a lower
level package, and then reclassify it as a different expression E'.
For example, a package for reading a configuration file might
reclassify one of the regular expression syntax errors from the
previous example as a configuration file syntax error.
When you do this, the new exception E' should include the original
exception E as an exception parameter, and the print function for
exception E' should print the high level description of the exception
(eg, "syntax error in configuration file %s at line %d\n"),
then print the subexception that is stored as an exception parameter.

<h2> Function Reference </h2>

<dl>
<dt>
<tt> SM_EXC_T *sm_exc_new_x(const SM_EXC_TYPE_T *type, ...) </tt>
<dd>
	Create a new exception.  Raise an exception on heap exhaustion.
	The new exception has a reference count of 1.
	<p>

	A list of zero or more exception arguments follows the exception type;
	these are copied into the new exception object.
	The number and types of these arguments is determined
	by <tt>type-&gt;etype_argformat</tt>.
	<p>

	Note that there is no rpool argument to sm_exc_new_x.
	Exceptions are allocated directly from the heap.
	This is because exceptions are normally raised at low levels
	of abstraction and handled at high levels.  Because the low
	level code typically has no idea of how or at what level the
	exception will be handled, it also has no idea of which resource
	pool, if any, should own the exception.
	<p>
<dt>
<tt> SM_EXC_T *sm_exc_addref(SM_EXC_T *exc) </tt>
<dd>
	Increment the reference count of an exception.
	Return the first argument.
	<p>
<dt>
<tt> void sm_exc_free(SM_EXC_T *exc) </tt>
<dd>
	Decrement the reference count of an exception.
	If it reaches 0, free the exception object.
	<p>
<dt>
<tt> bool sm_exc_match(SM_EXC_T *exc, const char *pattern) </tt>
<dd>
	Compare the exception's category to the specified glob pattern,
	return true if they match.
	<p>
<dt>
<tt> void sm_exc_print(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
<dd>
	Print the exception on the stream
	as a sequence of one or more newline terminated lines.
	<p>
<dt>
<tt> void sm_exc_write(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
<dd>
	Write the exception on the stream without a terminating newline.
	<p>
<dt>
<tt> void sm_exc_raise_x(SM_EXC_T *exc) </tt>
<dd>
	Raise the exception.  This function does not return to its caller.
	<p>
<dt>
<tt> void sm_exc_raisenew_x(const SM_EXC_TYPE_T *type, ...) </tt>
<dd>
	A short form for <tt>sm_exc_raise_x(sm_exc_new_x(type,...))</tt>.
</dl>

<h2> Macro Reference </h2>

The SM_TRY ... SM_END_TRY control structure
ensures that cleanup code is executed in the presence of exceptions,
and permits exceptions to be handled.

<blockquote><pre>
SM_TRY
	A block of code that may raise an exception.
SM_FINALLY
	Cleanup code that may raise an exception.
	This code is guaranteed to be executed whether or not
	an exception was raised by a previous clause.
	You may have 0 or more SM_FINALLY clauses.
SM_EXCEPT(e, pat)
	Exception handling code, which is triggered by an exception
	whose category matches the glob pattern 'pat'.
	The exception value is bound to the local variable 'e'.
	You may have 0 or more SM_EXCEPT clauses.
SM_END_TRY
</pre></blockquote>

First, the SM_TRY clause is executed, then each SM_FINALLY clause is
executed in sequence.
If one or more of these clauses was terminated by an exception,
then the first such exception is remembered, and the other exceptions
are lost.

If no exception was raised, then we are done.

Otherwise, each of the SM_EXCEPT clauses is examined in sequence.
and the first SM_EXCEPT clause whose pattern argument matches the exception
(see <tt>sm_exc_match</tt>) is executed.
If none of the SM_EXCEPT clauses matched the exception, or if there are
no SM_EXCEPT clauses, then the remembered exception is re-raised.

<p>
SM_TRY .. SM_END_TRY clauses may be nested arbitrarily.

<p>
It is illegal to jump out of a SM_TRY or SM_FINALLY clause
using goto, break, continue, return or longjmp.
If you do this, you will corrupt the internal exception handling stack.
You can't use <tt>break</tt> or <tt>continue</tt> in an SM_EXCEPT clause;
these are reserved for use by the implementation.
It is legal to jump out of an SM_EXCEPT clause using goto or return;
however, in this case, you must take responsibility
for freeing the exception object.

<p>
The SM_TRY and SM_FINALLY macros contain calls to setjmp,
and consequently, they suffer from the limitations imposed on setjmp
by the C standard.
Suppose you declare an auto variable <tt>i</tt> outside of a
SM_TRY ... SM_END_TRY statement, initializing it to 0.
Then you modify <tt>i</tt> inside of a SM_TRY or SM_FINALLY clause,
setting it to 1.
If you reference <tt>i</tt> in a different SM_FINALLY clause, or in
an SM_EXCEPT clause, then it is implementation dependent whether <tt>i</tt>
will be 0 or 1, unless you have declared <tt>i</tt> to be <tt>volatile</tt>.

<blockquote><pre>
int volatile i = 0;

SM_TRY
	i = 1;
	...
SM_FINALLY
	/* the following reference to i only works if i is declared volatile */
	use(i);
	...
SM_EXCEPT(exc, "*")
	/* the following reference to i only works if i is declared volatile */
	use(i);
	...
SM_END_TRY
</pre></blockquote>

</body>
</html>
OpenPOWER on IntegriCloud