summaryrefslogtreecommitdiff
path: root/usr/src/lib/libast/common/misc/stk.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libast/common/misc/stk.c')
-rw-r--r--usr/src/lib/libast/common/misc/stk.c508
1 files changed, 508 insertions, 0 deletions
diff --git a/usr/src/lib/libast/common/misc/stk.c b/usr/src/lib/libast/common/misc/stk.c
new file mode 100644
index 0000000000..9688e4b6cd
--- /dev/null
+++ b/usr/src/lib/libast/common/misc/stk.c
@@ -0,0 +1,508 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2007 AT&T Knowledge Ventures *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Knowledge Ventures *
+* *
+* A copy of the License is available at *
+* http://www.opensource.org/licenses/cpl1.0.txt *
+* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* David Korn <dgk@research.att.com> *
+* Phong Vo <kpv@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * Routines to implement a stack-like storage library
+ *
+ * A stack consists of a link list of variable size frames
+ * The beginning of each frame is initialized with a frame structure
+ * that contains a pointer to the previous frame and a pointer to the
+ * end of the current frame.
+ *
+ * This is a rewrite of the stk library that uses sfio
+ *
+ * David Korn
+ * AT&T Research
+ * dgk@research.att.com
+ *
+ */
+
+#include <sfio_t.h>
+#include <ast.h>
+#include <align.h>
+#include <stk.h>
+
+/*
+ * A stack is a header and a linked list of frames
+ * The first frame has structure
+ * Sfio_t
+ * Sfdisc_t
+ * struct stk
+ * Frames have structure
+ * struct frame
+ * data
+ */
+
+#define STK_ALIGN ALIGN_BOUND
+#define STK_FSIZE (1024*sizeof(int))
+#define STK_HDRSIZE (sizeof(Sfio_t)+sizeof(Sfdisc_t))
+
+typedef char* (*_stk_overflow_)(int);
+
+static int stkexcept(Sfio_t*,int,void*,Sfdisc_t*);
+static Sfdisc_t stkdisc = { 0, 0, 0, stkexcept };
+
+Sfio_t _Stak_data = SFNEW((char*)0,0,-1,SF_STATIC|SF_WRITE|SF_STRING,&stkdisc,0);
+
+__EXTERN__(Sfio_t, _Stak_data);
+
+struct frame
+{
+ char *prev; /* address of previous frame */
+ char *end; /* address of end this frame */
+ char **aliases; /* address aliases */
+ int nalias; /* number of aliases */
+};
+
+struct stk
+{
+ _stk_overflow_ stkoverflow; /* called when malloc fails */
+ short stkref; /* reference count; */
+ short stkflags; /* stack attributes */
+ char *stkbase; /* beginning of current stack frame */
+ char *stkend; /* end of current stack frame */
+};
+
+static int init; /* 1 when initialized */
+static struct stk *stkcur; /* pointer to current stk */
+static char *stkgrow(Sfio_t*, unsigned);
+
+#define stream2stk(stream) ((stream)==stkstd? stkcur:\
+ ((struct stk*)(((char*)(stream))+STK_HDRSIZE)))
+#define stk2stream(sp) ((Sfio_t*)(((char*)(sp))-STK_HDRSIZE))
+#define stkleft(stream) ((stream)->_endb-(stream)->_data)
+
+
+#ifdef STKSTATS
+ static struct
+ {
+ int create;
+ int delete;
+ int install;
+ int alloc;
+ int copy;
+ int puts;
+ int seek;
+ int set;
+ int grow;
+ int addsize;
+ int delsize;
+ int movsize;
+ } _stkstats;
+# define increment(x) (_stkstats.x++)
+# define count(x,n) (_stkstats.x += (n))
+#else
+# define increment(x)
+# define count(x,n)
+#endif /* STKSTATS */
+
+static const char Omsg[] = "malloc failed while growing stack\n";
+
+/*
+ * default overflow exception
+ */
+static char *overflow(int n)
+{
+ NoP(n);
+ write(2,Omsg, sizeof(Omsg)-1);
+ exit(2);
+ /* NOTREACHED */
+ return(0);
+}
+
+/*
+ * initialize stkstd, sfio operations may have already occcured
+ */
+static void stkinit(int size)
+{
+ register Sfio_t *sp;
+ init = size;
+ sp = stkopen(0);
+ init = 1;
+ stkinstall(sp,overflow);
+}
+
+static int stkexcept(register Sfio_t *stream, int type, void* val, Sfdisc_t* dp)
+{
+ NoP(dp);
+ NoP(val);
+ switch(type)
+ {
+ case SF_CLOSING:
+ {
+ register struct stk *sp = stream2stk(stream);
+ register char *cp = sp->stkbase;
+ register struct frame *fp;
+ if(--sp->stkref<=0)
+ {
+ increment(delete);
+ if(stream==stkstd)
+ stkset(stream,(char*)0,0);
+ else
+ {
+ while(1)
+ {
+ fp = (struct frame*)cp;
+ if(fp->prev)
+ {
+ cp = fp->prev;
+ free(fp);
+ }
+ else
+ {
+ free(fp);
+ break;
+ }
+ }
+ }
+ }
+ stream->_data = stream->_next = 0;
+ }
+ return(0);
+ case SF_FINAL:
+ free(stream);
+ return(1);
+ case SF_DPOP:
+ return(-1);
+ case SF_WRITE:
+ case SF_SEEK:
+ {
+ long size = sfvalue(stream);
+ if(init)
+ {
+ Sfio_t *old = 0;
+ if(stream!=stkstd)
+ old = stkinstall(stream,NiL);
+ if(!stkgrow(stkstd,size-(stkstd->_endb-stkstd->_data)))
+ return(-1);
+ if(old)
+ stkinstall(old,NiL);
+ }
+ else
+ stkinit(size);
+ }
+ return(1);
+ case SF_NEW:
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * create a stack
+ */
+Sfio_t *stkopen(int flags)
+{
+ register int bsize;
+ register Sfio_t *stream;
+ register struct stk *sp;
+ register struct frame *fp;
+ register Sfdisc_t *dp;
+ register char *cp;
+ if(!(stream=newof((char*)0,Sfio_t, 1, sizeof(*dp)+sizeof(*sp))))
+ return(0);
+ increment(create);
+ count(addsize,sizeof(*stream)+sizeof(*dp)+sizeof(*sp));
+ dp = (Sfdisc_t*)(stream+1);
+ dp->exceptf = stkexcept;
+ sp = (struct stk*)(dp+1);
+ sp->stkref = 1;
+ sp->stkflags = (flags&STK_SMALL);
+ if(flags&STK_NULL) sp->stkoverflow = 0;
+ else sp->stkoverflow = stkcur?stkcur->stkoverflow:overflow;
+ bsize = init+sizeof(struct frame);
+#ifndef USE_REALLOC
+ if(flags&STK_SMALL)
+ bsize = roundof(bsize,STK_FSIZE/16);
+ else
+#endif /* USE_REALLOC */
+ bsize = roundof(bsize,STK_FSIZE);
+ bsize -= sizeof(struct frame);
+ if(!(fp=newof((char*)0,struct frame, 1,bsize)))
+ {
+ free(stream);
+ return(0);
+ }
+ count(addsize,sizeof(*fp)+bsize);
+ cp = (char*)(fp+1);
+ sp->stkbase = (char*)fp;
+ fp->prev = 0;
+ fp->nalias = 0;
+ fp->aliases = 0;
+ fp->end = sp->stkend = cp+bsize;
+ if(!sfnew(stream,cp,bsize,-1,SF_STRING|SF_WRITE|SF_STATIC|SF_EOF))
+ return((Sfio_t*)0);
+ sfdisc(stream,dp);
+ return(stream);
+}
+
+/*
+ * return a pointer to the current stack
+ * if <stream> is not null, it becomes the new current stack
+ * <oflow> becomes the new overflow function
+ */
+Sfio_t *stkinstall(Sfio_t *stream, _stk_overflow_ oflow)
+{
+ Sfio_t *old;
+ register struct stk *sp;
+ if(!init)
+ {
+ stkinit(1);
+ if(oflow)
+ stkcur->stkoverflow = oflow;
+ return((Sfio_t*)0);
+ }
+ increment(install);
+ old = stkcur?stk2stream(stkcur):0;
+ if(stream)
+ {
+ sp = stream2stk(stream);
+ while(sfstack(stkstd, SF_POPSTACK));
+ if(stream!=stkstd)
+ sfstack(stkstd,stream);
+ stkcur = sp;
+#ifdef USE_REALLOC
+ /*** someday ***/
+#endif /* USE_REALLOC */
+ }
+ else
+ sp = stkcur;
+ if(oflow)
+ sp->stkoverflow = oflow;
+ return(old);
+}
+
+/*
+ * increase the reference count on the given <stack>
+ */
+int stklink(register Sfio_t* stream)
+{
+ register struct stk *sp = stream2stk(stream);
+ return(sp->stkref++);
+}
+
+/*
+ * terminate a stack and free up the space
+ * >0 returned if reference decremented but still > 0
+ * 0 returned on last close
+ * <0 returned on error
+ */
+int stkclose(Sfio_t* stream)
+{
+ register struct stk *sp = stream2stk(stream);
+ if(sp->stkref>1)
+ {
+ sp->stkref--;
+ return(1);
+ }
+ return(sfclose(stream));
+}
+
+/*
+ * reset the bottom of the current stack back to <loc>
+ * if <loc> is not in this stack, then the stack is reset to the beginning
+ * otherwise, the top of the stack is set to stkbot+<offset>
+ *
+ */
+char *stkset(register Sfio_t * stream, register char* loc, unsigned offset)
+{
+ register struct stk *sp = stream2stk(stream);
+ register char *cp;
+ register struct frame *fp;
+ register int frames = 0;
+ int n;
+ if(!init)
+ stkinit(offset+1);
+ increment(set);
+ while(1)
+ {
+ fp = (struct frame*)sp->stkbase;
+ cp = sp->stkbase + roundof(sizeof(struct frame), STK_ALIGN);
+ n = fp->nalias;
+ while(n-->0)
+ {
+ if(loc==fp->aliases[n])
+ {
+ loc = cp;
+ break;
+ }
+ }
+ /* see whether <loc> is in current stack frame */
+ if(loc>=cp && loc<=sp->stkend)
+ {
+ if(frames)
+ sfsetbuf(stream,cp,sp->stkend-cp);
+ stream->_data = (unsigned char*)(cp + roundof(loc-cp,STK_ALIGN));
+ stream->_next = (unsigned char*)loc+offset;
+ goto found;
+ }
+ if(fp->prev)
+ {
+ sp->stkbase = fp->prev;
+ sp->stkend = ((struct frame*)(fp->prev))->end;
+ free((void*)fp);
+ }
+ else
+ break;
+ frames++;
+ }
+ /* set stack back to the beginning */
+ cp = (char*)(fp+1);
+ if(frames)
+ sfsetbuf(stream,cp,sp->stkend-cp);
+ else
+ stream->_data = stream->_next = (unsigned char*)cp;
+found:
+ return((char*)stream->_data);
+}
+
+/*
+ * allocate <n> bytes on the current stack
+ */
+char *stkalloc(register Sfio_t *stream, register unsigned int n)
+{
+ register unsigned char *old;
+ if(!init)
+ stkinit(n);
+ increment(alloc);
+ n = roundof(n,STK_ALIGN);
+ if(stkleft(stream) <= (int)n && !stkgrow(stream,n))
+ return(0);
+ old = stream->_data;
+ stream->_data = stream->_next = old+n;
+ return((char*)old);
+}
+
+/*
+ * begin a new stack word of at least <n> bytes
+ */
+char *_stkseek(register Sfio_t *stream, register unsigned n)
+{
+ if(!init)
+ stkinit(n);
+ increment(seek);
+ if(stkleft(stream) <= (int)n && !stkgrow(stream,n))
+ return(0);
+ stream->_next = stream->_data+n;
+ return((char*)stream->_data);
+}
+
+/*
+ * advance the stack to the current top
+ * if extra is non-zero, first add a extra bytes and zero the first
+ */
+char *stkfreeze(register Sfio_t *stream, register unsigned extra)
+{
+ register unsigned char *old, *top;
+ if(!init)
+ stkinit(extra);
+ old = stream->_data;
+ top = stream->_next;
+ if(extra)
+ {
+ if(extra > (stream->_endb-stream->_next))
+ {
+ if (!(top = (unsigned char*)stkgrow(stream,extra)))
+ return(0);
+ old = stream->_data;
+ }
+ *top = 0;
+ top += extra;
+ }
+ stream->_next = stream->_data += roundof(top-old,STK_ALIGN);
+ return((char*)old);
+}
+
+/*
+ * copy string <str> onto the stack as a new stack word
+ */
+char *stkcopy(Sfio_t *stream, const char* str)
+{
+ register unsigned char *cp = (unsigned char*)str;
+ register int n;
+ while(*cp++);
+ n = roundof(cp-(unsigned char*)str,STK_ALIGN);
+ if(!init)
+ stkinit(n);
+ increment(copy);
+ if(stkleft(stream) <= n && !stkgrow(stream,n))
+ return(0);
+ strcpy((char*)(cp=stream->_data),str);
+ stream->_data = stream->_next = cp+n;
+ return((char*)cp);
+}
+
+/*
+ * add a new stack frame of size >= <n> to the current stack.
+ * if <n> > 0, copy the bytes from stkbot to stktop to the new stack
+ * if <n> is zero, then copy the remainder of the stack frame from stkbot
+ * to the end is copied into the new stack frame
+ */
+
+static char *stkgrow(register Sfio_t *stream, unsigned size)
+{
+ register int n = size;
+ register struct stk *sp = stream2stk(stream);
+ register struct frame *fp= (struct frame*)sp->stkbase;
+ register char *cp, *dp=0;
+ register unsigned m = stktell(stream);
+ int nn=0;
+ n += (m + sizeof(struct frame)+1);
+ if(sp->stkflags&STK_SMALL)
+#ifndef USE_REALLOC
+ n = roundof(n,STK_FSIZE/16);
+ else
+#endif /* !USE_REALLOC */
+ n = roundof(n,STK_FSIZE);
+ /* see whether current frame can be extended */
+ if(stkptr(stream,0)==sp->stkbase+sizeof(struct frame))
+ {
+ nn = fp->nalias+1;
+ dp=sp->stkbase;
+ sp->stkbase = ((struct frame*)dp)->prev;
+ }
+ cp = newof(dp, char, n, nn*sizeof(char*));
+ if(!cp && (!sp->stkoverflow || !(cp = (*sp->stkoverflow)(n))))
+ return(0);
+ increment(grow);
+ count(addsize,n - (dp?m:0));
+ if(dp && cp==dp)
+ nn--;
+ fp = (struct frame*)cp;
+ fp->prev = sp->stkbase;
+ sp->stkbase = cp;
+ sp->stkend = fp->end = cp+n;
+ cp = (char*)(fp+1);
+ cp = sp->stkbase + roundof((cp-sp->stkbase),STK_ALIGN);
+ if(fp->nalias=nn)
+ {
+ fp->aliases = (char**)fp->end;
+ fp->aliases[nn-1] = dp + roundof(sizeof(struct frame),STK_ALIGN);
+ }
+ if(m && !dp)
+ {
+ memcpy(cp,(char*)stream->_data,m);
+ count(movsize,m);
+ }
+ sfsetbuf(stream,cp,sp->stkend-cp);
+ return((char*)(stream->_next = stream->_data+m));
+}