diff options
author | Paul Gilbert | 2019-05-17 10:04:03 -1000 |
---|---|---|
committer | Paul Gilbert | 2019-05-24 18:21:06 -0700 |
commit | 0279143a62c2cdab635894103da03b43eba7cf9c (patch) | |
tree | fbc77cd007a4104204287825902601b6fb50bad1 /engines/glk/tads/tads2/error_handling.h | |
parent | 54d240d81f8858f7ad694c690fcf738b3ec8b89d (diff) | |
download | scummvm-rg350-0279143a62c2cdab635894103da03b43eba7cf9c.tar.gz scummvm-rg350-0279143a62c2cdab635894103da03b43eba7cf9c.tar.bz2 scummvm-rg350-0279143a62c2cdab635894103da03b43eba7cf9c.zip |
GLK: TADS2: Adding headers
Diffstat (limited to 'engines/glk/tads/tads2/error_handling.h')
-rw-r--r-- | engines/glk/tads/tads2/error_handling.h | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/engines/glk/tads/tads2/error_handling.h b/engines/glk/tads/tads2/error_handling.h new file mode 100644 index 0000000000..a225bbea74 --- /dev/null +++ b/engines/glk/tads/tads2/error_handling.h @@ -0,0 +1,338 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* Library error handling definitions + * 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. + */ + +#ifndef GLK_TADS_TADS2_ERROR_HANDLING +#define GLK_TADS_TADS2_ERROR_HANDLING + +#include "glk/tads/tads2/lib.h" +#include "glk/tads/osfrobtads.h" + +namespace Glk { +namespace TADS { +namespace TADS2 { + +// TODO: Clean away use of jmp_buf, since ScummVM doesn't allow it +struct jmp_buf {}; + +/** + * Maximum length of a facility identifier + */ +#define ERRFACMAX 6 + +union erradef { + int erraint; /* integer argument */ + char *errastr; /* text string argument */ +}; + +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 */ +}; + +#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 */ +}; + +/** + * 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 */ +struct errmdef { + uint errmerr; /* error number */ + char *errmtxt; /* text of error message */ +}; + +} // End of namespace TADS2 +} // End of namespace TADS +} // End of namespace Glk + +#endif |