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