-
Notifications
You must be signed in to change notification settings - Fork 1
/
ler.h
338 lines (278 loc) · 11.1 KB
/
ler.h
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/*
$Header: d:/cvsroot/tads/TADS2/LER.H,v 1.2 1999/05/17 02:52:12 MJRoberts Exp $
*/
/*
* Copyright (c) 1991, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
ler.h - library error handling definitions
Function
Defines error handling mechanism
Notes
All of the functions and macros in here are named ERRxxx because
this file was based on the TADS err.h, which used the ERRxxx naming
convention, and it would be a lot of trouble to change.
This package defines a set of macros that allows code to raise and
handle exceptions. A macro is provided which signals an error, which
does a non-local goto to the innermost enclosing exception handler.
A set of macros sets up exception handling code.
To catch exceptions that occur inside a block of code (i.e., in the
code or in any subroutines called by the code), begin the block with
ERRBEGIN. At the end of the protected code, place the exception
handler, which starts with ERRCATCH. At the end of the exception
handler, place ERREND. If no exception occurs, execution goes
through the protected code, then resumes at the code following
the ERREND.
The exception handler can signal another error, which will cause
the next enclosing frame to catch the error. Alternatively, if
the exception handler doesn't signal an error or return, execution
continues at the code following the ERREND. Exceptions that are
signalled during exception handling will be caught by the next
enclosing frame, unless the exception handler code is itself
protected by another ERRBEGIN-ERREND block.
To signal an error, use errsig().
To use a string argument in a signalled error, cover the string
with errstr(ctx, str, len); for example:
errsig1(ctx, ERR_XYZ, ERRTSTR, errstr(ctx, buf, strlen(buf)));
This copies the string into a buffer that is unaffected by
stack resetting during error signalling.
Modified
10/23/97 CNebel - fixed warnings from Metrowerks C compiler.
12/30/92 MJRoberts - created from TADS err.h
09/14/92 MJRoberts - add errlog2
08/15/91 MJRoberts - creation
*/
#ifndef LER_INCLUDED
#define LER_INCLUDED
#include "os.h"
#ifndef LIB_INCLUDED
#include "lib.h"
#endif
#include <setjmp.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
/* maximum length of a facility identifier */
#define ERRFACMAX 6
union erradef
{
int erraint; /* integer argument */
char *errastr; /* text string argument */
};
typedef union erradef erradef;
struct errdef
{
struct errdef *errprv; /* previous error frame */
int errcode; /* error code of exception being handled */
char errfac[ERRFACMAX+1]; /* facility of current error */
erradef erraav[10]; /* parameters for error */
int erraac; /* count of parameters in argc */
jmp_buf errbuf; /* jump buffer for current error frame */
};
typedef struct errdef errdef;
#define ERRBUFSIZ 512
/* seek location record for an error message by number */
struct errmfdef
{
uint errmfnum; /* error number */
ulong errmfseek; /* seek location of this message */
};
typedef struct errmfdef errmfdef;
struct errcxdef
{
errdef *errcxptr; /* current error frame */
void (*errcxlog)(void *, char *fac, int err, int argc, erradef *);
/* error logging callback function */
void *errcxlgc; /* context for error logging callback */
int errcxofs; /* offset in argument buffer */
char errcxbuf[ERRBUFSIZ]; /* space for argument strings */
osfildef *errcxfp; /* message file, if one is being used */
errmfdef *errcxseek; /* seek locations of messages in file */
uint errcxsksz; /* size of errcxseek array */
ulong errcxbase; /* offset in physical file of logical error file */
struct appctxdef *errcxappctx; /* host application context */
};
typedef struct errcxdef errcxdef;
/* begin protected code */
#define ERRBEGIN(ctx) \
{ \
errdef fr_; \
if ((fr_.errcode = setjmp(fr_.errbuf)) == 0) \
{ \
fr_.errprv = (ctx)->errcxptr; \
(ctx)->errcxptr = &fr_;
/* end protected code, begin error handler */
#define ERRCATCH(ctx, e) \
assert(1==1 && (ctx)->errcxptr != fr_.errprv); \
(ctx)->errcxptr = fr_.errprv; \
} \
else \
{ \
assert(2==2 && (ctx)->errcxptr != fr_.errprv); \
(e) = fr_.errcode; \
(ctx)->errcxptr = fr_.errprv;
/* retrieve argument (int, string) in current error frame */
#define errargint(argnum) (fr_.erraav[argnum].erraint)
#define errargstr(argnum) (fr_.erraav[argnum].errastr)
#define ERREND(ctx) \
} \
}
/* end protected code, begin cleanup (no handling; just cleaning up) */
#define ERRCLEAN(ctx) \
assert((ctx)->errcxptr != fr_.errprv); \
(ctx)->errcxptr = fr_.errprv; \
} \
else \
{ \
assert((ctx)->errcxptr != fr_.errprv); \
(ctx)->errcxptr = fr_.errprv;
#define ERRENDCLN(ctx) \
errrse(ctx); \
} \
}
/* argument types for errors with arguments */
#define ERRTINT erraint
#define ERRTSTR errastr
/* set argument count in error frame */
#define errargc(ctx,cnt) ((ctx)->errcxptr->erraac=(cnt))
/* enter string argument; returns pointer to argument used in errargv */
#ifdef ERR_NO_MACRO
char *errstr(errcxdef *ctx, const char *str, int len);
#else /* ERR_NO_MACRO */
#define errstr(ctx,str,len) \
((memcpy(&(ctx)->errcxbuf[(ctx)->errcxofs],str,(size_t)len), \
(ctx)->errcxofs += (len), \
(ctx)->errcxbuf[(ctx)->errcxofs++] = '\0'), \
&(ctx)->errcxbuf[(ctx)->errcxofs-(len)-1])
#endif /* ERR_NO_MACRO */
/* set argument in error frame argument vector */
#define errargv(ctx,index,typ,arg) \
((ctx)->errcxptr->erraav[index].typ=(arg))
/* signal an error with argument count already set */
#ifdef ERR_NO_MACRO
void errsign(errcxdef *ctx, int e, char *facility);
#else /* ERR_NO_MACRO */
# ifdef DEBUG
void errjmp(jmp_buf buf, int e);
# define errsign(ctx, e, fac) \
(strncpy((ctx)->errcxptr->errfac, fac, ERRFACMAX),\
(ctx)->errcxptr->errfac[ERRFACMAX]='\0',\
(ctx)->errcxofs=0, errjmp((ctx)->errcxptr->errbuf, e))
# else /* DEBUG */
# define errsign(ctx, e, fac) \
(strncpy((ctx)->errcxptr->errfac, fac, ERRFACMAX),\
(ctx)->errcxptr->errfac[ERRFACMAX]='\0',\
(ctx)->errcxofs=0, longjmp((ctx)->errcxptr->errbuf, e))
# endif /* DEBUG */
#endif /* ERR_NO_MACRO */
/* signal an error with no arguments */
#ifdef ERR_NO_MACRO
void errsigf(errcxdef *ctx, char *facility, int err);
#else /* ERR_NO_MACRO */
#define errsigf(ctx, fac, e) (errargc(ctx,0),errsign(ctx,e,fac))
#endif /* ERR_NO_MACRO */
/* signal an error with one argument */
#define errsigf1(ctx, fac, e, typ1, arg1) \
(errargv(ctx,0,typ1,arg1),errargc(ctx,1),errsign(ctx,e,fac))
/* signal an error with two arguments */
#define errsigf2(ctx, fac, e, typ1, arg1, typ2, arg2) \
(errargv(ctx,0,typ1,arg1), errargv(ctx,1,typ2,arg2), \
errargc(ctx,2), errsign(ctx,e,fac))
/* resignal the current error - only usable within exception handlers */
#ifdef ERR_NO_MACRO
void errrse1(errcxdef *ctx, errdef *fr);
# define errrse(ctx) errrse1(ctx, &fr_)
#else /* ERR_NO_MACRO */
/* void errrse(errcxdef *ctx); */
# define errrse(ctx) \
(errargc(ctx, fr_.erraac),\
memcpy((ctx)->errcxptr->erraav, fr_.erraav, \
(size_t)(fr_.erraac*sizeof(erradef))),\
errsign(ctx, fr_.errcode, fr_.errfac))
#endif /* ERR_NO_MACRO */
/*
* For use in an error handler (ERRCATCH..ERREND) only: Copy the
* parameters from the error currently being handled to the enclosing
* frame. This is useful when "keeping" an error being handled - i.e.,
* the arguments will continue to be used outside of the
* ERRCATCH..ERREND code.
*/
/* void errkeepargs(errcxdef *ctx); */
#define errkeepargs(ctx) errcopyargs(ctx, &fr_)
/*
* copy the parameters for an error from another frame into the current
* frame - this can be used when we want to be able to display an error
* that occurred in an inner frame within code that is protected by a
* new enclosing error frame
*/
/* void errcopyargs(errcxdef *ctx, errdef *fr); */
#define errcopyargs(ctx, fr) \
(errargc((ctx), (fr)->erraac), \
memcpy((ctx)->errcxptr->erraav, (fr)->erraav, \
(size_t)((fr)->erraac*sizeof(erradef))))
/* log error that's been caught, using arguments already caught */
#define errclog(ctx) \
((*(ctx)->errcxlog)((ctx)->errcxlgc,fr_.errfac,fr_.errcode,\
fr_.erraac,fr_.erraav))
/* log an error that's been set up but not signalled yet */
#define errprelog(ctx, err) \
((*(ctx)->errcxlog)((ctx)->errcxlgc,(ctx)->errcxptr->errfac,\
err,(ctx)->errcxptr->erraac,\
(ctx)->errcxptr->erraav))
/* log an error (no signalling, just reporting) */
#ifdef ERR_NO_MACRO
void errlogn(errcxdef *ctx, int err, char *facility);
#else /* ERR_NO_MACRO */
#define errlogn(ctx,err,fac) \
((ctx)->errcxofs=0,\
(*(ctx)->errcxlog)((ctx)->errcxlgc,fac,err,(ctx)->errcxptr->erraac,\
(ctx)->errcxptr->erraav))
#endif /* ERR_NO_MACRO */
/* log an error with no arguments */
#ifdef ERR_NO_MACRO
void errlogf(errcxdef *ctx, char *facility, int err);
#else /* ERR_NO_MACRO */
/* void errlogf(errcxdef *ctx, char *facility, int err); */
#define errlogf(ctx,fac,err) (errargc(ctx,0),errlogn(ctx,err,fac))
#endif /* ERR_NO_MACRO */
/* log an error with one argument */
#define errlogf1(ctx, fac, e, typ1, arg1) \
(errargv(ctx,0,typ1,arg1),errargc(ctx,1),errlogn(ctx,e,fac))
/* log an error with two arguments */
#define errlogf2(ctx, fac, e, typ1, arg1, typ2, arg2) \
(errargv(ctx,0,typ1,arg1),errargv(ctx,1,typ2,arg2),\
errargc(ctx,2),errlogn(ctx,e,fac))
/*
* Format an error message, sprintf-style, using arguments in an
* erradef array (which is passed to the error-logging callback).
* Returns the length of the output string, even if the actual
* output string was truncated because the outbuf was too short.
* (If called with outbufl == 0, nothing will be written out, but
* the size of the buffer needed, minus the terminating null byte,
* will be computed and returned.)
*/
int errfmt(char *outbuf, int outbufl, char *fmt, int argc,
erradef *argv);
/* get the text of an error */
void errmsg(errcxdef *ctx, char *outbuf, uint outbufl, uint err);
/* initialize error subsystem, opening error message file if necessary */
void errini(errcxdef *ctx, osfildef *fp);
/* allocate and initialize error context, free error context */
errcxdef *lerini();
void lerfre(errcxdef *ctx);
/* error message structure - number + text */
typedef struct errmdef errmdef;
struct errmdef
{
uint errmerr; /* error number */
char *errmtxt; /* text of error message */
};
#ifdef __cplusplus
}
#endif
#endif /* ERR_INCLUDED */