-
Notifications
You must be signed in to change notification settings - Fork 176
/
try.c
73 lines (66 loc) · 2.55 KB
/
try.c
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
/* try.c -- try / catch / throw exception handling for C99
* For copyright, version, and conditions of distribution and use, see try.h
*/
/* See try.h for documentation. This source file provides the global pointer
and the functions needed by throw(). The pointer is thread-unique if
pthread.h is included in try.h. */
#include "try.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
/* Set up the try stack with a global pointer to the next try block. The
global is thread-unique if pthread.h is included in try.h. */
#ifdef PTHREAD_ONCE_INIT
pthread_key_t try_key_;
static pthread_once_t try_once_ = PTHREAD_ONCE_INIT;
static void try_create_(void)
{
int ret = pthread_key_create(&try_key_, NULL);
assert(ret == 0 && "try: pthread_key_create() failed");
}
void try_setup_(void)
{
int ret = pthread_once(&try_once_, try_create_);
assert(ret == 0 && "try: pthread_once() failed");
}
#else /* !PTHREAD_ONCE_INIT */
try_t_ *try_stack_ = NULL;
#endif /* PTHREAD_ONCE_INIT */
/* Throw an exception. This must always have at least two arguments, where the
second argument can be a NULL. The throw() macro is permitted to have one
argument, since it appends a NULL argument in the call to this function. */
void try_throw_(int code, char *fmt, ...)
{
/* save the thrown information in the try stack before jumping */
try_setup_();
assert(try_stack_ != NULL && "try: naked throw");
try_stack_->ball.ret = 1;
try_stack_->ball.code = code;
try_stack_->ball.free = 0;
try_stack_->ball.why = fmt;
/* consider the second argument to be a string, and if it has formatting
commands, process them with the subsequent arguments of throw, saving
the result in allocated memory -- this if statement and clause must be
updated for a different interpretation of the throw() arguments and
different contents of the ball_t structure */
if (fmt != NULL && strchr(fmt, '%') != NULL) {
char *why, nul[1];
size_t len;
va_list ap1, ap2;
va_start(ap1, fmt);
va_copy(ap2, ap1);
len = vsnprintf(nul, 1, fmt, ap1);
va_end(ap1);
why = malloc(len + 1);
if (why == NULL)
try_stack_->ball.why = "try: out of memory";
else {
vsnprintf(why, len + 1, fmt, ap2);
va_end(ap2);
try_stack_->ball.free = 1;
try_stack_->ball.why = why;
}
}
/* jump to the end of the nearest enclosing try block */
longjmp(try_stack_->env, 1);
}