xref: /freebsd/contrib/sendmail/include/sm/exc.h (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
1 /*
2  * Copyright (c) 2000-2001 Proofpoint, 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  *	$Id: exc.h,v 1.24 2013-11-22 20:51:31 ca Exp $
10  */
11 
12 /*
13 **  libsm exception handling
14 **  See libsm/exc.html for documentation.
15 */
16 
17 #ifndef SM_EXC_H
18 # define SM_EXC_H
19 
20 #include <sm/setjmp.h>
21 #include <sm/io.h>
22 #include <sm/gen.h>
23 #include <sm/assert.h>
24 
25 typedef struct sm_exc SM_EXC_T;
26 typedef struct sm_exc_type SM_EXC_TYPE_T;
27 typedef union sm_val SM_VAL_T;
28 
29 /*
30 **  Exception types
31 */
32 
33 extern const char SmExcTypeMagic[];
34 
35 struct sm_exc_type
36 {
37 	const char	*sm_magic;
38 	const char	*etype_category;
39 	const char	*etype_argformat;
40 	void		(*etype_print) __P((SM_EXC_T *, SM_FILE_T *));
41 	const char	*etype_printcontext;
42 };
43 
44 extern const SM_EXC_TYPE_T SmEtypeOs;
45 extern const SM_EXC_TYPE_T SmEtypeErr;
46 
47 extern void
48 sm_etype_printf __P((
49 	SM_EXC_T *_exc,
50 	SM_FILE_T *_stream));
51 
52 /*
53 **  Exception objects
54 */
55 
56 extern const char SmExcMagic[];
57 
58 union sm_val
59 {
60 	int		v_int;
61 	long		v_long;
62 	char		*v_str;
63 	SM_EXC_T	*v_exc;
64 };
65 
66 struct sm_exc
67 {
68 	const char		*sm_magic;
69 	size_t			exc_refcount;
70 	const SM_EXC_TYPE_T	*exc_type;
71 	SM_VAL_T		*exc_argv;
72 };
73 
74 # define SM_EXC_INITIALIZER(type, argv) \
75 	{ \
76 		SmExcMagic, \
77 		0, \
78 		type, \
79 		argv, \
80 	}
81 
82 extern SM_EXC_T *
83 sm_exc_new_x __P((
84 	const SM_EXC_TYPE_T *_type,
85 	...));
86 
87 extern SM_EXC_T *
88 sm_exc_addref __P((
89 	SM_EXC_T *_exc));
90 
91 extern void
92 sm_exc_free __P((
93 	SM_EXC_T *_exc));
94 
95 extern bool
96 sm_exc_match __P((
97 	SM_EXC_T *_exc,
98 	const char *_pattern));
99 
100 extern void
101 sm_exc_write __P((
102 	SM_EXC_T *_exc,
103 	SM_FILE_T *_stream));
104 
105 extern void
106 sm_exc_print __P((
107 	SM_EXC_T *_exc,
108 	SM_FILE_T *_stream));
109 
110 extern SM_DEAD(void
111 sm_exc_raise_x __P((
112 	SM_EXC_T *_exc)));
113 
114 extern SM_DEAD(void
115 sm_exc_raisenew_x __P((
116 	const SM_EXC_TYPE_T *_type,
117 	...)));
118 
119 /*
120 **  Exception handling
121 */
122 
123 typedef void (*SM_EXC_DEFAULT_HANDLER_T) __P((SM_EXC_T *));
124 
125 extern void
126 sm_exc_newthread __P((
127 	SM_EXC_DEFAULT_HANDLER_T _handle));
128 
129 typedef struct sm_exc_handler SM_EXC_HANDLER_T;
130 struct sm_exc_handler
131 {
132 	SM_EXC_T		*eh_value;
133 	SM_JMPBUF_T		eh_context;
134 	SM_EXC_HANDLER_T	*eh_parent;
135 	int			eh_state;
136 };
137 
138 /* values for eh_state */
139 enum
140 {
141 	SM_EH_PUSHED = 2,
142 	SM_EH_POPPED = 0,
143 	SM_EH_HANDLED = 1
144 };
145 
146 extern SM_EXC_HANDLER_T *SmExcHandler;
147 
148 # define SM_TRY		{ SM_EXC_HANDLER_T _h; \
149 			  do { \
150 			    _h.eh_value = NULL; \
151 			    _h.eh_parent = SmExcHandler; \
152 			    _h.eh_state = SM_EH_PUSHED; \
153 			    SmExcHandler = &_h; \
154 			    if (sm_setjmp_nosig(_h.eh_context) == 0) {
155 
156 # define SM_FINALLY	      SM_ASSERT(SmExcHandler == &_h); \
157 			    } \
158 			    if (sm_setjmp_nosig(_h.eh_context) == 0) {
159 
160 # define SM_EXCEPT(e,pat)   } \
161 			    if (_h.eh_state == SM_EH_HANDLED) \
162 			      break; \
163 			    if (_h.eh_state == SM_EH_PUSHED) { \
164 			      SM_ASSERT(SmExcHandler == &_h); \
165 			      SmExcHandler = _h.eh_parent; \
166 			    } \
167 			    _h.eh_state = sm_exc_match(_h.eh_value,pat) \
168 			      ? SM_EH_HANDLED : SM_EH_POPPED; \
169 			    if (_h.eh_state == SM_EH_HANDLED) { \
170 			      SM_UNUSED(SM_EXC_T *e) = _h.eh_value;
171 
172 # define SM_END_TRY	  } \
173 			  } while (0); \
174 			  if (_h.eh_state == SM_EH_PUSHED) { \
175 			    SM_ASSERT(SmExcHandler == &_h); \
176 			    SmExcHandler = _h.eh_parent; \
177 			    if (_h.eh_value != NULL) \
178 			      sm_exc_raise_x(_h.eh_value); \
179 			  } else if (_h.eh_state == SM_EH_POPPED) { \
180 			    if (_h.eh_value != NULL) \
181 			      sm_exc_raise_x(_h.eh_value); \
182 			  } else \
183 			    sm_exc_free(_h.eh_value); \
184 			}
185 
186 #endif /* SM_EXC_H */
187