' Try/catch runtime demonstration ' ' This module implements the private signal and setjmp/longjmp state used by ' the companion try/catch macros. ' ' Ownership: Each Exception owns its string copies and replaces them only after ' a new copy has been allocated. ' ' This demonstration intentionally does not provide thread-safe exception ' delivery or an async-signal-safe allocation strategy. #include once "trycatch.bi" #define SIGINT 2 '' Interactive attention #define SIGILL 4 '' Illegal instruction #define SIGFPE 8 '' Floating point error #define SIGSEGV 11 '' Segmentation violation #define SIGTERM 15 '' Termination request #define SIGBREAK 21 '' Control-break #define SIGABRT 22 '' Abnormal termination (abort) extern "C" type __p_sig_fn_t as sub(byval as integer) declare function signal(byval as integer, byval as __p_sig_fn_t) as __p_sig_fn_t end extern type TryCatchCtx cur as TryCatch ptr oldsigabrt as __p_sig_fn_t oldsigsegv as __p_sig_fn_t oldsigfpe as __p_sig_fn_t oldsigill as __p_sig_fn_t oldsigterm as __p_sig_fn_t oldsigint as __p_sig_fn_t end type ' The signal handler and TryCatch constructors share one process-local context. '' FB-LINTER: DISABLE-NEXT-LINE FBL301 dim shared ctx as TryCatchCtx dim shared messages(0 to 31) as zstring * 32 private sub handler cdecl(byval sig as integer) if ctx.cur = 0 then error sig end if if sig < lbound(messages) orelse sig > ubound(messages) then error sig end if signal(sig, @handler) ctx.cur->ex = new Exception(messages(sig)) if ctx.cur->ex = 0 then error 7 end if var buf = @ctx.cur->buf ctx.cur = ctx.cur->prev crt.longjmp(buf, sig) end sub private sub __construc() constructor messages(SIGINT) = "Interactive attention" messages(SIGILL) = "Illegal instruction" messages(SIGFPE) = "Floating point error" messages(SIGSEGV) = "Segmentation violation" messages(SIGTERM) = "Termination request" messages(SIGBREAK) = "Control-break" messages(SIGABRT) = "Abnormal termination" ctx.oldsigabrt = signal(SIGABRT, @handler) ctx.oldsigsegv = signal(SIGSEGV, @handler) ctx.oldsigfpe = signal(SIGFPE, @handler) ctx.oldsigill = signal(SIGILL, @handler) ctx.oldsigterm = signal(SIGTERM, @handler) ctx.oldsigint = signal(SIGINT, @handler) end sub private sub __destruc() destructor signal(SIGABRT, ctx.oldsigabrt) signal(SIGSEGV, ctx.oldsigsegv) signal(SIGFPE, ctx.oldsigfpe) signal(SIGILL, ctx.oldsigill) signal(SIGTERM, ctx.oldsigterm) signal(SIGINT, ctx.oldsigint) end sub '' '' TryCatch '' constructor TryCatch() this.prev = ctx.cur ctx.cur = @this end constructor destructor TryCatch() if( ctx.cur = @this ) then ctx.cur = this.prev end if if this.ex <> 0 then delete this.ex end if end destructor sub TryCatch.throw_(file as zstring ptr, func as zstring ptr, line_ as integer) if ctx.cur = 0 then error 1 end if if this.ex = 0 then error 7 end if this.ex->file = file this.ex->func = func this.ex->line = line_ var buf = @ctx.cur->buf ctx.cur = ctx.cur->prev crt.longjmp(buf, 1) end sub sub TryCatch.throw_(ex as Exception ptr, file as zstring ptr, func as zstring ptr, line_ as integer) if ex = 0 then error 5 end if this.ex = ex throw_(file, func, line_) end sub sub TryCatch.throw_(msg as zstring ptr, file as zstring ptr, func as zstring ptr, line_ as integer) this.ex = new Exception(msg) if this.ex = 0 then error 7 end if throw_(file, func, line_) end sub '' '' Exception '' private sub CopyExceptionString(byref destination as zstring ptr, _ byval source as zstring ptr) dim as zstring ptr replacement if source = 0 then replacement = allocate(1) if replacement = 0 then error 7 *replacement = 0 else replacement = allocate(len(*source) + 1) if replacement = 0 then error 7 *replacement = *source end if if destination <> 0 then deallocate(destination) destination = replacement end sub constructor Exception() CopyExceptionString this.msg, @"" end constructor constructor Exception(msg as zstring ptr) CopyExceptionString this.msg, msg end constructor destructor Exception() if this.msg <> 0 then deallocate(this.msg) end if if this.file_ <> 0 then deallocate(this.file_) end if if this.func_ <> 0 then deallocate(this.func_) end if end destructor property Exception.message() as string return *this.msg end property property Exception.file() as string return iif(this.file_ <> 0, *this.file_, "") end property property Exception.file(file_ as zstring ptr) CopyExceptionString this.file_, file_ end property property Exception.func() as string return iif(this.func_ <> 0, *this.func_, "") end property property Exception.func(func_ as zstring ptr) CopyExceptionString this.func_, func_ end property property Exception.line() as integer return this.line_ end property property Exception.line(line_ as integer) this.line_ = line_ end property operator Exception.cast() as string operator = this.toString() end operator function Exception.toString() as string function = this.message & " exception threw at " & this.file & "(" & this.line & "):" & this.func & "()" end function ' End of trycatch.bas