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