Give the IPX dissector dissector hash tables for the IPX type and socket
[obnox/wireshark/wip.git] / except.c
1 /*
2  * Portable Exception Handling for ANSI C.
3  * Copyright (C) 1999 Kaz Kylheku <kaz@ashi.footprints.net>
4  *
5  * Free Software License:
6  *
7  * All rights are reserved by the author, with the following exceptions:
8  * Permission is granted to freely reproduce and distribute this software,
9  * possibly in exchange for a fee, provided that this copyright notice appears
10  * intact. Permission is also granted to adapt this software to produce
11  * derivative works, as long as the modified versions carry this copyright
12  * notice and additional notices stating that the work has been modified.
13  * This source code may be translated into executable form and incorporated
14  * into proprietary software; there is no requirement for such software to
15  * contain a copyright notice related to this source.
16  * $Id: except.c,v 1.1 2000/05/11 08:14:49 gram Exp $
17  * $Name:  $
18  */
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <limits.h>
25 #include "except.h"
26
27 #define XCEPT_BUFFER_SIZE       1024
28
29 #ifdef KAZLIB_RCSID
30 static const char rcsid[] = "$Id: except.c,v 1.1 2000/05/11 08:14:49 gram Exp $";
31 #endif
32
33 #define group except_group
34 #define code except_code
35 #define id except_id
36 #define message except_message
37 #define dyndata except_dyndata
38 #define func except_func
39 #define context except_context
40 #define id except_id
41 #define size except_size
42 #define obj except_obj
43 #define jmp except_jmp
44 #define down except_down
45 #define type except_type
46 #define catcher except_catcher
47 #define cleanup except_cleanup
48 #define info except_info
49
50 #ifdef KAZLIB_POSIX_THREADS
51
52 #include <pthread.h>
53
54 static pthread_mutex_t init_mtx = PTHREAD_MUTEX_INITIALIZER;
55 static int init_counter;
56 static pthread_key_t top_key;
57 static pthread_key_t uh_key;
58 static pthread_key_t alloc_key;
59 static pthread_key_t dealloc_key;
60 static void unhandled_catcher(except_t *);
61
62 #define get_top() ((struct except_stacknode *) pthread_getspecific(top_key))
63 #define set_top(T) (pthread_setspecific(top_key, (T)), (void)((T) == (struct except_stacknode *) 0))
64 #define set_catcher(C) (pthread_setspecific(uh_key, (void *) (C)), (void)((C) == (void (*)(except_t *)) 0))
65 #define set_alloc(A) (pthread_setspecific(alloc_key, (void *) (A)), (void)((A) == (void *(*)(size_t)) 0))
66 #define set_dealloc(D) (pthread_setspecific(dealloc_key, (void *) (D)), (void)((D) == (void (*)(void *)) 0))
67
68 static void (*get_catcher(void))(except_t *)
69 {
70     void (*catcher)(except_t *) = (void (*)(except_t *)) pthread_getspecific(uh_key);
71     return (catcher == 0) ? unhandled_catcher : catcher;
72 }
73
74 static void *(*get_alloc(void))(size_t)
75 {
76     void *(*alloc)(size_t) = (void *(*)(size_t)) pthread_getspecific(alloc_key);
77     return (alloc == 0) ? malloc : alloc;
78 }
79
80 static void (*get_dealloc(void))(void *)
81 {
82     void (*dealloc)(void *) = (void (*)(void *)) pthread_getspecific(dealloc_key);
83     return (dealloc == 0) ? free : dealloc;
84 }
85
86 int except_init(void)
87 {
88     int retval = 1;
89
90     pthread_mutex_lock(&init_mtx);
91
92     assert (init_counter < INT_MAX);
93
94     if (init_counter++ == 0) {
95         int top_ok = (pthread_key_create(&top_key, 0) == 0);
96         int uh_ok = (pthread_key_create(&uh_key, 0) == 0);
97         int alloc_ok = (pthread_key_create(&alloc_key, 0) == 0);
98         int dealloc_ok = (pthread_key_create(&dealloc_key, 0) == 0);
99        
100         if (!top_ok || !uh_ok || !alloc_ok || !dealloc_ok) {
101             retval = 0;
102             init_counter = 0;
103             if (top_ok)
104                 pthread_key_delete(top_key);
105             if (uh_ok)
106                 pthread_key_delete(uh_key);
107             if (alloc_ok)
108                 pthread_key_delete(alloc_key);
109             if (dealloc_ok)
110                 pthread_key_delete(dealloc_key);
111         }
112     }
113
114     pthread_mutex_unlock(&init_mtx);
115
116     return retval;
117 }
118
119 void except_deinit(void)
120 {
121     pthread_mutex_lock(&init_mtx);
122
123     assert (init_counter > 0);
124
125     if (--init_counter == 0) {
126         pthread_key_delete(top_key);
127         pthread_key_delete(uh_key);
128         pthread_key_delete(alloc_key);
129         pthread_key_delete(dealloc_key);
130     }
131
132     pthread_mutex_unlock(&init_mtx);
133 }
134
135 #else   /* no thread support */
136
137 static int init_counter;
138 static void unhandled_catcher(except_t *);
139 static void (*uh_catcher_ptr)(except_t *) = unhandled_catcher;
140 static void *(*allocator)(size_t) = malloc;
141 static void (*deallocator)(void *) = free;
142 static struct except_stacknode *stack_top;
143
144 #define get_top() (stack_top)
145 #define set_top(T) (stack_top = (T))
146 #define get_catcher() (uh_catcher_ptr)
147 #define set_catcher(C) (uh_catcher_ptr = (C))
148 #define get_alloc() (allocator)
149 #define set_alloc(A) (allocator = (A))
150 #define get_dealloc() (deallocator)
151 #define set_dealloc(D) (deallocator = (D))
152
153 int except_init(void)
154 {
155     assert (init_counter < INT_MAX);
156     init_counter++;
157     return 1;
158 }
159
160 void except_deinit(void)
161 {
162     assert (init_counter > 0);
163     init_counter--;
164 }
165
166 #endif
167
168
169 static int match(const except_id_t *thrown, const except_id_t *caught)
170 {
171     int group_match = (caught->group == XCEPT_GROUP_ANY || caught->group == thrown->group);
172     int code_match = (caught->code == XCEPT_CODE_ANY || caught->code == thrown->code);
173
174     return group_match && code_match;
175 }
176
177 static void do_throw(except_t *except)
178 {
179     struct except_stacknode *top;
180
181     assert (except->id.group != 0 && except->id.code != 0);
182
183     for (top = get_top(); top != 0; top = top->down) {
184         if (top->type == XCEPT_CLEANUP) {
185             top->info.cleanup->func(top->info.cleanup->context);
186         } else {
187             struct except_catch *catcher = top->info.catcher;
188             const except_id_t *pi = catcher->id;
189             size_t i;
190         
191             assert (top->type == XCEPT_CATCHER);
192             except_free(catcher->obj.dyndata);
193
194             for (i = 0; i < catcher->size; pi++, i++) {
195                 if (match(&except->id, pi)) {
196                     catcher->obj = *except;
197                     set_top(top);
198                     longjmp(catcher->jmp, 1);
199                 }
200             }
201         }
202     }
203
204     set_top(top);
205     get_catcher()(except);      /* unhandled exception */
206     abort();
207 }
208
209 static void unhandled_catcher(except_t *except)
210 {
211     fprintf(stderr, "Unhandled exception (\"%s\", group=%ld, code=%ld)\n",
212             except->message, except->id.group, except->id.code);
213     abort();
214 }
215
216 static void stack_push(struct except_stacknode *node)
217 {
218     node->down = get_top();
219     set_top(node);
220 }
221
222 void except_setup_clean(struct except_stacknode *esn,
223         struct except_cleanup *ecl, void (*cleanf)(void *), void *context)
224 {
225     esn->type = XCEPT_CLEANUP;
226     ecl->func = cleanf;
227     ecl->context = context;
228     esn->info.cleanup = ecl;
229     stack_push(esn);
230 }
231
232 void except_setup_try(struct except_stacknode *esn,
233         struct except_catch *ech, const except_id_t id[], size_t size)
234 {
235    ech->id = id;
236    ech->size = size;
237    ech->obj.dyndata = 0;
238    esn->type = XCEPT_CATCHER;
239    esn->info.catcher = ech;
240    stack_push(esn);
241 }
242
243 struct except_stacknode *except_pop(void)
244 {
245     struct except_stacknode *top = get_top();
246     set_top(top->down);
247     return top;
248 }
249
250 void except_rethrow(except_t *except)
251 {
252     struct except_stacknode *top = get_top();
253     assert (top != 0);
254     assert (top->type == XCEPT_CATCHER);
255     assert (&top->info.catcher->obj == except);
256     set_top(top->down);
257     do_throw(except);
258 }
259
260 void except_throw(long group, long code, const char *msg)
261 {
262     except_t except;
263
264     except.id.group = group;
265     except.id.code = code;
266     except.message = msg;
267     except.dyndata = 0;
268
269     do_throw(&except);
270 }
271
272 void except_throwd(long group, long code, const char *msg, void *data)
273 {
274     except_t except;
275
276     except.id.group = group;
277     except.id.code = code;
278     except.message = msg;
279     except.dyndata = data;
280
281     do_throw(&except);
282 }
283
284 void except_throwf(long group, long code, const char *fmt, ...)
285 {
286     char *buf = except_alloc(XCEPT_BUFFER_SIZE);
287     va_list vl;
288
289     va_start (vl, fmt);
290     vsprintf(buf, fmt, vl);
291     va_end (vl);
292     except_throwd(group, code, buf, buf);
293 }
294
295 void (*except_unhandled_catcher(void (*new_catcher)(except_t *)))(except_t *)
296 {
297     void (*old_catcher)(except_t *) = get_catcher();
298     set_catcher(new_catcher);
299     return old_catcher;
300 }
301
302 #undef except_code
303 #undef except_group
304 #undef except_message
305 #undef except_data
306
307 unsigned long except_code(except_t *ex)
308 {
309     return ex->id.code;
310 }
311
312 unsigned long except_group(except_t *ex)
313 {
314     return ex->id.group;
315 }
316
317 const char *except_message(except_t *ex)
318 {
319     return ex->message;
320 }
321
322 void *except_data(except_t *ex)
323 {
324     return ex->dyndata;
325 }
326
327 void *except_take_data(except_t *ex)
328 {
329     void *data = ex->dyndata;
330     ex->dyndata = 0;
331     return data;
332 }
333
334 void except_set_allocator(void *(*alloc)(size_t), void (*dealloc)(void *))
335 {
336     set_alloc(alloc);
337     set_dealloc(dealloc);
338 }
339
340 void *except_alloc(size_t size)
341 {
342     void *ptr = get_alloc()(size);
343
344     if (ptr == 0)
345         except_throw(XCEPT_BAD_ALLOC, 0, "out of memory");
346     return ptr;
347 }
348
349 void except_free(void *ptr)
350 {
351     get_dealloc()(ptr);
352 }
353
354 #ifdef KAZLIB_TEST_MAIN
355
356 #include <stdio.h>
357 #include <ctype.h>
358
359 static void cleanup(void *arg)
360 {
361     printf("cleanup(\"%s\") called\n", (char *) arg);
362 }
363
364 static void bottom_level(void)
365 {
366     char buf[256];
367     printf("throw exception? "); fflush(stdout);
368     fgets(buf, sizeof buf, stdin);
369
370     if (toupper(buf[0]) == 'Y')
371         except_throw(1, 1, "nasty exception");
372 }
373
374 static void top_level(void)
375 {
376     except_cleanup_push(cleanup, "argument");
377     bottom_level();
378     except_cleanup_pop(0);
379 }
380
381 int main(int argc, char **argv)
382 {
383     static const except_id_t catch[] = { { 1, 1 }, { 1, 2 } };
384     except_t *ex;
385
386     /*
387      * Nested exception ``try blocks''
388      */
389
390     /* outer */
391     except_try_push(catch, 2, &ex);
392     if (!ex) {
393         /* inner */
394         except_try_push(catch, 2, &ex);
395         if (!ex) {
396             top_level();
397         } else {
398             /* inner catch */
399             printf("caught exception (inner): \"%s\", s=%ld, c=%ld\n",
400                     except_message(ex), except_group(ex), except_code(ex));
401             except_rethrow(ex);
402         }
403         except_try_pop();
404     } else {
405         /* outer catch */
406         printf("caught exception (outer): \"%s\", s=%ld, c=%ld\n",
407                 except_message(ex), except_group(ex), except_code(ex));
408     }
409     except_try_pop();
410     except_throw(99, 99, "exception in main");
411     return 0;
412 }
413
414
415 #endif