1b30d1939SAndy Fiddaman /***********************************************************************
2b30d1939SAndy Fiddaman *                                                                      *
3b30d1939SAndy Fiddaman *               This software is part of the ast package               *
4b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5b30d1939SAndy Fiddaman *                      and is licensed under the                       *
6b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
7b30d1939SAndy Fiddaman *                    by AT&T Intellectual Property                     *
8b30d1939SAndy Fiddaman *                                                                      *
9b30d1939SAndy Fiddaman *                A copy of the License is available at                 *
10b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12b30d1939SAndy Fiddaman *                                                                      *
13b30d1939SAndy Fiddaman *              Information and Software Systems Research               *
14b30d1939SAndy Fiddaman *                            AT&T Research                             *
15b30d1939SAndy Fiddaman *                           Florham Park NJ                            *
16b30d1939SAndy Fiddaman *                                                                      *
17b30d1939SAndy Fiddaman *                 Glenn Fowler <gsf@research.att.com>                  *
18b30d1939SAndy Fiddaman *                  David Korn <dgk@research.att.com>                   *
19b30d1939SAndy Fiddaman *                   Phong Vo <kpv@research.att.com>                    *
20b30d1939SAndy Fiddaman *                                                                      *
21b30d1939SAndy Fiddaman ***********************************************************************/
22b30d1939SAndy Fiddaman #pragma prototyped
23b30d1939SAndy Fiddaman /*
24b30d1939SAndy Fiddaman  *   Routines to implement a stack-like storage library
25b30d1939SAndy Fiddaman  *
26b30d1939SAndy Fiddaman  *   A stack consists of a link list of variable size frames
27b30d1939SAndy Fiddaman  *   The beginning of each frame is initialized with a frame structure
28b30d1939SAndy Fiddaman  *   that contains a pointer to the previous frame and a pointer to the
29b30d1939SAndy Fiddaman  *   end of the current frame.
30b30d1939SAndy Fiddaman  *
31b30d1939SAndy Fiddaman  *   This is a rewrite of the stk library that uses sfio
32b30d1939SAndy Fiddaman  *
33b30d1939SAndy Fiddaman  *   David Korn
34b30d1939SAndy Fiddaman  *   AT&T Research
35b30d1939SAndy Fiddaman  *   dgk@research.att.com
36b30d1939SAndy Fiddaman  *
37b30d1939SAndy Fiddaman  */
38b30d1939SAndy Fiddaman 
39b30d1939SAndy Fiddaman #include	<sfio_t.h>
40b30d1939SAndy Fiddaman #include	<ast.h>
41b30d1939SAndy Fiddaman #include	<align.h>
42b30d1939SAndy Fiddaman #include	<stk.h>
43b30d1939SAndy Fiddaman 
44b30d1939SAndy Fiddaman /*
45b30d1939SAndy Fiddaman  *  A stack is a header and a linked list of frames
46b30d1939SAndy Fiddaman  *  The first frame has structure
47b30d1939SAndy Fiddaman  *	Sfio_t
48b30d1939SAndy Fiddaman  *	Sfdisc_t
49b30d1939SAndy Fiddaman  *	struct stk
50b30d1939SAndy Fiddaman  * Frames have structure
51b30d1939SAndy Fiddaman  *	struct frame
52b30d1939SAndy Fiddaman  *	data
53b30d1939SAndy Fiddaman  */
54b30d1939SAndy Fiddaman 
55b30d1939SAndy Fiddaman #define STK_ALIGN	ALIGN_BOUND
56b30d1939SAndy Fiddaman #define STK_FSIZE	(1024*sizeof(char*))
57b30d1939SAndy Fiddaman #define STK_HDRSIZE	(sizeof(Sfio_t)+sizeof(Sfdisc_t))
58b30d1939SAndy Fiddaman 
59b30d1939SAndy Fiddaman typedef char* (*_stk_overflow_)(int);
60b30d1939SAndy Fiddaman 
61b30d1939SAndy Fiddaman static int stkexcept(Sfio_t*,int,void*,Sfdisc_t*);
62b30d1939SAndy Fiddaman static Sfdisc_t stkdisc = { 0, 0, 0, stkexcept };
63b30d1939SAndy Fiddaman 
64b30d1939SAndy Fiddaman Sfio_t _Stak_data = SFNEW((char*)0,0,-1,SF_STATIC|SF_WRITE|SF_STRING,&stkdisc,0);
65b30d1939SAndy Fiddaman 
66b30d1939SAndy Fiddaman __EXTERN__(Sfio_t, _Stak_data);
67b30d1939SAndy Fiddaman 
68b30d1939SAndy Fiddaman struct frame
69b30d1939SAndy Fiddaman {
70b30d1939SAndy Fiddaman 	char	*prev;		/* address of previous frame */
71b30d1939SAndy Fiddaman 	char	*end;		/* address of end this frame */
72b30d1939SAndy Fiddaman 	char	**aliases;	/* address aliases */
73b30d1939SAndy Fiddaman 	int	nalias;		/* number of aliases */
74b30d1939SAndy Fiddaman };
75b30d1939SAndy Fiddaman 
76b30d1939SAndy Fiddaman struct stk
77b30d1939SAndy Fiddaman {
78b30d1939SAndy Fiddaman 	_stk_overflow_	stkoverflow;	/* called when malloc fails */
79b30d1939SAndy Fiddaman 	short		stkref;	/* reference count; */
80b30d1939SAndy Fiddaman 	short		stkflags;	/* stack attributes */
81b30d1939SAndy Fiddaman 	char		*stkbase;	/* beginning of current stack frame */
82b30d1939SAndy Fiddaman 	char		*stkend;	/* end of current stack frame */
83b30d1939SAndy Fiddaman };
84b30d1939SAndy Fiddaman 
85b30d1939SAndy Fiddaman static size_t		init;		/* 1 when initialized */
86b30d1939SAndy Fiddaman static struct stk	*stkcur;	/* pointer to current stk */
87b30d1939SAndy Fiddaman static char		*stkgrow(Sfio_t*, size_t);
88b30d1939SAndy Fiddaman 
89b30d1939SAndy Fiddaman #define stream2stk(stream)	((stream)==stkstd? stkcur:\
90b30d1939SAndy Fiddaman 				 ((struct stk*)(((char*)(stream))+STK_HDRSIZE)))
91b30d1939SAndy Fiddaman #define stk2stream(sp)		((Sfio_t*)(((char*)(sp))-STK_HDRSIZE))
92b30d1939SAndy Fiddaman #define stkleft(stream)		((stream)->_endb-(stream)->_data)
93b30d1939SAndy Fiddaman 
94b30d1939SAndy Fiddaman 
95b30d1939SAndy Fiddaman #ifdef STKSTATS
96b30d1939SAndy Fiddaman     static struct
97b30d1939SAndy Fiddaman     {
98b30d1939SAndy Fiddaman 	int	create;
99b30d1939SAndy Fiddaman 	int	delete;
100b30d1939SAndy Fiddaman 	int	install;
101b30d1939SAndy Fiddaman 	int	alloc;
102b30d1939SAndy Fiddaman 	int	copy;
103b30d1939SAndy Fiddaman 	int	puts;
104b30d1939SAndy Fiddaman 	int	seek;
105b30d1939SAndy Fiddaman 	int	set;
106b30d1939SAndy Fiddaman 	int	grow;
107b30d1939SAndy Fiddaman 	int	addsize;
108b30d1939SAndy Fiddaman 	int	delsize;
109b30d1939SAndy Fiddaman 	int	movsize;
110b30d1939SAndy Fiddaman     } _stkstats;
111b30d1939SAndy Fiddaman #   define increment(x)	(_stkstats.x++)
112b30d1939SAndy Fiddaman #   define count(x,n)	(_stkstats.x += (n))
113b30d1939SAndy Fiddaman #else
114b30d1939SAndy Fiddaman #   define increment(x)
115b30d1939SAndy Fiddaman #   define count(x,n)
116b30d1939SAndy Fiddaman #endif /* STKSTATS */
117b30d1939SAndy Fiddaman 
118b30d1939SAndy Fiddaman static const char Omsg[] = "malloc failed while growing stack\n";
119b30d1939SAndy Fiddaman 
120b30d1939SAndy Fiddaman /*
121b30d1939SAndy Fiddaman  * default overflow exception
122b30d1939SAndy Fiddaman  */
overflow(int n)123b30d1939SAndy Fiddaman static char *overflow(int n)
124b30d1939SAndy Fiddaman {
125b30d1939SAndy Fiddaman 	NoP(n);
126b30d1939SAndy Fiddaman 	write(2,Omsg, sizeof(Omsg)-1);
127b30d1939SAndy Fiddaman 	exit(2);
128b30d1939SAndy Fiddaman 	/* NOTREACHED */
129b30d1939SAndy Fiddaman 	return(0);
130b30d1939SAndy Fiddaman }
131b30d1939SAndy Fiddaman 
132b30d1939SAndy Fiddaman /*
133b30d1939SAndy Fiddaman  * initialize stkstd, sfio operations may have already occcured
134b30d1939SAndy Fiddaman  */
stkinit(size_t size)135b30d1939SAndy Fiddaman static void stkinit(size_t size)
136b30d1939SAndy Fiddaman {
137b30d1939SAndy Fiddaman 	register Sfio_t *sp;
138b30d1939SAndy Fiddaman 	init = size;
139b30d1939SAndy Fiddaman 	sp = stkopen(0);
140b30d1939SAndy Fiddaman 	init = 1;
141b30d1939SAndy Fiddaman 	stkinstall(sp,overflow);
142b30d1939SAndy Fiddaman }
143b30d1939SAndy Fiddaman 
stkexcept(register Sfio_t * stream,int type,void * val,Sfdisc_t * dp)144b30d1939SAndy Fiddaman static int stkexcept(register Sfio_t *stream, int type, void* val, Sfdisc_t* dp)
145b30d1939SAndy Fiddaman {
146b30d1939SAndy Fiddaman 	NoP(dp);
147b30d1939SAndy Fiddaman 	NoP(val);
148b30d1939SAndy Fiddaman 	switch(type)
149b30d1939SAndy Fiddaman 	{
150b30d1939SAndy Fiddaman 	    case SF_CLOSING:
151b30d1939SAndy Fiddaman 		{
152b30d1939SAndy Fiddaman 			register struct stk *sp = stream2stk(stream);
153b30d1939SAndy Fiddaman 			register char *cp = sp->stkbase;
154b30d1939SAndy Fiddaman 			register struct frame *fp;
155b30d1939SAndy Fiddaman 			if(--sp->stkref<=0)
156b30d1939SAndy Fiddaman 			{
157b30d1939SAndy Fiddaman 				increment(delete);
158b30d1939SAndy Fiddaman 				if(stream==stkstd)
159b30d1939SAndy Fiddaman 					stkset(stream,(char*)0,0);
160b30d1939SAndy Fiddaman 				else
161b30d1939SAndy Fiddaman 				{
162b30d1939SAndy Fiddaman 					while(1)
163b30d1939SAndy Fiddaman 					{
164b30d1939SAndy Fiddaman 						fp = (struct frame*)cp;
165b30d1939SAndy Fiddaman 						if(fp->prev)
166b30d1939SAndy Fiddaman 						{
167b30d1939SAndy Fiddaman 							cp = fp->prev;
168b30d1939SAndy Fiddaman 							free(fp);
169b30d1939SAndy Fiddaman 						}
170b30d1939SAndy Fiddaman 						else
171b30d1939SAndy Fiddaman 						{
172b30d1939SAndy Fiddaman 							free(fp);
173b30d1939SAndy Fiddaman 							break;
174b30d1939SAndy Fiddaman 						}
175b30d1939SAndy Fiddaman 					}
176b30d1939SAndy Fiddaman 				}
177b30d1939SAndy Fiddaman 			}
178b30d1939SAndy Fiddaman 			stream->_data = stream->_next = 0;
179b30d1939SAndy Fiddaman 		}
180b30d1939SAndy Fiddaman 		return(0);
181b30d1939SAndy Fiddaman 	    case SF_FINAL:
182b30d1939SAndy Fiddaman 		free(stream);
183b30d1939SAndy Fiddaman 		return(1);
184b30d1939SAndy Fiddaman 	    case SF_DPOP:
185b30d1939SAndy Fiddaman 		return(-1);
186b30d1939SAndy Fiddaman 	    case SF_WRITE:
187b30d1939SAndy Fiddaman 	    case SF_SEEK:
188b30d1939SAndy Fiddaman 		{
189b30d1939SAndy Fiddaman 			long size = sfvalue(stream);
190b30d1939SAndy Fiddaman 			if(init)
191b30d1939SAndy Fiddaman 			{
192b30d1939SAndy Fiddaman 				Sfio_t *old = 0;
193b30d1939SAndy Fiddaman 				if(stream!=stkstd)
194b30d1939SAndy Fiddaman 					old = stkinstall(stream,NiL);
195b30d1939SAndy Fiddaman 				if(!stkgrow(stkstd,size-(stkstd->_endb-stkstd->_data)))
196b30d1939SAndy Fiddaman 					return(-1);
197b30d1939SAndy Fiddaman 				if(old)
198b30d1939SAndy Fiddaman 					stkinstall(old,NiL);
199b30d1939SAndy Fiddaman 			}
200b30d1939SAndy Fiddaman 			else
201b30d1939SAndy Fiddaman 				stkinit(size);
202b30d1939SAndy Fiddaman 		}
203b30d1939SAndy Fiddaman 		return(1);
204b30d1939SAndy Fiddaman 	    case SF_NEW:
205b30d1939SAndy Fiddaman 		return(-1);
206b30d1939SAndy Fiddaman 	}
207b30d1939SAndy Fiddaman 	return(0);
208b30d1939SAndy Fiddaman }
209b30d1939SAndy Fiddaman 
210b30d1939SAndy Fiddaman /*
211b30d1939SAndy Fiddaman  * create a stack
212b30d1939SAndy Fiddaman  */
stkopen(int flags)213b30d1939SAndy Fiddaman Sfio_t *stkopen(int flags)
214b30d1939SAndy Fiddaman {
215b30d1939SAndy Fiddaman 	register size_t bsize;
216b30d1939SAndy Fiddaman 	register Sfio_t *stream;
217b30d1939SAndy Fiddaman 	register struct stk *sp;
218b30d1939SAndy Fiddaman 	register struct frame *fp;
219b30d1939SAndy Fiddaman 	register Sfdisc_t *dp;
220b30d1939SAndy Fiddaman 	register char *cp;
221b30d1939SAndy Fiddaman 	if(!(stream=newof((char*)0,Sfio_t, 1, sizeof(*dp)+sizeof(*sp))))
222b30d1939SAndy Fiddaman 		return(0);
223b30d1939SAndy Fiddaman 	increment(create);
224b30d1939SAndy Fiddaman 	count(addsize,sizeof(*stream)+sizeof(*dp)+sizeof(*sp));
225b30d1939SAndy Fiddaman 	dp = (Sfdisc_t*)(stream+1);
226b30d1939SAndy Fiddaman 	dp->exceptf = stkexcept;
227b30d1939SAndy Fiddaman 	sp = (struct stk*)(dp+1);
228b30d1939SAndy Fiddaman 	sp->stkref = 1;
229b30d1939SAndy Fiddaman 	sp->stkflags = (flags&STK_SMALL);
230b30d1939SAndy Fiddaman 	if(flags&STK_NULL) sp->stkoverflow = 0;
231b30d1939SAndy Fiddaman 	else sp->stkoverflow = stkcur?stkcur->stkoverflow:overflow;
232b30d1939SAndy Fiddaman 	bsize = init+sizeof(struct frame);
233b30d1939SAndy Fiddaman #ifndef USE_REALLOC
234b30d1939SAndy Fiddaman 	if(flags&STK_SMALL)
235b30d1939SAndy Fiddaman 		bsize = roundof(bsize,STK_FSIZE/16);
236b30d1939SAndy Fiddaman 	else
237b30d1939SAndy Fiddaman #endif /* USE_REALLOC */
238b30d1939SAndy Fiddaman 		bsize = roundof(bsize,STK_FSIZE);
239b30d1939SAndy Fiddaman 	bsize -= sizeof(struct frame);
240b30d1939SAndy Fiddaman 	if(!(fp=newof((char*)0,struct frame, 1,bsize)))
241b30d1939SAndy Fiddaman 	{
242b30d1939SAndy Fiddaman 		free(stream);
243b30d1939SAndy Fiddaman 		return(0);
244b30d1939SAndy Fiddaman 	}
245b30d1939SAndy Fiddaman 	count(addsize,sizeof(*fp)+bsize);
246b30d1939SAndy Fiddaman 	cp = (char*)(fp+1);
247b30d1939SAndy Fiddaman 	sp->stkbase = (char*)fp;
248b30d1939SAndy Fiddaman 	fp->prev = 0;
249b30d1939SAndy Fiddaman 	fp->nalias = 0;
250b30d1939SAndy Fiddaman 	fp->aliases = 0;
251b30d1939SAndy Fiddaman 	fp->end = sp->stkend = cp+bsize;
252b30d1939SAndy Fiddaman 	if(!sfnew(stream,cp,bsize,-1,SF_STRING|SF_WRITE|SF_STATIC|SF_EOF))
253b30d1939SAndy Fiddaman 		return((Sfio_t*)0);
254b30d1939SAndy Fiddaman 	sfdisc(stream,dp);
255b30d1939SAndy Fiddaman 	return(stream);
256b30d1939SAndy Fiddaman }
257b30d1939SAndy Fiddaman 
258b30d1939SAndy Fiddaman /*
259b30d1939SAndy Fiddaman  * return a pointer to the current stack
260b30d1939SAndy Fiddaman  * if <stream> is not null, it becomes the new current stack
261b30d1939SAndy Fiddaman  * <oflow> becomes the new overflow function
262b30d1939SAndy Fiddaman  */
stkinstall(Sfio_t * stream,_stk_overflow_ oflow)263b30d1939SAndy Fiddaman Sfio_t *stkinstall(Sfio_t *stream, _stk_overflow_ oflow)
264b30d1939SAndy Fiddaman {
265b30d1939SAndy Fiddaman 	Sfio_t *old;
266b30d1939SAndy Fiddaman 	register struct stk *sp;
267b30d1939SAndy Fiddaman 	if(!init)
268b30d1939SAndy Fiddaman 	{
269b30d1939SAndy Fiddaman 		stkinit(1);
270b30d1939SAndy Fiddaman 		if(oflow)
271b30d1939SAndy Fiddaman 			stkcur->stkoverflow = oflow;
272b30d1939SAndy Fiddaman 		return((Sfio_t*)0);
273b30d1939SAndy Fiddaman 	}
274b30d1939SAndy Fiddaman 	increment(install);
275b30d1939SAndy Fiddaman 	old = stkcur?stk2stream(stkcur):0;
276b30d1939SAndy Fiddaman 	if(stream)
277b30d1939SAndy Fiddaman 	{
278b30d1939SAndy Fiddaman 		sp = stream2stk(stream);
279b30d1939SAndy Fiddaman 		while(sfstack(stkstd, SF_POPSTACK));
280b30d1939SAndy Fiddaman 		if(stream!=stkstd)
281b30d1939SAndy Fiddaman 			sfstack(stkstd,stream);
282b30d1939SAndy Fiddaman 		stkcur = sp;
283b30d1939SAndy Fiddaman #ifdef USE_REALLOC
284b30d1939SAndy Fiddaman 		/*** someday ***/
285b30d1939SAndy Fiddaman #endif /* USE_REALLOC */
286b30d1939SAndy Fiddaman 	}
287b30d1939SAndy Fiddaman 	else
288b30d1939SAndy Fiddaman 		sp = stkcur;
289b30d1939SAndy Fiddaman 	if(oflow)
290b30d1939SAndy Fiddaman 		sp->stkoverflow = oflow;
291b30d1939SAndy Fiddaman 	return(old);
292b30d1939SAndy Fiddaman }
293b30d1939SAndy Fiddaman 
294b30d1939SAndy Fiddaman /*
295b30d1939SAndy Fiddaman  * increase the reference count on the given <stack>
296b30d1939SAndy Fiddaman  */
stklink(register Sfio_t * stream)297b30d1939SAndy Fiddaman int stklink(register Sfio_t* stream)
298b30d1939SAndy Fiddaman {
299b30d1939SAndy Fiddaman 	register struct stk *sp = stream2stk(stream);
300b30d1939SAndy Fiddaman 	return(sp->stkref++);
301b30d1939SAndy Fiddaman }
302b30d1939SAndy Fiddaman 
303b30d1939SAndy Fiddaman /*
304b30d1939SAndy Fiddaman  * terminate a stack and free up the space
305b30d1939SAndy Fiddaman  * >0 returned if reference decremented but still > 0
306b30d1939SAndy Fiddaman  *  0 returned on last close
307b30d1939SAndy Fiddaman  * <0 returned on error
308b30d1939SAndy Fiddaman  */
stkclose(Sfio_t * stream)309b30d1939SAndy Fiddaman int stkclose(Sfio_t* stream)
310b30d1939SAndy Fiddaman {
311b30d1939SAndy Fiddaman 	register struct stk *sp = stream2stk(stream);
312b30d1939SAndy Fiddaman 	if(sp->stkref>1)
313b30d1939SAndy Fiddaman 	{
314b30d1939SAndy Fiddaman 		sp->stkref--;
315b30d1939SAndy Fiddaman 		return(1);
316b30d1939SAndy Fiddaman 	}
317b30d1939SAndy Fiddaman 	return(sfclose(stream));
318b30d1939SAndy Fiddaman }
319b30d1939SAndy Fiddaman 
320b30d1939SAndy Fiddaman /*
321b30d1939SAndy Fiddaman  * returns 1 if <loc> is on this stack
322b30d1939SAndy Fiddaman  */
stkon(register Sfio_t * stream,register char * loc)323b30d1939SAndy Fiddaman int stkon(register Sfio_t * stream, register char* loc)
324b30d1939SAndy Fiddaman {
325b30d1939SAndy Fiddaman 	register struct stk *sp = stream2stk(stream);
326b30d1939SAndy Fiddaman 	register struct frame *fp;
327b30d1939SAndy Fiddaman 	for(fp=(struct frame*)sp->stkbase; fp; fp=(struct frame*)fp->prev)
328b30d1939SAndy Fiddaman 		if(loc>=((char*)(fp+1)) && loc< fp->end)
329b30d1939SAndy Fiddaman 			return(1);
330b30d1939SAndy Fiddaman 	return(0);
331b30d1939SAndy Fiddaman }
332b30d1939SAndy Fiddaman /*
333b30d1939SAndy Fiddaman  * reset the bottom of the current stack back to <loc>
334*3636ae54SAndy Fiddaman  * if <loc> is null, then the stack is reset to the beginning
335*3636ae54SAndy Fiddaman  * if <loc> is not in this stack, the program dumps core
336b30d1939SAndy Fiddaman  * otherwise, the top of the stack is set to stkbot+<offset>
337b30d1939SAndy Fiddaman  */
stkset(register Sfio_t * stream,register char * loc,size_t offset)338b30d1939SAndy Fiddaman char *stkset(register Sfio_t * stream, register char* loc, size_t offset)
339b30d1939SAndy Fiddaman {
340b30d1939SAndy Fiddaman 	register struct stk *sp = stream2stk(stream);
341b30d1939SAndy Fiddaman 	register char *cp;
342b30d1939SAndy Fiddaman 	register struct frame *fp;
343b30d1939SAndy Fiddaman 	register int frames = 0;
344b30d1939SAndy Fiddaman 	int n;
345b30d1939SAndy Fiddaman 	if(!init)
346b30d1939SAndy Fiddaman 		stkinit(offset+1);
347b30d1939SAndy Fiddaman 	increment(set);
348b30d1939SAndy Fiddaman 	while(1)
349b30d1939SAndy Fiddaman 	{
350b30d1939SAndy Fiddaman 		fp = (struct frame*)sp->stkbase;
351b30d1939SAndy Fiddaman 		cp = sp->stkbase + roundof(sizeof(struct frame), STK_ALIGN);
352b30d1939SAndy Fiddaman 		n = fp->nalias;
353b30d1939SAndy Fiddaman 		while(n-->0)
354b30d1939SAndy Fiddaman 		{
355b30d1939SAndy Fiddaman 			if(loc==fp->aliases[n])
356b30d1939SAndy Fiddaman 			{
357b30d1939SAndy Fiddaman 				loc = cp;
358b30d1939SAndy Fiddaman 				break;
359b30d1939SAndy Fiddaman 			}
360b30d1939SAndy Fiddaman 		}
361b30d1939SAndy Fiddaman 		/* see whether <loc> is in current stack frame */
362b30d1939SAndy Fiddaman 		if(loc>=cp && loc<=sp->stkend)
363b30d1939SAndy Fiddaman 		{
364b30d1939SAndy Fiddaman 			if(frames)
365b30d1939SAndy Fiddaman 				sfsetbuf(stream,cp,sp->stkend-cp);
366b30d1939SAndy Fiddaman 			stream->_data = (unsigned char*)(cp + roundof(loc-cp,STK_ALIGN));
367b30d1939SAndy Fiddaman 			stream->_next = (unsigned char*)loc+offset;
368b30d1939SAndy Fiddaman 			goto found;
369b30d1939SAndy Fiddaman 		}
370b30d1939SAndy Fiddaman 		if(fp->prev)
371b30d1939SAndy Fiddaman 		{
372b30d1939SAndy Fiddaman 			sp->stkbase = fp->prev;
373b30d1939SAndy Fiddaman 			sp->stkend = ((struct frame*)(fp->prev))->end;
374b30d1939SAndy Fiddaman 			free((void*)fp);
375b30d1939SAndy Fiddaman 		}
376b30d1939SAndy Fiddaman 		else
377b30d1939SAndy Fiddaman 			break;
378b30d1939SAndy Fiddaman 		frames++;
379b30d1939SAndy Fiddaman 	}
380*3636ae54SAndy Fiddaman 	/* not found: produce a useful stack trace now instead of a useless one later */
381*3636ae54SAndy Fiddaman 	if(loc)
382*3636ae54SAndy Fiddaman 		abort();
383b30d1939SAndy Fiddaman 	/* set stack back to the beginning */
384b30d1939SAndy Fiddaman 	cp = (char*)(fp+1);
385b30d1939SAndy Fiddaman 	if(frames)
386b30d1939SAndy Fiddaman 		sfsetbuf(stream,cp,sp->stkend-cp);
387b30d1939SAndy Fiddaman 	else
388b30d1939SAndy Fiddaman 		stream->_data = stream->_next = (unsigned char*)cp;
389b30d1939SAndy Fiddaman found:
390b30d1939SAndy Fiddaman 	return((char*)stream->_data);
391b30d1939SAndy Fiddaman }
392b30d1939SAndy Fiddaman 
393b30d1939SAndy Fiddaman /*
394b30d1939SAndy Fiddaman  * allocate <n> bytes on the current stack
395b30d1939SAndy Fiddaman  */
stkalloc(register Sfio_t * stream,register size_t n)396b30d1939SAndy Fiddaman char *stkalloc(register Sfio_t *stream, register size_t n)
397b30d1939SAndy Fiddaman {
398b30d1939SAndy Fiddaman 	register unsigned char *old;
399b30d1939SAndy Fiddaman 	if(!init)
400b30d1939SAndy Fiddaman 		stkinit(n);
401b30d1939SAndy Fiddaman 	increment(alloc);
402b30d1939SAndy Fiddaman 	n = roundof(n,STK_ALIGN);
403b30d1939SAndy Fiddaman 	if(stkleft(stream) <= (int)n && !stkgrow(stream,n))
404b30d1939SAndy Fiddaman 		return(0);
405b30d1939SAndy Fiddaman 	old = stream->_data;
406b30d1939SAndy Fiddaman 	stream->_data = stream->_next = old+n;
407b30d1939SAndy Fiddaman 	return((char*)old);
408b30d1939SAndy Fiddaman }
409b30d1939SAndy Fiddaman 
410b30d1939SAndy Fiddaman /*
411b30d1939SAndy Fiddaman  * begin a new stack word of at least <n> bytes
412b30d1939SAndy Fiddaman  */
_stkseek(register Sfio_t * stream,register ssize_t n)413b30d1939SAndy Fiddaman char *_stkseek(register Sfio_t *stream, register ssize_t n)
414b30d1939SAndy Fiddaman {
415b30d1939SAndy Fiddaman 	if(!init)
416b30d1939SAndy Fiddaman 		stkinit(n);
417b30d1939SAndy Fiddaman 	increment(seek);
418b30d1939SAndy Fiddaman 	if(stkleft(stream) <= n && !stkgrow(stream,n))
419b30d1939SAndy Fiddaman 		return(0);
420b30d1939SAndy Fiddaman 	stream->_next = stream->_data+n;
421b30d1939SAndy Fiddaman 	return((char*)stream->_data);
422b30d1939SAndy Fiddaman }
423b30d1939SAndy Fiddaman 
424b30d1939SAndy Fiddaman /*
425b30d1939SAndy Fiddaman  * advance the stack to the current top
426b30d1939SAndy Fiddaman  * if extra is non-zero, first add a extra bytes and zero the first
427b30d1939SAndy Fiddaman  */
stkfreeze(register Sfio_t * stream,register size_t extra)428b30d1939SAndy Fiddaman char	*stkfreeze(register Sfio_t *stream, register size_t extra)
429b30d1939SAndy Fiddaman {
430b30d1939SAndy Fiddaman 	register unsigned char *old, *top;
431b30d1939SAndy Fiddaman 	if(!init)
432b30d1939SAndy Fiddaman 		stkinit(extra);
433b30d1939SAndy Fiddaman 	old = stream->_data;
434b30d1939SAndy Fiddaman 	top = stream->_next;
435b30d1939SAndy Fiddaman 	if(extra)
436b30d1939SAndy Fiddaman 	{
437b30d1939SAndy Fiddaman 		if(extra > (stream->_endb-stream->_next))
438b30d1939SAndy Fiddaman 		{
439b30d1939SAndy Fiddaman 			if (!(top = (unsigned char*)stkgrow(stream,extra)))
440b30d1939SAndy Fiddaman 				return(0);
441b30d1939SAndy Fiddaman 			old = stream->_data;
442b30d1939SAndy Fiddaman 		}
443b30d1939SAndy Fiddaman 		*top = 0;
444b30d1939SAndy Fiddaman 		top += extra;
445b30d1939SAndy Fiddaman 	}
446b30d1939SAndy Fiddaman 	stream->_next = stream->_data += roundof(top-old,STK_ALIGN);
447b30d1939SAndy Fiddaman 	return((char*)old);
448b30d1939SAndy Fiddaman }
449b30d1939SAndy Fiddaman 
450b30d1939SAndy Fiddaman /*
451b30d1939SAndy Fiddaman  * copy string <str> onto the stack as a new stack word
452b30d1939SAndy Fiddaman  */
stkcopy(Sfio_t * stream,const char * str)453b30d1939SAndy Fiddaman char	*stkcopy(Sfio_t *stream, const char* str)
454b30d1939SAndy Fiddaman {
455b30d1939SAndy Fiddaman 	register unsigned char *cp = (unsigned char*)str;
456b30d1939SAndy Fiddaman 	register size_t n;
457b30d1939SAndy Fiddaman 	register int off=stktell(stream);
458b30d1939SAndy Fiddaman 	char buff[40], *tp=buff;
459b30d1939SAndy Fiddaman 	if(off)
460b30d1939SAndy Fiddaman 	{
461b30d1939SAndy Fiddaman 		if(off > sizeof(buff))
462b30d1939SAndy Fiddaman 		{
463b30d1939SAndy Fiddaman 			if(!(tp = malloc(off)))
464b30d1939SAndy Fiddaman 			{
465b30d1939SAndy Fiddaman 				struct stk *sp = stream2stk(stream);
466b30d1939SAndy Fiddaman 				if(!sp->stkoverflow || !(tp = (*sp->stkoverflow)(off)))
467b30d1939SAndy Fiddaman 					return(0);
468b30d1939SAndy Fiddaman 			}
469b30d1939SAndy Fiddaman 		}
470b30d1939SAndy Fiddaman 		memcpy(tp, stream->_data, off);
471b30d1939SAndy Fiddaman 	}
472b30d1939SAndy Fiddaman 	while(*cp++);
473b30d1939SAndy Fiddaman 	n = roundof(cp-(unsigned char*)str,STK_ALIGN);
474b30d1939SAndy Fiddaman 	if(!init)
475b30d1939SAndy Fiddaman 		stkinit(n);
476b30d1939SAndy Fiddaman 	increment(copy);
477b30d1939SAndy Fiddaman 	if(stkleft(stream) <= n && !stkgrow(stream,n))
478b30d1939SAndy Fiddaman 		cp = 0;
479b30d1939SAndy Fiddaman 	else
480b30d1939SAndy Fiddaman 	{
481b30d1939SAndy Fiddaman 		strcpy((char*)(cp=stream->_data),str);
482b30d1939SAndy Fiddaman 		stream->_data = stream->_next = cp+n;
483b30d1939SAndy Fiddaman 		if(off)
484b30d1939SAndy Fiddaman 		{
485b30d1939SAndy Fiddaman 			_stkseek(stream,off);
486b30d1939SAndy Fiddaman 			memcpy(stream->_data, tp, off);
487b30d1939SAndy Fiddaman 		}
488b30d1939SAndy Fiddaman 	}
489b30d1939SAndy Fiddaman 	if(tp!=buff)
490b30d1939SAndy Fiddaman 		free((void*)tp);
491b30d1939SAndy Fiddaman 	return((char*)cp);
492b30d1939SAndy Fiddaman }
493b30d1939SAndy Fiddaman 
494b30d1939SAndy Fiddaman /*
495b30d1939SAndy Fiddaman  * add a new stack frame of size >= <n> to the current stack.
496b30d1939SAndy Fiddaman  * if <n> > 0, copy the bytes from stkbot to stktop to the new stack
497b30d1939SAndy Fiddaman  * if <n> is zero, then copy the remainder of the stack frame from stkbot
498b30d1939SAndy Fiddaman  * to the end is copied into the new stack frame
499b30d1939SAndy Fiddaman  */
500b30d1939SAndy Fiddaman 
stkgrow(register Sfio_t * stream,size_t size)501b30d1939SAndy Fiddaman static char *stkgrow(register Sfio_t *stream, size_t size)
502b30d1939SAndy Fiddaman {
503b30d1939SAndy Fiddaman 	register size_t n = size;
504b30d1939SAndy Fiddaman 	register struct stk *sp = stream2stk(stream);
505b30d1939SAndy Fiddaman 	register struct frame *fp= (struct frame*)sp->stkbase;
506b30d1939SAndy Fiddaman 	register char *cp, *dp=0;
507b30d1939SAndy Fiddaman 	register size_t m = stktell(stream);
508b30d1939SAndy Fiddaman 	size_t endoff;
509*3636ae54SAndy Fiddaman 	char *end=0, *oldbase=0;
510b30d1939SAndy Fiddaman 	int nn=0,add=1;
511b30d1939SAndy Fiddaman 	n += (m + sizeof(struct frame)+1);
512b30d1939SAndy Fiddaman 	if(sp->stkflags&STK_SMALL)
513b30d1939SAndy Fiddaman #ifndef USE_REALLOC
514b30d1939SAndy Fiddaman 		n = roundof(n,STK_FSIZE/16);
515b30d1939SAndy Fiddaman 	else
516b30d1939SAndy Fiddaman #endif /* !USE_REALLOC */
517b30d1939SAndy Fiddaman 		n = roundof(n,STK_FSIZE);
518b30d1939SAndy Fiddaman 	/* see whether current frame can be extended */
519b30d1939SAndy Fiddaman 	if(stkptr(stream,0)==sp->stkbase+sizeof(struct frame))
520b30d1939SAndy Fiddaman 	{
521b30d1939SAndy Fiddaman 		nn = fp->nalias+1;
522b30d1939SAndy Fiddaman 		dp=sp->stkbase;
523b30d1939SAndy Fiddaman 		sp->stkbase = ((struct frame*)dp)->prev;
524b30d1939SAndy Fiddaman 		end = fp->end;
525*3636ae54SAndy Fiddaman 		oldbase = dp;
526b30d1939SAndy Fiddaman 	}
527b30d1939SAndy Fiddaman 	endoff = end - dp;
528b30d1939SAndy Fiddaman 	cp = newof(dp, char, n, nn*sizeof(char*));
529b30d1939SAndy Fiddaman 	if(!cp && (!sp->stkoverflow || !(cp = (*sp->stkoverflow)(n))))
530b30d1939SAndy Fiddaman 		return(0);
531b30d1939SAndy Fiddaman 	increment(grow);
532b30d1939SAndy Fiddaman 	count(addsize,n - (dp?m:0));
533b30d1939SAndy Fiddaman 	if(dp==cp)
534b30d1939SAndy Fiddaman 	{
535b30d1939SAndy Fiddaman 		nn--;
536b30d1939SAndy Fiddaman 		add = 0;
537b30d1939SAndy Fiddaman 	}
538b30d1939SAndy Fiddaman 	else if(dp)
539b30d1939SAndy Fiddaman 	{
540b30d1939SAndy Fiddaman 		dp = cp;
541b30d1939SAndy Fiddaman 		end = dp + endoff;
542b30d1939SAndy Fiddaman 	}
543b30d1939SAndy Fiddaman 	fp = (struct frame*)cp;
544b30d1939SAndy Fiddaman 	fp->prev = sp->stkbase;
545b30d1939SAndy Fiddaman 	sp->stkbase = cp;
546b30d1939SAndy Fiddaman 	sp->stkend = fp->end = cp+n;
547b30d1939SAndy Fiddaman 	cp = (char*)(fp+1);
548b30d1939SAndy Fiddaman 	cp = sp->stkbase + roundof((cp-sp->stkbase),STK_ALIGN);
549b30d1939SAndy Fiddaman 	if(fp->nalias=nn)
550b30d1939SAndy Fiddaman 	{
551b30d1939SAndy Fiddaman 		fp->aliases = (char**)fp->end;
552*3636ae54SAndy Fiddaman 		if(end && nn>add)
553*3636ae54SAndy Fiddaman 			memmove(fp->aliases,end,(nn-add)*sizeof(char*));
554b30d1939SAndy Fiddaman 		if(add)
555*3636ae54SAndy Fiddaman 			fp->aliases[nn-1] = oldbase + roundof(sizeof(struct frame),STK_ALIGN);
556b30d1939SAndy Fiddaman 	}
557b30d1939SAndy Fiddaman 	if(m && !dp)
558b30d1939SAndy Fiddaman 	{
559b30d1939SAndy Fiddaman 		memcpy(cp,(char*)stream->_data,m);
560b30d1939SAndy Fiddaman 		count(movsize,m);
561b30d1939SAndy Fiddaman 	}
562b30d1939SAndy Fiddaman 	sfsetbuf(stream,cp,sp->stkend-cp);
563b30d1939SAndy Fiddaman 	return((char*)(stream->_next = stream->_data+m));
564b30d1939SAndy Fiddaman }
565