diff options
Diffstat (limited to 'librols/handlecond.c')
-rw-r--r-- | librols/handlecond.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/librols/handlecond.c b/librols/handlecond.c new file mode 100644 index 0000000..06668b8 --- /dev/null +++ b/librols/handlecond.c @@ -0,0 +1,287 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)handlecond.c 1.22 04/05/09 Copyright 1985-2004 J. Schilling */ +/* + * setup/clear a condition handler for a software signal + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* + * A procedure frame is marked to have handlers if the + * previous freme pointer for this procedure is odd. + * The even base value, in this case actually points to a SIGBLK which + * holds the saved "real" frame pointer. + * The SIGBLK mentioned above may me the start of a chain of SIGBLK's, + * containing different handlers. + * + * This will work on processors which support a frame pointer chain + * on the stack. + * On a processor which doesn't support this I think of a method + * where handlecond() has an own chain of frames, holding chains of + * SIGBLK's. + * In this case, a parameter has to be added to handlecond() and + * unhandlecond(). This parameter will be an opaque cookie which is zero + * on the first call to handlecond() in a procedure. + * A new cookie will be returned by handlecond() which must be used on + * each subsequent call to handlecond() and unhandlecond() in the same + * procedure. + * + * Copyright (c) 1985-2004 J. Schilling + */ +#include <mconfig.h> +#include <sigblk.h> +#include <standard.h> +#include <stdxlib.h> +#include <strdefs.h> +#include <avoffset.h> +#include <utypes.h> +#include <schily.h> + +#if !defined(AV_OFFSET) || !defined(FP_INDIR) +# ifdef HAVE_SCANSTACK +# undef HAVE_SCANSTACK +# endif +#endif + +#ifdef HAVE_SCANSTACK +#include <stkframe.h> +#else +extern SIGBLK *__roothandle; +#endif /* HAVE_SCANSTACK */ + +#define is_even(p) ((((long)(p)) & 1) == 0) +#define even(p) (((long)(p)) & ~1L) +#if defined(__sun) && defined(__i386) +/* + * Solaris x86 has a broken frame.h which defines the frame ptr to int. + */ +#define odd(p) (((Intptr_t)(p)) | 1) +#else +#define odd(p) (void *)(((Intptr_t)(p)) | 1) +#endif + +#ifdef __future__ +#define even(p) (((long)(p)) - 1) /* will this work with 64 bit ?? */ +#endif + +EXPORT void starthandlecond __PR((SIGBLK *sp)); + +#ifdef PROTOTYPES +EXPORT void +handlecond(const char *signame, + register SIGBLK *sp, + int (*func)(const char *, long, long), + long arg1) +#else +EXPORT void +handlecond(signame, sp, func, arg1) + char *signame; + register SIGBLK *sp; + BOOL (*func)(); + long arg1; +#endif +{ + register SIGBLK *this; + register SIGBLK *last = (SIGBLK *)NULL; +#ifdef HAVE_SCANSTACK + struct frame *fp = (struct frame *)NULL; +#endif + int slen; + + if (signame == NULL || (slen = strlen(signame)) == 0) { + raisecond("handle_bad_name", (long)signame); + abort(); + } + +#ifdef HAVE_SCANSTACK + fp = (struct frame *)getfp(); + fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */ + if (is_even(fp->fr_savfp)) { + /* + * Easy case: no handlers yet + * save real framepointer in sp->sb_savfp + */ + sp->sb_savfp = (long **)fp->fr_savfp; + this = (SIGBLK *)NULL; + } else { + this = (SIGBLK *)even(fp->fr_savfp); + } +#else + this = __roothandle; +#endif + + for (; this; this = this->sb_signext) { + if (this == sp) { + /* + * If a SIGBLK is reused, the name must not change. + */ + if (this->sb_signame != NULL && + !streql(this->sb_signame, signame)) { + raisecond("handle_reused_block", (long)signame); + abort(); + } + sp->sb_sigfun = func; + sp->sb_sigarg = arg1; + return; + } + if (this->sb_signame != NULL && + streql(this->sb_signame, signame)) { + if (last == (SIGBLK *)NULL) { + /* + * 'this' is the first entry in chain + */ + if (this->sb_signext == (SIGBLK *)NULL) { + /* + * only 'this' entry is in chain, copy + * saved real frame pointer into new sp + */ + sp->sb_savfp = this->sb_savfp; + } else { +#ifdef HAVE_SCANSTACK + /* + * make second entry first link in chain + */ + this->sb_signext->sb_savfp = + this->sb_savfp; + fp->fr_savfp = odd(this->sb_signext); +#else + /* + * Cannot happen if scanning the stack + * is not possible... + */ + raisecond("handle_is_empty", (long)0); + abort(); +#endif + } + continue; /* don't trash 'last' ptr */ + } else { + last->sb_signext = this->sb_signext; + } + } + last = this; + } + sp->sb_signext = (SIGBLK *)NULL; + sp->sb_signame = signame; + sp->sb_siglen = slen; + sp->sb_sigfun = func; + sp->sb_sigarg = arg1; + /* + * If there is a chain append to end of the chain, else make it first + */ + if (last) + last->sb_signext = sp; +#ifdef HAVE_SCANSTACK + else + fp->fr_savfp = odd(sp); +#else + /* + * Cannot happen if scanning the stack is not possible... + */ + else { + raisecond("handle_is_empty", (long)0); + abort(); + } +#endif +} + +EXPORT void +starthandlecond(sp) + register SIGBLK *sp; +{ +#ifdef HAVE_SCANSTACK + struct frame *fp = NULL; + + /* + * As the SCO OpenServer C-Compiler has a bug that may cause + * the first function call to getfp() been done before the + * new stack frame is created, we call getfp() twice. + */ + (void) getfp(); +#endif + + sp->sb_signext = (SIGBLK *)NULL; + sp->sb_signame = NULL; + sp->sb_siglen = 0; + sp->sb_sigfun = (handlefunc_t)NULL; + sp->sb_sigarg = 0; + +#ifdef HAVE_SCANSTACK + fp = (struct frame *)getfp(); + fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */ + + if (is_even(fp->fr_savfp)) { + /* + * Easy case: no handlers yet + * save real framepointer in sp + */ + sp->sb_savfp = (long **)fp->fr_savfp; + fp->fr_savfp = odd(sp); + } else { + raisecond("handle_not_empty", (long)0); + abort(); + } +#else + sp->sb_savfp = (long **)__roothandle; + __roothandle = sp; +#endif +} + +EXPORT void +unhandlecond(sp) + register SIGBLK *sp; +{ +#ifdef HAVE_SCANSTACK + register struct frame *fp; + register SIGBLK *sps; + + /* + * As the SCO OpenServer C-Compiler has a bug that may cause + * the first function call to getfp() been done before the + * new stack frame is created, we call getfp() twice. + */ + (void) getfp(); + fp = (struct frame *)getfp(); + fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */ + + if (!is_even(fp->fr_savfp)) { /* if handlers */ + sps = (SIGBLK *)even(fp->fr_savfp); /* point to SIGBLK */ + /* real framepointer */ +#if defined(__sun) && defined(__i386) + fp->fr_savfp = (intptr_t)sps->sb_savfp; +#else + fp->fr_savfp = (struct frame *)sps->sb_savfp; +#endif + } +#else + if (__roothandle == NULL) { + raisecond("handle_is_empty", (long)0); + abort(); + } + /* + * Pop top level handler chain. + */ + __roothandle = (SIGBLK *)__roothandle->sb_savfp; +#endif +} |