xref: /titanic_44/usr/src/cmd/sendmail/libsm/exc.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *	All rights reserved.
4*7c478bd9Sstevel@tonic-gate  *
5*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
6*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
7*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  */
10*7c478bd9Sstevel@tonic-gate 
11*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
12*7c478bd9Sstevel@tonic-gate 
13*7c478bd9Sstevel@tonic-gate #include <sm/gen.h>
14*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: exc.c,v 1.47.2.1 2003/12/05 22:44:17 ca Exp $")
15*7c478bd9Sstevel@tonic-gate 
16*7c478bd9Sstevel@tonic-gate /*
17*7c478bd9Sstevel@tonic-gate **  exception handling
18*7c478bd9Sstevel@tonic-gate **  For documentation, see exc.html
19*7c478bd9Sstevel@tonic-gate */
20*7c478bd9Sstevel@tonic-gate 
21*7c478bd9Sstevel@tonic-gate #include <ctype.h>
22*7c478bd9Sstevel@tonic-gate #include <string.h>
23*7c478bd9Sstevel@tonic-gate 
24*7c478bd9Sstevel@tonic-gate #include <sm/errstring.h>
25*7c478bd9Sstevel@tonic-gate #include <sm/exc.h>
26*7c478bd9Sstevel@tonic-gate #include <sm/heap.h>
27*7c478bd9Sstevel@tonic-gate #include <sm/string.h>
28*7c478bd9Sstevel@tonic-gate #include <sm/varargs.h>
29*7c478bd9Sstevel@tonic-gate #include <sm/io.h>
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate const char SmExcMagic[] = "sm_exc";
32*7c478bd9Sstevel@tonic-gate const char SmExcTypeMagic[] = "sm_exc_type";
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate /*
35*7c478bd9Sstevel@tonic-gate **  SM_ETYPE_PRINTF -- printf for exception types.
36*7c478bd9Sstevel@tonic-gate **
37*7c478bd9Sstevel@tonic-gate **	Parameters:
38*7c478bd9Sstevel@tonic-gate **		exc -- exception.
39*7c478bd9Sstevel@tonic-gate **		stream -- file for output.
40*7c478bd9Sstevel@tonic-gate **
41*7c478bd9Sstevel@tonic-gate **	Returns:
42*7c478bd9Sstevel@tonic-gate **		none.
43*7c478bd9Sstevel@tonic-gate */
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate /*
46*7c478bd9Sstevel@tonic-gate **  A simple formatted print function that can be used as the print function
47*7c478bd9Sstevel@tonic-gate **  by most exception types.  It prints the printcontext string, interpreting
48*7c478bd9Sstevel@tonic-gate **  occurrences of %0 through %9 as references to the argument vector.
49*7c478bd9Sstevel@tonic-gate **  If exception argument 3 is an int or long, then %3 will print the
50*7c478bd9Sstevel@tonic-gate **  argument in decimal, and %o3 or %x3 will print it in octal or hex.
51*7c478bd9Sstevel@tonic-gate */
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate void
54*7c478bd9Sstevel@tonic-gate sm_etype_printf(exc, stream)
55*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
56*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream;
57*7c478bd9Sstevel@tonic-gate {
58*7c478bd9Sstevel@tonic-gate 	size_t n = strlen(exc->exc_type->etype_argformat);
59*7c478bd9Sstevel@tonic-gate 	const char *p, *s;
60*7c478bd9Sstevel@tonic-gate 	char format;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 	for (p = exc->exc_type->etype_printcontext; *p != '\0'; ++p)
63*7c478bd9Sstevel@tonic-gate 	{
64*7c478bd9Sstevel@tonic-gate 		if (*p != '%')
65*7c478bd9Sstevel@tonic-gate 		{
66*7c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(stream, SM_TIME_DEFAULT, *p);
67*7c478bd9Sstevel@tonic-gate 			continue;
68*7c478bd9Sstevel@tonic-gate 		}
69*7c478bd9Sstevel@tonic-gate 		++p;
70*7c478bd9Sstevel@tonic-gate 		if (*p == '\0')
71*7c478bd9Sstevel@tonic-gate 		{
72*7c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
73*7c478bd9Sstevel@tonic-gate 			break;
74*7c478bd9Sstevel@tonic-gate 		}
75*7c478bd9Sstevel@tonic-gate 		if (*p == '%')
76*7c478bd9Sstevel@tonic-gate 		{
77*7c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
78*7c478bd9Sstevel@tonic-gate 			continue;
79*7c478bd9Sstevel@tonic-gate 		}
80*7c478bd9Sstevel@tonic-gate 		format = '\0';
81*7c478bd9Sstevel@tonic-gate 		if (isalpha(*p))
82*7c478bd9Sstevel@tonic-gate 		{
83*7c478bd9Sstevel@tonic-gate 			format = *p++;
84*7c478bd9Sstevel@tonic-gate 			if (*p == '\0')
85*7c478bd9Sstevel@tonic-gate 			{
86*7c478bd9Sstevel@tonic-gate 				(void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
87*7c478bd9Sstevel@tonic-gate 				(void) sm_io_putc(stream, SM_TIME_DEFAULT,
88*7c478bd9Sstevel@tonic-gate 						  format);
89*7c478bd9Sstevel@tonic-gate 				break;
90*7c478bd9Sstevel@tonic-gate 			}
91*7c478bd9Sstevel@tonic-gate 		}
92*7c478bd9Sstevel@tonic-gate 		if (isdigit(*p))
93*7c478bd9Sstevel@tonic-gate 		{
94*7c478bd9Sstevel@tonic-gate 			size_t i = *p - '0';
95*7c478bd9Sstevel@tonic-gate 			if (i < n)
96*7c478bd9Sstevel@tonic-gate 			{
97*7c478bd9Sstevel@tonic-gate 				switch (exc->exc_type->etype_argformat[i])
98*7c478bd9Sstevel@tonic-gate 				{
99*7c478bd9Sstevel@tonic-gate 				  case 's':
100*7c478bd9Sstevel@tonic-gate 				  case 'r':
101*7c478bd9Sstevel@tonic-gate 					s = exc->exc_argv[i].v_str;
102*7c478bd9Sstevel@tonic-gate 					if (s == NULL)
103*7c478bd9Sstevel@tonic-gate 						s = "(null)";
104*7c478bd9Sstevel@tonic-gate 					sm_io_fputs(stream, SM_TIME_DEFAULT, s);
105*7c478bd9Sstevel@tonic-gate 					continue;
106*7c478bd9Sstevel@tonic-gate 				  case 'i':
107*7c478bd9Sstevel@tonic-gate 					sm_io_fprintf(stream,
108*7c478bd9Sstevel@tonic-gate 						SM_TIME_DEFAULT,
109*7c478bd9Sstevel@tonic-gate 						format == 'o' ? "%o"
110*7c478bd9Sstevel@tonic-gate 						: format == 'x' ? "%x"
111*7c478bd9Sstevel@tonic-gate 								: "%d",
112*7c478bd9Sstevel@tonic-gate 						exc->exc_argv[i].v_int);
113*7c478bd9Sstevel@tonic-gate 					continue;
114*7c478bd9Sstevel@tonic-gate 				  case 'l':
115*7c478bd9Sstevel@tonic-gate 					sm_io_fprintf(stream,
116*7c478bd9Sstevel@tonic-gate 						SM_TIME_DEFAULT,
117*7c478bd9Sstevel@tonic-gate 						format == 'o' ? "%lo"
118*7c478bd9Sstevel@tonic-gate 						: format == 'x' ? "%lx"
119*7c478bd9Sstevel@tonic-gate 								: "%ld",
120*7c478bd9Sstevel@tonic-gate 						exc->exc_argv[i].v_long);
121*7c478bd9Sstevel@tonic-gate 					continue;
122*7c478bd9Sstevel@tonic-gate 				  case 'e':
123*7c478bd9Sstevel@tonic-gate 					sm_exc_write(exc->exc_argv[i].v_exc,
124*7c478bd9Sstevel@tonic-gate 						stream);
125*7c478bd9Sstevel@tonic-gate 					continue;
126*7c478bd9Sstevel@tonic-gate 				}
127*7c478bd9Sstevel@tonic-gate 			}
128*7c478bd9Sstevel@tonic-gate 		}
129*7c478bd9Sstevel@tonic-gate 		(void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
130*7c478bd9Sstevel@tonic-gate 		if (format)
131*7c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(stream, SM_TIME_DEFAULT, format);
132*7c478bd9Sstevel@tonic-gate 		(void) sm_io_putc(stream, SM_TIME_DEFAULT, *p);
133*7c478bd9Sstevel@tonic-gate 	}
134*7c478bd9Sstevel@tonic-gate }
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate /*
137*7c478bd9Sstevel@tonic-gate **  Standard exception types.
138*7c478bd9Sstevel@tonic-gate */
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /*
141*7c478bd9Sstevel@tonic-gate **  SM_ETYPE_OS_PRINT -- Print OS related exception.
142*7c478bd9Sstevel@tonic-gate **
143*7c478bd9Sstevel@tonic-gate **	Parameters:
144*7c478bd9Sstevel@tonic-gate **		exc -- exception.
145*7c478bd9Sstevel@tonic-gate **		stream -- file for output.
146*7c478bd9Sstevel@tonic-gate **
147*7c478bd9Sstevel@tonic-gate **	Returns:
148*7c478bd9Sstevel@tonic-gate **		none.
149*7c478bd9Sstevel@tonic-gate */
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate static void
152*7c478bd9Sstevel@tonic-gate sm_etype_os_print __P((
153*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc,
154*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream));
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate static void
157*7c478bd9Sstevel@tonic-gate sm_etype_os_print(exc, stream)
158*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
159*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream;
160*7c478bd9Sstevel@tonic-gate {
161*7c478bd9Sstevel@tonic-gate 	int err = exc->exc_argv[0].v_int;
162*7c478bd9Sstevel@tonic-gate 	char *syscall = exc->exc_argv[1].v_str;
163*7c478bd9Sstevel@tonic-gate 	char *sysargs = exc->exc_argv[2].v_str;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	if (sysargs)
166*7c478bd9Sstevel@tonic-gate 		sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s: %s failed: %s",
167*7c478bd9Sstevel@tonic-gate 			      sysargs, syscall, sm_errstring(err));
168*7c478bd9Sstevel@tonic-gate 	else
169*7c478bd9Sstevel@tonic-gate 		sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s failed: %s", syscall,
170*7c478bd9Sstevel@tonic-gate 			      sm_errstring(err));
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate /*
174*7c478bd9Sstevel@tonic-gate **  SmEtypeOs represents the failure of a Unix system call.
175*7c478bd9Sstevel@tonic-gate **  The three arguments are:
176*7c478bd9Sstevel@tonic-gate **   int errno (eg, ENOENT)
177*7c478bd9Sstevel@tonic-gate **   char *syscall (eg, "open")
178*7c478bd9Sstevel@tonic-gate **   char *sysargs (eg, NULL or "/etc/mail/sendmail.cf")
179*7c478bd9Sstevel@tonic-gate */
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate const SM_EXC_TYPE_T SmEtypeOs =
182*7c478bd9Sstevel@tonic-gate {
183*7c478bd9Sstevel@tonic-gate 	SmExcTypeMagic,
184*7c478bd9Sstevel@tonic-gate 	"E:sm.os",
185*7c478bd9Sstevel@tonic-gate 	"isr",
186*7c478bd9Sstevel@tonic-gate 	sm_etype_os_print,
187*7c478bd9Sstevel@tonic-gate 	NULL,
188*7c478bd9Sstevel@tonic-gate };
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate /*
191*7c478bd9Sstevel@tonic-gate **  SmEtypeErr is a completely generic error which should only be
192*7c478bd9Sstevel@tonic-gate **  used in applications and test programs.  Libraries should use
193*7c478bd9Sstevel@tonic-gate **  more specific exception codes.
194*7c478bd9Sstevel@tonic-gate */
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate const SM_EXC_TYPE_T SmEtypeErr =
197*7c478bd9Sstevel@tonic-gate {
198*7c478bd9Sstevel@tonic-gate 	SmExcTypeMagic,
199*7c478bd9Sstevel@tonic-gate 	"E:sm.err",
200*7c478bd9Sstevel@tonic-gate 	"r",
201*7c478bd9Sstevel@tonic-gate 	sm_etype_printf,
202*7c478bd9Sstevel@tonic-gate 	"%0",
203*7c478bd9Sstevel@tonic-gate };
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate /*
206*7c478bd9Sstevel@tonic-gate **  SM_EXC_VNEW_X -- Construct a new exception object.
207*7c478bd9Sstevel@tonic-gate **
208*7c478bd9Sstevel@tonic-gate **	Parameters:
209*7c478bd9Sstevel@tonic-gate **		etype -- type of exception.
210*7c478bd9Sstevel@tonic-gate **		ap -- varargs.
211*7c478bd9Sstevel@tonic-gate **
212*7c478bd9Sstevel@tonic-gate **	Returns:
213*7c478bd9Sstevel@tonic-gate **		pointer to exception object.
214*7c478bd9Sstevel@tonic-gate */
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate /*
217*7c478bd9Sstevel@tonic-gate **  This is an auxiliary function called by sm_exc_new_x and sm_exc_raisenew_x.
218*7c478bd9Sstevel@tonic-gate **
219*7c478bd9Sstevel@tonic-gate **  If an exception is raised, then to avoid a storage leak, we must:
220*7c478bd9Sstevel@tonic-gate **  (a) Free all storage we have allocated.
221*7c478bd9Sstevel@tonic-gate **  (b) Free all exception arguments in the varargs list.
222*7c478bd9Sstevel@tonic-gate **  Getting this right is tricky.
223*7c478bd9Sstevel@tonic-gate **
224*7c478bd9Sstevel@tonic-gate **  To see why (b) is required, consider the code fragment
225*7c478bd9Sstevel@tonic-gate **     SM_EXCEPT(exc, "*")
226*7c478bd9Sstevel@tonic-gate **         sm_exc_raisenew_x(&MyEtype, exc);
227*7c478bd9Sstevel@tonic-gate **     SM_END_TRY
228*7c478bd9Sstevel@tonic-gate **  In the normal case, sm_exc_raisenew_x will allocate and raise a new
229*7c478bd9Sstevel@tonic-gate **  exception E that owns exc.  When E is eventually freed, exc is also freed.
230*7c478bd9Sstevel@tonic-gate **  In the exceptional case, sm_exc_raisenew_x must free exc before raising
231*7c478bd9Sstevel@tonic-gate **  an out-of-memory exception so that exc is not leaked.
232*7c478bd9Sstevel@tonic-gate */
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate SM_EXC_T *
235*7c478bd9Sstevel@tonic-gate sm_exc_vnew_x(etype, ap)
236*7c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype;
237*7c478bd9Sstevel@tonic-gate 	va_list SM_NONVOLATILE ap;
238*7c478bd9Sstevel@tonic-gate {
239*7c478bd9Sstevel@tonic-gate 	/*
240*7c478bd9Sstevel@tonic-gate 	**  All variables that are modified in the SM_TRY clause and
241*7c478bd9Sstevel@tonic-gate 	**  referenced in the SM_EXCEPT clause must be declared volatile.
242*7c478bd9Sstevel@tonic-gate 	*/
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	/* NOTE: Type of si, i, and argc *must* match */
245*7c478bd9Sstevel@tonic-gate 	SM_EXC_T * volatile exc = NULL;
246*7c478bd9Sstevel@tonic-gate 	int volatile si = 0;
247*7c478bd9Sstevel@tonic-gate 	SM_VAL_T * volatile argv = NULL;
248*7c478bd9Sstevel@tonic-gate 	int i, argc;
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(etype, SmExcTypeMagic);
251*7c478bd9Sstevel@tonic-gate 	argc = strlen(etype->etype_argformat);
252*7c478bd9Sstevel@tonic-gate 	SM_TRY
253*7c478bd9Sstevel@tonic-gate 	{
254*7c478bd9Sstevel@tonic-gate 		/*
255*7c478bd9Sstevel@tonic-gate 		**  Step 1.  Allocate the exception structure.
256*7c478bd9Sstevel@tonic-gate 		**  On failure, scan the varargs list and free all
257*7c478bd9Sstevel@tonic-gate 		**  exception arguments.
258*7c478bd9Sstevel@tonic-gate 		*/
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 		exc = sm_malloc_x(sizeof(SM_EXC_T));
261*7c478bd9Sstevel@tonic-gate 		exc->sm_magic = SmExcMagic;
262*7c478bd9Sstevel@tonic-gate 		exc->exc_refcount = 1;
263*7c478bd9Sstevel@tonic-gate 		exc->exc_type = etype;
264*7c478bd9Sstevel@tonic-gate 		exc->exc_argv = NULL;
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 		/*
267*7c478bd9Sstevel@tonic-gate 		**  Step 2.  Allocate the argument vector.
268*7c478bd9Sstevel@tonic-gate 		**  On failure, free exc, scan the varargs list and free all
269*7c478bd9Sstevel@tonic-gate 		**  exception arguments.  On success, scan the varargs list,
270*7c478bd9Sstevel@tonic-gate 		**  and copy the arguments into argv.
271*7c478bd9Sstevel@tonic-gate 		*/
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		argv = sm_malloc_x(argc * sizeof(SM_VAL_T));
274*7c478bd9Sstevel@tonic-gate 		exc->exc_argv = argv;
275*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < argc; ++i)
276*7c478bd9Sstevel@tonic-gate 		{
277*7c478bd9Sstevel@tonic-gate 			switch (etype->etype_argformat[i])
278*7c478bd9Sstevel@tonic-gate 			{
279*7c478bd9Sstevel@tonic-gate 			  case 'i':
280*7c478bd9Sstevel@tonic-gate 				argv[i].v_int = SM_VA_ARG(ap, int);
281*7c478bd9Sstevel@tonic-gate 				break;
282*7c478bd9Sstevel@tonic-gate 			  case 'l':
283*7c478bd9Sstevel@tonic-gate 				argv[i].v_long = SM_VA_ARG(ap, long);
284*7c478bd9Sstevel@tonic-gate 				break;
285*7c478bd9Sstevel@tonic-gate 			  case 'e':
286*7c478bd9Sstevel@tonic-gate 				argv[i].v_exc = SM_VA_ARG(ap, SM_EXC_T*);
287*7c478bd9Sstevel@tonic-gate 				break;
288*7c478bd9Sstevel@tonic-gate 			  case 's':
289*7c478bd9Sstevel@tonic-gate 				argv[i].v_str = SM_VA_ARG(ap, char*);
290*7c478bd9Sstevel@tonic-gate 				break;
291*7c478bd9Sstevel@tonic-gate 			  case 'r':
292*7c478bd9Sstevel@tonic-gate 				SM_REQUIRE(etype->etype_argformat[i+1] == '\0');
293*7c478bd9Sstevel@tonic-gate 				argv[i].v_str = SM_VA_ARG(ap, char*);
294*7c478bd9Sstevel@tonic-gate 				break;
295*7c478bd9Sstevel@tonic-gate 			  default:
296*7c478bd9Sstevel@tonic-gate 				sm_abort("sm_exc_vnew_x: bad argformat '%c'",
297*7c478bd9Sstevel@tonic-gate 					etype->etype_argformat[i]);
298*7c478bd9Sstevel@tonic-gate 			}
299*7c478bd9Sstevel@tonic-gate 		}
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 		/*
302*7c478bd9Sstevel@tonic-gate 		**  Step 3.  Scan argv, and allocate space for all
303*7c478bd9Sstevel@tonic-gate 		**  string arguments.  si is the number of elements
304*7c478bd9Sstevel@tonic-gate 		**  of argv that have been processed so far.
305*7c478bd9Sstevel@tonic-gate 		**  On failure, free exc, argv, all the exception arguments
306*7c478bd9Sstevel@tonic-gate 		**  and all of the strings that have been copied.
307*7c478bd9Sstevel@tonic-gate 		*/
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 		for (si = 0; si < argc; ++si)
310*7c478bd9Sstevel@tonic-gate 		{
311*7c478bd9Sstevel@tonic-gate 			switch (etype->etype_argformat[si])
312*7c478bd9Sstevel@tonic-gate 			{
313*7c478bd9Sstevel@tonic-gate 			  case 's':
314*7c478bd9Sstevel@tonic-gate 			    {
315*7c478bd9Sstevel@tonic-gate 				char *str = argv[si].v_str;
316*7c478bd9Sstevel@tonic-gate 				if (str != NULL)
317*7c478bd9Sstevel@tonic-gate 				    argv[si].v_str = sm_strdup_x(str);
318*7c478bd9Sstevel@tonic-gate 			    }
319*7c478bd9Sstevel@tonic-gate 			    break;
320*7c478bd9Sstevel@tonic-gate 			  case 'r':
321*7c478bd9Sstevel@tonic-gate 			    {
322*7c478bd9Sstevel@tonic-gate 				char *fmt = argv[si].v_str;
323*7c478bd9Sstevel@tonic-gate 				if (fmt != NULL)
324*7c478bd9Sstevel@tonic-gate 				    argv[si].v_str = sm_vstringf_x(fmt, ap);
325*7c478bd9Sstevel@tonic-gate 			    }
326*7c478bd9Sstevel@tonic-gate 			    break;
327*7c478bd9Sstevel@tonic-gate 			}
328*7c478bd9Sstevel@tonic-gate 		}
329*7c478bd9Sstevel@tonic-gate 	}
330*7c478bd9Sstevel@tonic-gate 	SM_EXCEPT(e, "*")
331*7c478bd9Sstevel@tonic-gate 	{
332*7c478bd9Sstevel@tonic-gate 		if (exc == NULL || argv == NULL)
333*7c478bd9Sstevel@tonic-gate 		{
334*7c478bd9Sstevel@tonic-gate 			/*
335*7c478bd9Sstevel@tonic-gate 			**  Failure in step 1 or step 2.
336*7c478bd9Sstevel@tonic-gate 			**  Scan ap and free all exception arguments.
337*7c478bd9Sstevel@tonic-gate 			*/
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < argc; ++i)
340*7c478bd9Sstevel@tonic-gate 			{
341*7c478bd9Sstevel@tonic-gate 				switch (etype->etype_argformat[i])
342*7c478bd9Sstevel@tonic-gate 				{
343*7c478bd9Sstevel@tonic-gate 				  case 'i':
344*7c478bd9Sstevel@tonic-gate 					(void) SM_VA_ARG(ap, int);
345*7c478bd9Sstevel@tonic-gate 					break;
346*7c478bd9Sstevel@tonic-gate 				  case 'l':
347*7c478bd9Sstevel@tonic-gate 					(void) SM_VA_ARG(ap, long);
348*7c478bd9Sstevel@tonic-gate 					break;
349*7c478bd9Sstevel@tonic-gate 				  case 'e':
350*7c478bd9Sstevel@tonic-gate 					sm_exc_free(SM_VA_ARG(ap, SM_EXC_T*));
351*7c478bd9Sstevel@tonic-gate 					break;
352*7c478bd9Sstevel@tonic-gate 				  case 's':
353*7c478bd9Sstevel@tonic-gate 				  case 'r':
354*7c478bd9Sstevel@tonic-gate 					(void) SM_VA_ARG(ap, char*);
355*7c478bd9Sstevel@tonic-gate 					break;
356*7c478bd9Sstevel@tonic-gate 				}
357*7c478bd9Sstevel@tonic-gate 			}
358*7c478bd9Sstevel@tonic-gate 		}
359*7c478bd9Sstevel@tonic-gate 		else
360*7c478bd9Sstevel@tonic-gate 		{
361*7c478bd9Sstevel@tonic-gate 			/*
362*7c478bd9Sstevel@tonic-gate 			**  Failure in step 3.  Scan argv and free
363*7c478bd9Sstevel@tonic-gate 			**  all exception arguments and all string
364*7c478bd9Sstevel@tonic-gate 			**  arguments that have been duplicated.
365*7c478bd9Sstevel@tonic-gate 			**  Then free argv.
366*7c478bd9Sstevel@tonic-gate 			*/
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < argc; ++i)
369*7c478bd9Sstevel@tonic-gate 			{
370*7c478bd9Sstevel@tonic-gate 				switch (etype->etype_argformat[i])
371*7c478bd9Sstevel@tonic-gate 				{
372*7c478bd9Sstevel@tonic-gate 				  case 'e':
373*7c478bd9Sstevel@tonic-gate 					sm_exc_free(argv[i].v_exc);
374*7c478bd9Sstevel@tonic-gate 					break;
375*7c478bd9Sstevel@tonic-gate 				  case 's':
376*7c478bd9Sstevel@tonic-gate 				  case 'r':
377*7c478bd9Sstevel@tonic-gate 					if (i < si)
378*7c478bd9Sstevel@tonic-gate 						sm_free(argv[i].v_str);
379*7c478bd9Sstevel@tonic-gate 					break;
380*7c478bd9Sstevel@tonic-gate 				}
381*7c478bd9Sstevel@tonic-gate 			}
382*7c478bd9Sstevel@tonic-gate 			sm_free(argv);
383*7c478bd9Sstevel@tonic-gate 		}
384*7c478bd9Sstevel@tonic-gate 		sm_free(exc);
385*7c478bd9Sstevel@tonic-gate 		sm_exc_raise_x(e);
386*7c478bd9Sstevel@tonic-gate 	}
387*7c478bd9Sstevel@tonic-gate 	SM_END_TRY
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	return exc;
390*7c478bd9Sstevel@tonic-gate }
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate /*
393*7c478bd9Sstevel@tonic-gate **  SM_EXC_NEW_X -- Construct a new exception object.
394*7c478bd9Sstevel@tonic-gate **
395*7c478bd9Sstevel@tonic-gate **	Parameters:
396*7c478bd9Sstevel@tonic-gate **		etype -- type of exception.
397*7c478bd9Sstevel@tonic-gate **		... -- varargs.
398*7c478bd9Sstevel@tonic-gate **
399*7c478bd9Sstevel@tonic-gate **	Returns:
400*7c478bd9Sstevel@tonic-gate **		pointer to exception object.
401*7c478bd9Sstevel@tonic-gate */
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate SM_EXC_T *
404*7c478bd9Sstevel@tonic-gate #if SM_VA_STD
405*7c478bd9Sstevel@tonic-gate sm_exc_new_x(
406*7c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype,
407*7c478bd9Sstevel@tonic-gate 	...)
408*7c478bd9Sstevel@tonic-gate #else /* SM_VA_STD */
409*7c478bd9Sstevel@tonic-gate sm_exc_new_x(etype, va_alist)
410*7c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype;
411*7c478bd9Sstevel@tonic-gate 	va_dcl
412*7c478bd9Sstevel@tonic-gate #endif /* SM_VA_STD */
413*7c478bd9Sstevel@tonic-gate {
414*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
415*7c478bd9Sstevel@tonic-gate 	SM_VA_LOCAL_DECL
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	SM_VA_START(ap, etype);
418*7c478bd9Sstevel@tonic-gate 	exc = sm_exc_vnew_x(etype, ap);
419*7c478bd9Sstevel@tonic-gate 	SM_VA_END(ap);
420*7c478bd9Sstevel@tonic-gate 	return exc;
421*7c478bd9Sstevel@tonic-gate }
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate /*
424*7c478bd9Sstevel@tonic-gate **  SM_ADDREF -- Add a reference to an exception object.
425*7c478bd9Sstevel@tonic-gate **
426*7c478bd9Sstevel@tonic-gate **	Parameters:
427*7c478bd9Sstevel@tonic-gate **		exc -- exception object.
428*7c478bd9Sstevel@tonic-gate **
429*7c478bd9Sstevel@tonic-gate **	Returns:
430*7c478bd9Sstevel@tonic-gate **		exc itself.
431*7c478bd9Sstevel@tonic-gate */
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate SM_EXC_T *
434*7c478bd9Sstevel@tonic-gate sm_addref(exc)
435*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
436*7c478bd9Sstevel@tonic-gate {
437*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(exc, SmExcMagic);
438*7c478bd9Sstevel@tonic-gate 	if (exc->exc_refcount != 0)
439*7c478bd9Sstevel@tonic-gate 		++exc->exc_refcount;
440*7c478bd9Sstevel@tonic-gate 	return exc;
441*7c478bd9Sstevel@tonic-gate }
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate /*
444*7c478bd9Sstevel@tonic-gate **  SM_EXC_FREE -- Destroy a reference to an exception object.
445*7c478bd9Sstevel@tonic-gate **
446*7c478bd9Sstevel@tonic-gate **	Parameters:
447*7c478bd9Sstevel@tonic-gate **		exc -- exception object.
448*7c478bd9Sstevel@tonic-gate **
449*7c478bd9Sstevel@tonic-gate **	Returns:
450*7c478bd9Sstevel@tonic-gate **		none.
451*7c478bd9Sstevel@tonic-gate */
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate void
454*7c478bd9Sstevel@tonic-gate sm_exc_free(exc)
455*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
456*7c478bd9Sstevel@tonic-gate {
457*7c478bd9Sstevel@tonic-gate 	if (exc == NULL)
458*7c478bd9Sstevel@tonic-gate 		return;
459*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE(exc->sm_magic == SmExcMagic);
460*7c478bd9Sstevel@tonic-gate 	if (exc->exc_refcount == 0)
461*7c478bd9Sstevel@tonic-gate 		return;
462*7c478bd9Sstevel@tonic-gate 	if (--exc->exc_refcount == 0)
463*7c478bd9Sstevel@tonic-gate 	{
464*7c478bd9Sstevel@tonic-gate 		int i, c;
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 		for (i = 0; (c = exc->exc_type->etype_argformat[i]) != '\0';
467*7c478bd9Sstevel@tonic-gate 		     ++i)
468*7c478bd9Sstevel@tonic-gate 		{
469*7c478bd9Sstevel@tonic-gate 			switch (c)
470*7c478bd9Sstevel@tonic-gate 			{
471*7c478bd9Sstevel@tonic-gate 			  case 's':
472*7c478bd9Sstevel@tonic-gate 			  case 'r':
473*7c478bd9Sstevel@tonic-gate 				sm_free(exc->exc_argv[i].v_str);
474*7c478bd9Sstevel@tonic-gate 				break;
475*7c478bd9Sstevel@tonic-gate 			  case 'e':
476*7c478bd9Sstevel@tonic-gate 				sm_exc_free(exc->exc_argv[i].v_exc);
477*7c478bd9Sstevel@tonic-gate 				break;
478*7c478bd9Sstevel@tonic-gate 			}
479*7c478bd9Sstevel@tonic-gate 		}
480*7c478bd9Sstevel@tonic-gate 		exc->sm_magic = NULL;
481*7c478bd9Sstevel@tonic-gate 		sm_free(exc->exc_argv);
482*7c478bd9Sstevel@tonic-gate 		sm_free(exc);
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate }
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate /*
487*7c478bd9Sstevel@tonic-gate **  SM_EXC_MATCH -- Match exception category against a glob pattern.
488*7c478bd9Sstevel@tonic-gate **
489*7c478bd9Sstevel@tonic-gate **	Parameters:
490*7c478bd9Sstevel@tonic-gate **		exc -- exception.
491*7c478bd9Sstevel@tonic-gate **		pattern -- glob pattern.
492*7c478bd9Sstevel@tonic-gate **
493*7c478bd9Sstevel@tonic-gate **	Returns:
494*7c478bd9Sstevel@tonic-gate **		true iff match.
495*7c478bd9Sstevel@tonic-gate */
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate bool
498*7c478bd9Sstevel@tonic-gate sm_exc_match(exc, pattern)
499*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
500*7c478bd9Sstevel@tonic-gate 	const char *pattern;
501*7c478bd9Sstevel@tonic-gate {
502*7c478bd9Sstevel@tonic-gate 	if (exc == NULL)
503*7c478bd9Sstevel@tonic-gate 		return false;
504*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE(exc->sm_magic == SmExcMagic);
505*7c478bd9Sstevel@tonic-gate 	return sm_match(exc->exc_type->etype_category, pattern);
506*7c478bd9Sstevel@tonic-gate }
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate /*
509*7c478bd9Sstevel@tonic-gate **  SM_EXC_WRITE -- Write exception message to a stream (wo trailing newline).
510*7c478bd9Sstevel@tonic-gate **
511*7c478bd9Sstevel@tonic-gate **	Parameters:
512*7c478bd9Sstevel@tonic-gate **		exc -- exception.
513*7c478bd9Sstevel@tonic-gate **		stream -- file for output.
514*7c478bd9Sstevel@tonic-gate **
515*7c478bd9Sstevel@tonic-gate **	Returns:
516*7c478bd9Sstevel@tonic-gate **		none.
517*7c478bd9Sstevel@tonic-gate */
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate void
520*7c478bd9Sstevel@tonic-gate sm_exc_write(exc, stream)
521*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
522*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream;
523*7c478bd9Sstevel@tonic-gate {
524*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(exc, SmExcMagic);
525*7c478bd9Sstevel@tonic-gate 	exc->exc_type->etype_print(exc, stream);
526*7c478bd9Sstevel@tonic-gate }
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate /*
529*7c478bd9Sstevel@tonic-gate **  SM_EXC_PRINT -- Print exception message to a stream (with trailing newline).
530*7c478bd9Sstevel@tonic-gate **
531*7c478bd9Sstevel@tonic-gate **	Parameters:
532*7c478bd9Sstevel@tonic-gate **		exc -- exception.
533*7c478bd9Sstevel@tonic-gate **		stream -- file for output.
534*7c478bd9Sstevel@tonic-gate **
535*7c478bd9Sstevel@tonic-gate **	Returns:
536*7c478bd9Sstevel@tonic-gate **		none.
537*7c478bd9Sstevel@tonic-gate */
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate void
540*7c478bd9Sstevel@tonic-gate sm_exc_print(exc, stream)
541*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
542*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream;
543*7c478bd9Sstevel@tonic-gate {
544*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(exc, SmExcMagic);
545*7c478bd9Sstevel@tonic-gate 	exc->exc_type->etype_print(exc, stream);
546*7c478bd9Sstevel@tonic-gate 	(void) sm_io_putc(stream, SM_TIME_DEFAULT, '\n');
547*7c478bd9Sstevel@tonic-gate }
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate SM_EXC_HANDLER_T *SmExcHandler = NULL;
550*7c478bd9Sstevel@tonic-gate static SM_EXC_DEFAULT_HANDLER_T SmExcDefaultHandler = NULL;
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate /*
553*7c478bd9Sstevel@tonic-gate **  SM_EXC_NEWTHREAD -- Initialize exception handling for new process/thread.
554*7c478bd9Sstevel@tonic-gate **
555*7c478bd9Sstevel@tonic-gate **	Parameters:
556*7c478bd9Sstevel@tonic-gate **		h -- default exception handler.
557*7c478bd9Sstevel@tonic-gate **
558*7c478bd9Sstevel@tonic-gate **	Returns:
559*7c478bd9Sstevel@tonic-gate **		none.
560*7c478bd9Sstevel@tonic-gate */
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate /*
563*7c478bd9Sstevel@tonic-gate **  Initialize a new process or a new thread by clearing the
564*7c478bd9Sstevel@tonic-gate **  exception handler stack and optionally setting a default
565*7c478bd9Sstevel@tonic-gate **  exception handler function.  Call this at the beginning of main,
566*7c478bd9Sstevel@tonic-gate **  or in a new process after calling fork, or in a new thread.
567*7c478bd9Sstevel@tonic-gate **
568*7c478bd9Sstevel@tonic-gate **  This function is a luxury, not a necessity.
569*7c478bd9Sstevel@tonic-gate **  If h != NULL then you can get the same effect by
570*7c478bd9Sstevel@tonic-gate **  wrapping the body of main, or the body of a forked child
571*7c478bd9Sstevel@tonic-gate **  or a new thread in SM_TRY ... SM_EXCEPT(e,"*") h(e); SM_END_TRY.
572*7c478bd9Sstevel@tonic-gate */
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate void
575*7c478bd9Sstevel@tonic-gate sm_exc_newthread(h)
576*7c478bd9Sstevel@tonic-gate 	SM_EXC_DEFAULT_HANDLER_T h;
577*7c478bd9Sstevel@tonic-gate {
578*7c478bd9Sstevel@tonic-gate 	SmExcHandler = NULL;
579*7c478bd9Sstevel@tonic-gate 	SmExcDefaultHandler = h;
580*7c478bd9Sstevel@tonic-gate }
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate /*
583*7c478bd9Sstevel@tonic-gate **  SM_EXC_RAISE_X -- Raise an exception.
584*7c478bd9Sstevel@tonic-gate **
585*7c478bd9Sstevel@tonic-gate **	Parameters:
586*7c478bd9Sstevel@tonic-gate **		exc -- exception.
587*7c478bd9Sstevel@tonic-gate **
588*7c478bd9Sstevel@tonic-gate **	Returns:
589*7c478bd9Sstevel@tonic-gate **		doesn't.
590*7c478bd9Sstevel@tonic-gate */
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate void SM_DEAD_D
593*7c478bd9Sstevel@tonic-gate sm_exc_raise_x(exc)
594*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
595*7c478bd9Sstevel@tonic-gate {
596*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(exc, SmExcMagic);
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	if (SmExcHandler == NULL)
599*7c478bd9Sstevel@tonic-gate 	{
600*7c478bd9Sstevel@tonic-gate 		if (SmExcDefaultHandler != NULL)
601*7c478bd9Sstevel@tonic-gate 		{
602*7c478bd9Sstevel@tonic-gate 			SM_EXC_DEFAULT_HANDLER_T h;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 			/*
605*7c478bd9Sstevel@tonic-gate 			**  If defined, the default handler is expected
606*7c478bd9Sstevel@tonic-gate 			**  to terminate the current thread of execution
607*7c478bd9Sstevel@tonic-gate 			**  using exit() or pthread_exit().
608*7c478bd9Sstevel@tonic-gate 			**  If it instead returns normally, then we fall
609*7c478bd9Sstevel@tonic-gate 			**  through to the default case below.  If it
610*7c478bd9Sstevel@tonic-gate 			**  raises an exception, then sm_exc_raise_x is
611*7c478bd9Sstevel@tonic-gate 			**  re-entered and, because we set SmExcDefaultHandler
612*7c478bd9Sstevel@tonic-gate 			**  to NULL before invoking h, we will again
613*7c478bd9Sstevel@tonic-gate 			**  end up in the default case below.
614*7c478bd9Sstevel@tonic-gate 			*/
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 			h = SmExcDefaultHandler;
617*7c478bd9Sstevel@tonic-gate 			SmExcDefaultHandler = NULL;
618*7c478bd9Sstevel@tonic-gate 			(*h)(exc);
619*7c478bd9Sstevel@tonic-gate 		}
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 		/*
622*7c478bd9Sstevel@tonic-gate 		**  No exception handler, so print the error and exit.
623*7c478bd9Sstevel@tonic-gate 		**  To override this behaviour on a program wide basis,
624*7c478bd9Sstevel@tonic-gate 		**  call sm_exc_newthread or put an exception handler in main().
625*7c478bd9Sstevel@tonic-gate 		**
626*7c478bd9Sstevel@tonic-gate 		**  XXX TODO: map the exception category to an exit code
627*7c478bd9Sstevel@tonic-gate 		**  XXX from <sysexits.h>.
628*7c478bd9Sstevel@tonic-gate 		*/
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 		sm_exc_print(exc, smioerr);
631*7c478bd9Sstevel@tonic-gate 		exit(255);
632*7c478bd9Sstevel@tonic-gate 	}
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	if (SmExcHandler->eh_value == NULL)
635*7c478bd9Sstevel@tonic-gate 		SmExcHandler->eh_value = exc;
636*7c478bd9Sstevel@tonic-gate 	else
637*7c478bd9Sstevel@tonic-gate 		sm_exc_free(exc);
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	sm_longjmp_nosig(SmExcHandler->eh_context, 1);
640*7c478bd9Sstevel@tonic-gate }
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate /*
643*7c478bd9Sstevel@tonic-gate **  SM_EXC_RAISENEW_X -- shorthand for sm_exc_raise_x(sm_exc_new_x(...))
644*7c478bd9Sstevel@tonic-gate **
645*7c478bd9Sstevel@tonic-gate **	Parameters:
646*7c478bd9Sstevel@tonic-gate **		etype -- type of exception.
647*7c478bd9Sstevel@tonic-gate **		ap -- varargs.
648*7c478bd9Sstevel@tonic-gate **
649*7c478bd9Sstevel@tonic-gate **	Returns:
650*7c478bd9Sstevel@tonic-gate **		none.
651*7c478bd9Sstevel@tonic-gate */
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate void SM_DEAD_D
654*7c478bd9Sstevel@tonic-gate #if SM_VA_STD
655*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(
656*7c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype,
657*7c478bd9Sstevel@tonic-gate 	...)
658*7c478bd9Sstevel@tonic-gate #else
659*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(etype, va_alist)
660*7c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype;
661*7c478bd9Sstevel@tonic-gate 	va_dcl
662*7c478bd9Sstevel@tonic-gate #endif
663*7c478bd9Sstevel@tonic-gate {
664*7c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
665*7c478bd9Sstevel@tonic-gate 	SM_VA_LOCAL_DECL
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	SM_VA_START(ap, etype);
668*7c478bd9Sstevel@tonic-gate 	exc = sm_exc_vnew_x(etype, ap);
669*7c478bd9Sstevel@tonic-gate 	SM_VA_END(ap);
670*7c478bd9Sstevel@tonic-gate 	sm_exc_raise_x(exc);
671*7c478bd9Sstevel@tonic-gate }
672