Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / librols / handlecond.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)handlecond.c     1.22 04/05/09 Copyright 1985-2004 J. Schilling */
14 /*
15  *      setup/clear a condition handler for a software signal
16  */
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License version 2
20  * as published by the Free Software Foundation.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License along with
28  * this program; see the file COPYING.  If not, write to the Free Software
29  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30  */
31 /*
32  *      A procedure frame is marked to have handlers if the
33  *      previous freme pointer for this procedure is odd.
34  *      The even base value, in this case actually points to a SIGBLK which
35  *      holds the saved "real" frame pointer.
36  *      The SIGBLK mentioned above may me the start of a chain of SIGBLK's,
37  *      containing different handlers.
38  *
39  *      This will work on processors which support a frame pointer chain
40  *      on the stack.
41  *      On a processor which doesn't support this I think of a method
42  *      where handlecond() has an own chain of frames, holding chains of
43  *      SIGBLK's.
44  *      In this case, a parameter has to be added to handlecond() and
45  *      unhandlecond(). This parameter will be an opaque cookie which is zero
46  *      on the first call to handlecond() in a procedure.
47  *      A new cookie will be returned by handlecond() which must be used on
48  *      each subsequent call to handlecond() and unhandlecond() in the same
49  *      procedure.
50  *
51  *      Copyright (c) 1985-2004 J. Schilling
52  */
53 #include <mconfig.h>
54 #include <sigblk.h>
55 #include <standard.h>
56 #include <stdxlib.h>
57 #include <strdefs.h>
58 #include <avoffset.h>
59 #include <utypes.h>
60 #include <schily.h>
61
62 #if     !defined(AV_OFFSET) || !defined(FP_INDIR)
63 #       ifdef   HAVE_SCANSTACK
64 #       undef   HAVE_SCANSTACK
65 #       endif
66 #endif
67
68 #ifdef  HAVE_SCANSTACK
69 #include <stkframe.h>
70 #else
71 extern  SIGBLK  *__roothandle;
72 #endif  /* HAVE_SCANSTACK */
73
74 #define is_even(p)      ((((long)(p)) & 1) == 0)
75 #define even(p)         (((long)(p)) & ~1L)
76 #if defined(__sun) && defined(__i386)
77 /*
78  * Solaris x86 has a broken frame.h which defines the frame ptr to int.
79  */
80 #define odd(p)          (((Intptr_t)(p)) | 1)
81 #else
82 #define odd(p)          (void *)(((Intptr_t)(p)) | 1)
83 #endif
84
85 #ifdef  __future__
86 #define even(p)         (((long)(p)) - 1) /* will this work with 64 bit ?? */
87 #endif
88
89 EXPORT  void    starthandlecond __PR((SIGBLK *sp));
90
91 #ifdef  PROTOTYPES
92 EXPORT void
93 handlecond(const char   *signame,
94                 register SIGBLK *sp,
95                 int             (*func)(const char *, long, long),
96                 long            arg1)
97 #else
98 EXPORT void
99 handlecond(signame, sp, func, arg1)
100                 char    *signame;
101         register SIGBLK *sp;
102                 BOOL    (*func)();
103                 long    arg1;
104 #endif
105 {
106         register SIGBLK *this;
107         register SIGBLK *last = (SIGBLK *)NULL;
108 #ifdef  HAVE_SCANSTACK
109         struct frame    *fp   = (struct frame *)NULL;
110 #endif
111                 int     slen;
112
113         if (signame == NULL || (slen = strlen(signame)) == 0) {
114                 raisecond("handle_bad_name", (long)signame);
115                 abort();
116         }
117
118 #ifdef  HAVE_SCANSTACK
119         fp = (struct frame *)getfp();
120         fp = (struct frame *)fp->fr_savfp;      /* point to frame of caller */
121         if (is_even(fp->fr_savfp)) {
122                 /*
123                  * Easy case: no handlers yet
124                  * save real framepointer in sp->sb_savfp
125                  */
126                 sp->sb_savfp   = (long **)fp->fr_savfp;
127                 this = (SIGBLK *)NULL;
128         } else {
129                 this = (SIGBLK *)even(fp->fr_savfp);
130         }
131 #else
132         this = __roothandle;
133 #endif
134
135         for (; this; this = this->sb_signext) {
136                 if (this == sp) {
137                         /*
138                          * If a SIGBLK is reused, the name must not change.
139                          */
140                         if (this->sb_signame != NULL &&
141                             !streql(this->sb_signame, signame)) {
142                                 raisecond("handle_reused_block", (long)signame);
143                                 abort();
144                         }
145                         sp->sb_sigfun = func;
146                         sp->sb_sigarg = arg1;
147                         return;
148                 }
149                 if (this->sb_signame != NULL &&
150                     streql(this->sb_signame, signame)) {
151                         if (last == (SIGBLK *)NULL) {
152                                 /*
153                                  * 'this' is the first entry in chain
154                                  */
155                                 if (this->sb_signext == (SIGBLK *)NULL) {
156                                         /*
157                                          * only 'this' entry is in chain, copy
158                                          * saved real frame pointer into new sp
159                                          */
160                                         sp->sb_savfp = this->sb_savfp;
161                                 } else {
162 #ifdef  HAVE_SCANSTACK
163                                         /*
164                                          * make second entry first link in chain
165                                          */
166                                         this->sb_signext->sb_savfp =
167                                                                 this->sb_savfp;
168                                         fp->fr_savfp = odd(this->sb_signext);
169 #else
170                                         /*
171                                          * Cannot happen if scanning the stack
172                                          * is not possible...
173                                          */
174                                         raisecond("handle_is_empty", (long)0);
175                                         abort();
176 #endif
177                                 }
178                                 continue;       /* don't trash 'last' ptr */
179                         } else {
180                                 last->sb_signext = this->sb_signext;
181                         }
182                 }
183                 last = this;
184         }
185         sp->sb_signext = (SIGBLK *)NULL;
186         sp->sb_signame = signame;
187         sp->sb_siglen  = slen;
188         sp->sb_sigfun  = func;
189         sp->sb_sigarg  = arg1;
190         /*
191          * If there is a chain append to end of the chain, else make it first
192          */
193         if (last)
194                 last->sb_signext = sp;
195 #ifdef  HAVE_SCANSTACK
196         else
197                 fp->fr_savfp = odd(sp);
198 #else
199         /*
200          * Cannot happen if scanning the stack is not possible...
201          */
202         else {
203                 raisecond("handle_is_empty", (long)0);
204                 abort();
205         }
206 #endif
207 }
208
209 EXPORT void
210 starthandlecond(sp)
211         register SIGBLK *sp;
212 {
213 #ifdef  HAVE_SCANSTACK
214         struct frame    *fp = NULL;
215
216         /*
217          * As the SCO OpenServer C-Compiler has a bug that may cause
218          * the first function call to getfp() been done before the
219          * new stack frame is created, we call getfp() twice.
220          */
221         (void) getfp();
222 #endif
223
224         sp->sb_signext = (SIGBLK *)NULL;
225         sp->sb_signame = NULL;
226         sp->sb_siglen  = 0;
227         sp->sb_sigfun  = (handlefunc_t)NULL;
228         sp->sb_sigarg  = 0;
229
230 #ifdef  HAVE_SCANSTACK
231         fp = (struct frame *)getfp();
232         fp = (struct frame *)fp->fr_savfp;      /* point to frame of caller */
233
234         if (is_even(fp->fr_savfp)) {
235                 /*
236                  * Easy case: no handlers yet
237                  * save real framepointer in sp
238                  */
239                 sp->sb_savfp = (long **)fp->fr_savfp;
240                 fp->fr_savfp = odd(sp);
241         } else {
242                 raisecond("handle_not_empty", (long)0);
243                 abort();
244         }
245 #else
246         sp->sb_savfp    = (long **)__roothandle;
247         __roothandle    = sp;
248 #endif
249 }
250
251 EXPORT void
252 unhandlecond(sp)
253         register SIGBLK *sp;
254 {
255 #ifdef  HAVE_SCANSTACK
256         register struct frame   *fp;
257         register SIGBLK         *sps;
258
259         /*
260          * As the SCO OpenServer C-Compiler has a bug that may cause
261          * the first function call to getfp() been done before the
262          * new stack frame is created, we call getfp() twice.
263          */
264         (void) getfp();
265         fp = (struct frame *)getfp();
266         fp = (struct frame *)fp->fr_savfp;      /* point to frame of caller */
267
268         if (!is_even(fp->fr_savfp)) {                   /* if handlers      */
269                 sps = (SIGBLK *)even(fp->fr_savfp);     /* point to SIGBLK  */
270                                                         /* real framepointer */
271 #if defined(__sun) && defined(__i386)
272                 fp->fr_savfp = (intptr_t)sps->sb_savfp;
273 #else
274                 fp->fr_savfp = (struct frame *)sps->sb_savfp;
275 #endif
276         }
277 #else
278         if (__roothandle == NULL) {
279                 raisecond("handle_is_empty", (long)0);
280                 abort();
281         }
282         /*
283          * Pop top level handler chain.
284          */
285         __roothandle = (SIGBLK *)__roothandle->sb_savfp;
286 #endif
287 }