1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
24 * Routines to implement a stack-like storage library
26 * A stack consists of a link list of variable size frames
27 * The beginning of each frame is initialized with a frame structure
28 * that contains a pointer to the previous frame and a pointer to the
29 * end of the current frame.
31 * This is a rewrite of the stk library that uses sfio
35 * dgk@research.att.com
45 * A stack is a header and a linked list of frames
46 * The first frame has structure
50 * Frames have structure
55 #define STK_ALIGN ALIGN_BOUND
56 #define STK_FSIZE (1024*sizeof(int))
57 #define STK_HDRSIZE (sizeof(Sfio_t)+sizeof(Sfdisc_t))
59 typedef char* (*_stk_overflow_
)(int);
61 static int stkexcept(Sfio_t
*,int,void*,Sfdisc_t
*);
62 static Sfdisc_t stkdisc
= { 0, 0, 0, stkexcept
};
64 Sfio_t _Stak_data
= SFNEW((char*)0,0,-1,SF_STATIC
|SF_WRITE
|SF_STRING
,&stkdisc
,0);
66 __EXTERN__(Sfio_t
, _Stak_data
);
70 char *prev
; /* address of previous frame */
71 char *end
; /* address of end this frame */
72 char **aliases
; /* address aliases */
73 int nalias
; /* number of aliases */
78 _stk_overflow_ stkoverflow
; /* called when malloc fails */
79 short stkref
; /* reference count; */
80 short stkflags
; /* stack attributes */
81 char *stkbase
; /* beginning of current stack frame */
82 char *stkend
; /* end of current stack frame */
85 static int init
; /* 1 when initialized */
86 static struct stk
*stkcur
; /* pointer to current stk */
87 static char *stkgrow(Sfio_t
*, unsigned);
89 #define stream2stk(stream) ((stream)==stkstd? stkcur:\
90 ((struct stk*)(((char*)(stream))+STK_HDRSIZE)))
91 #define stk2stream(sp) ((Sfio_t*)(((char*)(sp))-STK_HDRSIZE))
92 #define stkleft(stream) ((stream)->_endb-(stream)->_data)
111 # define increment(x) (_stkstats.x++)
112 # define count(x,n) (_stkstats.x += (n))
114 # define increment(x)
116 #endif /* STKSTATS */
118 static const char Omsg
[] = "malloc failed while growing stack\n";
121 * default overflow exception
123 static char *overflow(int n
)
126 write(2,Omsg
, sizeof(Omsg
)-1);
133 * initialize stkstd, sfio operations may have already occcured
135 static void stkinit(int size
)
141 stkinstall(sp
,overflow
);
144 static int stkexcept(register Sfio_t
*stream
, int type
, void* val
, Sfdisc_t
* dp
)
152 register struct stk
*sp
= stream2stk(stream
);
153 register char *cp
= sp
->stkbase
;
154 register struct frame
*fp
;
159 stkset(stream
,(char*)0,0);
164 fp
= (struct frame
*)cp
;
178 stream
->_data
= stream
->_next
= 0;
189 long size
= sfvalue(stream
);
194 old
= stkinstall(stream
,NiL
);
195 if(!stkgrow(stkstd
,size
-(stkstd
->_endb
-stkstd
->_data
)))
213 Sfio_t
*stkopen(int flags
)
216 register Sfio_t
*stream
;
217 register struct stk
*sp
;
218 register struct frame
*fp
;
219 register Sfdisc_t
*dp
;
221 if(!(stream
=newof((char*)0,Sfio_t
, 1, sizeof(*dp
)+sizeof(*sp
))))
224 count(addsize
,sizeof(*stream
)+sizeof(*dp
)+sizeof(*sp
));
225 dp
= (Sfdisc_t
*)(stream
+1);
226 dp
->exceptf
= stkexcept
;
227 sp
= (struct stk
*)(dp
+1);
229 sp
->stkflags
= (flags
&STK_SMALL
);
230 if(flags
&STK_NULL
) sp
->stkoverflow
= 0;
231 else sp
->stkoverflow
= stkcur
?stkcur
->stkoverflow
:overflow
;
232 bsize
= init
+sizeof(struct frame
);
235 bsize
= roundof(bsize
,STK_FSIZE
/16);
237 #endif /* USE_REALLOC */
238 bsize
= roundof(bsize
,STK_FSIZE
);
239 bsize
-= sizeof(struct frame
);
240 if(!(fp
=newof((char*)0,struct frame
, 1,bsize
)))
245 count(addsize
,sizeof(*fp
)+bsize
);
247 sp
->stkbase
= (char*)fp
;
251 fp
->end
= sp
->stkend
= cp
+bsize
;
252 if(!sfnew(stream
,cp
,bsize
,-1,SF_STRING
|SF_WRITE
|SF_STATIC
|SF_EOF
))
259 * return a pointer to the current stack
260 * if <stream> is not null, it becomes the new current stack
261 * <oflow> becomes the new overflow function
263 Sfio_t
*stkinstall(Sfio_t
*stream
, _stk_overflow_ oflow
)
266 register struct stk
*sp
;
271 stkcur
->stkoverflow
= oflow
;
275 old
= stkcur
?stk2stream(stkcur
):0;
278 sp
= stream2stk(stream
);
279 while(sfstack(stkstd
, SF_POPSTACK
));
281 sfstack(stkstd
,stream
);
285 #endif /* USE_REALLOC */
290 sp
->stkoverflow
= oflow
;
295 * increase the reference count on the given <stack>
297 int stklink(register Sfio_t
* stream
)
299 register struct stk
*sp
= stream2stk(stream
);
300 return(sp
->stkref
++);
304 * terminate a stack and free up the space
305 * >0 returned if reference decremented but still > 0
306 * 0 returned on last close
307 * <0 returned on error
309 int stkclose(Sfio_t
* stream
)
311 register struct stk
*sp
= stream2stk(stream
);
317 return(sfclose(stream
));
321 * returns 1 if <loc> is on this stack
323 int stkon(register Sfio_t
* stream
, register char* loc
)
325 register struct stk
*sp
= stream2stk(stream
);
326 register struct frame
*fp
;
327 for(fp
=(struct frame
*)sp
->stkbase
; fp
; fp
=(struct frame
*)fp
->prev
)
328 if(loc
>=((char*)(fp
+1)) && loc
< fp
->end
)
333 * reset the bottom of the current stack back to <loc>
334 * if <loc> is not in this stack, then the stack is reset to the beginning
335 * otherwise, the top of the stack is set to stkbot+<offset>
338 char *stkset(register Sfio_t
* stream
, register char* loc
, unsigned offset
)
340 register struct stk
*sp
= stream2stk(stream
);
342 register struct frame
*fp
;
343 register int frames
= 0;
350 fp
= (struct frame
*)sp
->stkbase
;
351 cp
= sp
->stkbase
+ roundof(sizeof(struct frame
), STK_ALIGN
);
355 if(loc
==fp
->aliases
[n
])
361 /* see whether <loc> is in current stack frame */
362 if(loc
>=cp
&& loc
<=sp
->stkend
)
365 sfsetbuf(stream
,cp
,sp
->stkend
-cp
);
366 stream
->_data
= (unsigned char*)(cp
+ roundof(loc
-cp
,STK_ALIGN
));
367 stream
->_next
= (unsigned char*)loc
+offset
;
372 sp
->stkbase
= fp
->prev
;
373 sp
->stkend
= ((struct frame
*)(fp
->prev
))->end
;
380 /* set stack back to the beginning */
383 sfsetbuf(stream
,cp
,sp
->stkend
-cp
);
385 stream
->_data
= stream
->_next
= (unsigned char*)cp
;
387 return((char*)stream
->_data
);
391 * allocate <n> bytes on the current stack
393 char *stkalloc(register Sfio_t
*stream
, register unsigned int n
)
395 register unsigned char *old
;
399 n
= roundof(n
,STK_ALIGN
);
400 if(stkleft(stream
) <= (int)n
&& !stkgrow(stream
,n
))
403 stream
->_data
= stream
->_next
= old
+n
;
408 * begin a new stack word of at least <n> bytes
410 char *_stkseek(register Sfio_t
*stream
, register unsigned n
)
415 if(stkleft(stream
) <= (int)n
&& !stkgrow(stream
,n
))
417 stream
->_next
= stream
->_data
+n
;
418 return((char*)stream
->_data
);
422 * advance the stack to the current top
423 * if extra is non-zero, first add a extra bytes and zero the first
425 char *stkfreeze(register Sfio_t
*stream
, register unsigned extra
)
427 register unsigned char *old
, *top
;
434 if(extra
> (stream
->_endb
-stream
->_next
))
436 if (!(top
= (unsigned char*)stkgrow(stream
,extra
)))
443 stream
->_next
= stream
->_data
+= roundof(top
-old
,STK_ALIGN
);
448 * copy string <str> onto the stack as a new stack word
450 char *stkcopy(Sfio_t
*stream
, const char* str
)
452 register unsigned char *cp
= (unsigned char*)str
;
454 register int off
=stktell(stream
);
455 char buff
[40], *tp
=buff
;
458 if(off
> sizeof(buff
))
460 if(!(tp
= malloc(off
)))
462 struct stk
*sp
= stream2stk(stream
);
463 if(!sp
->stkoverflow
|| !(tp
= (*sp
->stkoverflow
)(off
)))
467 memcpy(tp
, stream
->_data
, off
);
470 n
= roundof(cp
-(unsigned char*)str
,STK_ALIGN
);
474 if(stkleft(stream
) <= n
&& !stkgrow(stream
,n
))
476 strcpy((char*)(cp
=stream
->_data
),str
);
477 stream
->_data
= stream
->_next
= cp
+n
;
480 _stkseek(stream
,off
);
481 memcpy(stream
->_data
, tp
, off
);
489 * add a new stack frame of size >= <n> to the current stack.
490 * if <n> > 0, copy the bytes from stkbot to stktop to the new stack
491 * if <n> is zero, then copy the remainder of the stack frame from stkbot
492 * to the end is copied into the new stack frame
495 static char *stkgrow(register Sfio_t
*stream
, unsigned size
)
497 register int n
= size
;
498 register struct stk
*sp
= stream2stk(stream
);
499 register struct frame
*fp
= (struct frame
*)sp
->stkbase
;
500 register char *cp
, *dp
=0;
501 register unsigned m
= stktell(stream
);
503 n
+= (m
+ sizeof(struct frame
)+1);
504 if(sp
->stkflags
&STK_SMALL
)
506 n
= roundof(n
,STK_FSIZE
/16);
508 #endif /* !USE_REALLOC */
509 n
= roundof(n
,STK_FSIZE
);
510 /* see whether current frame can be extended */
511 if(stkptr(stream
,0)==sp
->stkbase
+sizeof(struct frame
))
515 sp
->stkbase
= ((struct frame
*)dp
)->prev
;
517 cp
= newof(dp
, char, n
, nn
*sizeof(char*));
518 if(!cp
&& (!sp
->stkoverflow
|| !(cp
= (*sp
->stkoverflow
)(n
))))
521 count(addsize
,n
- (dp
?m
:0));
524 fp
= (struct frame
*)cp
;
525 fp
->prev
= sp
->stkbase
;
527 sp
->stkend
= fp
->end
= cp
+n
;
529 cp
= sp
->stkbase
+ roundof((cp
-sp
->stkbase
),STK_ALIGN
);
532 fp
->aliases
= (char**)fp
->end
;
533 fp
->aliases
[nn
-1] = dp
+ roundof(sizeof(struct frame
),STK_ALIGN
);
537 memcpy(cp
,(char*)stream
->_data
,m
);
540 sfsetbuf(stream
,cp
,sp
->stkend
-cp
);
541 return((char*)(stream
->_next
= stream
->_data
+m
));