summaryrefslogtreecommitdiff
path: root/src/lib/libast/disc
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libast/disc
downloadksh-upstream.tar.gz
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libast/disc')
-rw-r--r--src/lib/libast/disc/memfatal.c82
-rw-r--r--src/lib/libast/disc/sfdcdio.c229
-rw-r--r--src/lib/libast/disc/sfdcdos.c416
-rw-r--r--src/lib/libast/disc/sfdcfilter.c186
-rw-r--r--src/lib/libast/disc/sfdchdr.h28
-rw-r--r--src/lib/libast/disc/sfdcmore.c369
-rw-r--r--src/lib/libast/disc/sfdcprefix.c153
-rw-r--r--src/lib/libast/disc/sfdcseekable.c227
-rw-r--r--src/lib/libast/disc/sfdcslow.c84
-rw-r--r--src/lib/libast/disc/sfdcsubstr.c217
-rw-r--r--src/lib/libast/disc/sfdctee.c102
-rw-r--r--src/lib/libast/disc/sfdcunion.c203
-rw-r--r--src/lib/libast/disc/sfkeyprintf.c392
-rw-r--r--src/lib/libast/disc/sfstrtmp.c62
14 files changed, 2750 insertions, 0 deletions
diff --git a/src/lib/libast/disc/memfatal.c b/src/lib/libast/disc/memfatal.c
new file mode 100644
index 0000000..9016d36
--- /dev/null
+++ b/src/lib/libast/disc/memfatal.c
@@ -0,0 +1,82 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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
+
+/*
+ * install error message handler for fatal malloc exceptions
+ */
+
+#include <ast.h>
+#include <error.h>
+#include <vmalloc.h>
+
+#include "FEATURE/vmalloc"
+
+#if _std_malloc
+
+void
+memfatal(void)
+{
+}
+
+#else
+
+/*
+ * print message and fail on VM_BADADDR,VM_NOMEM
+ */
+
+static int
+nomalloc(Vmalloc_t* region, int type, void* obj, Vmdisc_t* disc)
+{
+ Vmstat_t st;
+
+ NoP(disc);
+ switch (type)
+ {
+#ifdef VM_BADADDR
+ case VM_BADADDR:
+ error(ERROR_SYSTEM|3, "invalid pointer %p passed to free or realloc", obj);
+ return(-1);
+#endif
+ case VM_NOMEM:
+ vmstat(region, &st);
+ error(ERROR_SYSTEM|3, "storage allocator out of space on %lu byte request ( region %lu segments %lu busy %lu:%lu:%lu free %lu:%lu:%lu )", (size_t)obj, st.extent, st.n_seg, st.n_busy, st.s_busy, st.m_busy, st.n_free, st.s_free, st.m_free);
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * initialize the malloc exception handler
+ */
+
+void
+memfatal(void)
+{
+ Vmdisc_t* disc;
+
+ malloc(0);
+ if (disc = vmdisc(Vmregion, NiL))
+ disc->exceptf = nomalloc;
+}
+
+#endif
diff --git a/src/lib/libast/disc/sfdcdio.c b/src/lib/libast/disc/sfdcdio.c
new file mode 100644
index 0000000..e8277f1
--- /dev/null
+++ b/src/lib/libast/disc/sfdcdio.c
@@ -0,0 +1,229 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+/* Discipline to turn on direct IO capability.
+** This currently only works for XFS on SGI's.
+**
+** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
+*/
+
+#ifndef FDIRECT
+#undef F_FIOINFO
+#endif
+
+typedef struct _direct_s
+{ Sfdisc_t disc; /* Sfio discipline */
+ int cntl; /* file control flags */
+#ifdef F_DIOINFO
+ struct dioattr dio; /* direct IO params */
+#endif
+} Direct_t;
+
+/* convert a pointer to an int */
+#define P2I(p) (Sfulong_t)((char*)(p) - (char*)0)
+
+#if __STD_C
+static ssize_t diordwr(Sfio_t* f, Void_t* buf, size_t n, Direct_t* di, int type)
+#else
+static ssize_t diordwr(f, buf, n, di, type)
+Sfio_t* f;
+Void_t* buf;
+size_t n;
+Direct_t* di;
+int type;
+#endif
+{
+ size_t rw, done;
+ ssize_t rv;
+
+ done = 0; /* amount processed by direct IO */
+ rv = 0;
+
+#ifdef F_DIOINFO
+ if((P2I(buf)%di->dio.d_mem) == 0 &&
+ (f->here%di->dio.d_miniosz) == 0 && n >= di->dio.d_miniosz )
+ { /* direct IO ok, make sure we're in the right mode */
+ if(!(di->cntl & FDIRECT) )
+ { di->cntl |= FDIRECT;
+ (void)fcntl(f->file, F_SETFL, di->cntl);
+ }
+
+ for(rw = (n/di->dio.d_miniosz)*di->dio.d_miniosz;; )
+ { size_t io;
+
+ if((io = rw) > di->dio.d_maxiosz )
+ io = di->dio.d_maxiosz;
+ if(type == SF_READ)
+ rv = read(f->file,buf,io);
+ else rv = write(f->file,buf,io);
+
+ if(rv > 0)
+ { rw -= rv; done += rv;
+ buf = (Void_t*)((char*)buf + rv);
+ }
+
+ if(rv < io || rw < di->dio.d_miniosz)
+ break;
+ }
+ }
+
+ if(done < n && (di->cntl & FDIRECT) )
+ { /* turn off directIO for remaining IO operation */
+ di->cntl &= ~FDIRECT;
+ (void)fcntl(f->file, F_SETFL, di->cntl);
+ }
+#endif /*F_DIOINFO*/
+
+ if((rw = n-done) > 0 &&
+ (rv = type == SF_READ ? read(f->file,buf,rw) : write(f->file,buf,rw)) > 0 )
+ done += rv;
+
+ return done ? done : rv;
+}
+
+#if __STD_C
+static ssize_t dioread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t dioread(f, buf, n, disc)
+Sfio_t* f;
+Void_t* buf;
+size_t n;
+Sfdisc_t* disc;
+#endif
+{
+ return diordwr(f, buf, n, (Direct_t*)disc, SF_READ);
+}
+
+#if __STD_C
+static ssize_t diowrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t diowrite(f, buf, n, disc)
+Sfio_t* f;
+Void_t* buf;
+size_t n;
+Sfdisc_t* disc;
+#endif
+{
+ return diordwr(f, (Void_t*)buf, n, (Direct_t*)disc, SF_WRITE);
+}
+
+#if __STD_C
+static int dioexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
+#else
+static int dioexcept(f,type,data,disc)
+Sfio_t* f;
+int type;
+Void_t* data;
+Sfdisc_t* disc;
+#endif
+{
+ Direct_t* di = (Direct_t*)disc;
+
+ if(type == SF_FINAL || type == SF_DPOP)
+ {
+#ifdef F_DIOINFO
+ if(di->cntl&FDIRECT)
+ { di->cntl &= ~FDIRECT;
+ (void)fcntl(f->file,F_SETFL,di->cntl);
+ }
+#endif
+ free(disc);
+ }
+
+ return 0;
+}
+
+#if __STD_C
+int sfdcdio(Sfio_t* f, size_t bufsize)
+#else
+int sfdcdio(f, bufsize)
+Sfio_t* f;
+size_t bufsize;
+#endif
+{
+#ifndef F_DIOINFO
+ return -1;
+#else
+ int cntl;
+ struct dioattr dio;
+ Void_t* buf;
+ Direct_t* di;
+
+ if(f->extent < 0 || (f->flags&SF_STRING))
+ return -1;
+
+ if((cntl = fcntl(f->file,F_GETFL,0)) < 0)
+ return -1;
+
+ if(!(cntl&FDIRECT) )
+ { cntl |= FDIRECT;
+ if(fcntl(f->file,F_SETFL,cntl) < 0)
+ return -1;
+ }
+
+ if(fcntl(f->file,F_DIOINFO,&dio) < 0)
+ goto no_direct;
+
+ if(bufsize > 0)
+ bufsize = (bufsize/dio.d_miniosz)*dio.d_miniosz;
+ if(bufsize <= 0)
+ bufsize = dio.d_miniosz*64;
+ if(bufsize > dio.d_maxiosz)
+ bufsize = dio.d_maxiosz;
+
+ if(!(di = (Direct_t*)malloc(sizeof(Direct_t))) )
+ goto no_direct;
+
+ if(!(buf = (Void_t*)memalign(dio.d_mem,bufsize)) )
+ { free(di);
+ goto no_direct;
+ }
+
+ sfsetbuf(f,buf,bufsize);
+ if(sfsetbuf(f,buf,0) == buf)
+ sfset(f,SF_MALLOC,1);
+ else
+ { free(buf);
+ free(di);
+ goto no_direct;
+ }
+
+ di->disc.readf = dioread;
+ di->disc.writef = diowrite;
+ di->disc.seekf = NIL(Sfseek_f);
+ di->disc.exceptf = dioexcept;
+ di->cntl = cntl;
+ di->dio = dio;
+
+ if(sfdisc(f,(Sfdisc_t*)di) != (Sfdisc_t*)di)
+ { free(di);
+ no_direct:
+ cntl &= ~FDIRECT;
+ (void)fcntl(f->file,F_SETFL,cntl);
+ return -1;
+ }
+
+ return 0;
+
+#endif /*F_DIOINFO*/
+}
diff --git a/src/lib/libast/disc/sfdcdos.c b/src/lib/libast/disc/sfdcdos.c
new file mode 100644
index 0000000..15b7865
--- /dev/null
+++ b/src/lib/libast/disc/sfdcdos.c
@@ -0,0 +1,416 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+/* Discipline to turn \r\n into \n.
+** This is useful to deal with DOS text files.
+**
+** Written by David Korn (03/18/1998).
+*/
+
+#define MINMAP 8
+#define CHUNK 1024
+
+struct map
+{
+ Sfoff_t logical;
+ Sfoff_t physical;
+};
+
+typedef struct _dosdisc
+{
+ Sfdisc_t disc;
+ struct map *maptable;
+ int mapsize;
+ int maptop;
+ Sfoff_t lhere;
+ Sfoff_t llast;
+ Sfoff_t lmax;
+ Sfoff_t pmax;
+ Sfoff_t phere;
+ Sfoff_t plast;
+ Sfoff_t begin;
+ int skip;
+ void *buff;
+ char last;
+ char extra;
+ int bsize;
+} Dosdisc_t;
+
+#if __STD_C
+static void addmapping(register Dosdisc_t *dp)
+#else
+static void addmapping(dp)
+register Dosdisc_t *dp;
+#endif
+{
+ register int n;
+ if((n=dp->maptop++)>=dp->mapsize)
+ {
+ dp->mapsize *= 2;
+ if(!(dp->maptable=(struct map*)realloc((void*)dp->maptable,(dp->mapsize+1)*sizeof(struct map))))
+ {
+ dp->maptop--;
+ dp->mapsize *= 2;
+ return;
+ }
+ }
+ dp->maptable[n].physical = dp->phere;
+ dp->maptable[n].logical = dp->lhere;
+ dp->maptable[dp->maptop].logical=0;
+}
+
+#if __STD_C
+static struct map *getmapping(Dosdisc_t *dp, Sfoff_t offset, register int whence)
+#else
+static struct map *getmapping(dp, offset, whence)
+Dosdisc_t *dp;
+Sfoff_t offset;
+register int whence;
+#endif
+{
+ register struct map *mp;
+ static struct map dummy;
+ if(offset <= dp->begin)
+ {
+ dummy.logical = dummy.physical = offset;
+ return(&dummy);
+ }
+ if(!(mp=dp->maptable))
+ {
+ dummy.logical = dp->begin;
+ dummy.physical = dummy.logical+1;
+ return(&dummy);
+ }
+ while((++mp)->logical && (whence==SEEK_CUR?mp->physical:mp->logical) <= offset);
+ return(mp-1);
+}
+
+#if __STD_C
+static ssize_t dos_read(Sfio_t *iop, void *buff, size_t size, Sfdisc_t* disc)
+#else
+static ssize_t dos_read(iop, buff, size, disc)
+Sfio_t *iop;
+void *buff;
+size_t size;
+Sfdisc_t* disc;
+#endif
+{
+ register Dosdisc_t *dp = (Dosdisc_t*)disc;
+ register char *cp = (char*)buff, *first, *cpmax;
+ register int n, count, m;
+ if(dp->extra)
+ {
+ dp->extra=0;
+ *cp = dp->last;
+ return(1);
+ }
+ while(1)
+ {
+ if((n = sfrd(iop,buff,size,disc)) <= 0)
+ return(n);
+ dp->plast=dp->phere;
+ dp->phere +=n;
+ dp->llast = dp->lhere;
+ cpmax = cp+n-1;
+ if(dp->last=='\r' && *cp!='\n')
+ {
+ /* should insert a '\r' */ ;
+ }
+ dp->last = *cpmax;
+ if(n>1)
+ break;
+ if(dp->last!='\r')
+ {
+ dp->lhere++;
+ return(1);
+ }
+ }
+ if(dp->last=='\r')
+ n--;
+ else if(dp->last!='\n' || cpmax[-1]!='\r')
+ *cpmax = '\r';
+ dp->lhere += n;
+ while(1)
+ {
+ while(*cp++ != '\r');
+ if(cp > cpmax || *cp=='\n')
+ break;
+ }
+ dp->skip = cp-1 - (char*)buff;
+ /* if not \r\n in buffer, just return */
+ if((count = cpmax+1-cp) <=0)
+ {
+ *cpmax = dp->last;
+ if(!dp->maptable)
+ dp->begin +=n;
+ dp->skip++;
+ count=0;
+ goto done;
+ }
+ if(!dp->maptable)
+ {
+ dp->begin += cp - (char*)buff-1;
+ if(dp->maptable=(struct map*)malloc((MINMAP+1)*sizeof(struct map)))
+ {
+ dp->mapsize = MINMAP;
+ dp->maptable[0].logical= dp->begin;
+ dp->maptable[0].physical = dp->maptable[0].logical+1;
+ dp->maptable[1].logical=0;
+ dp->maptop = 1;
+ }
+ }
+ /* save original discipline inside buffer */
+ if(count>dp->bsize)
+ {
+ if(dp->bsize==0)
+ dp->buff = malloc(count);
+ else
+ dp->buff = realloc(dp->buff,count);
+ dp->bsize = count;
+ if(!dp->buff)
+ return(-1);
+ }
+ memcpy(dp->buff, cp, count);
+ count=1;
+ while(1)
+ {
+ first=cp;
+ if(cp==cpmax)
+ cp++;
+ else
+ while(*cp++ != '\r');
+ if(cp<=cpmax && *cp!='\n')
+ continue;
+ if((m=(cp-first)-1) >0)
+ memcpy(first-count, first, m);
+ if(cp > cpmax)
+ break;
+ count++;
+ }
+ cpmax[-count] = dp->last;
+ dp->lhere -= count;
+done:
+ if(dp->lhere>dp->lmax)
+ {
+ dp->lmax = dp->lhere;
+ dp->pmax = dp->phere;
+ if(dp->maptable && dp->lmax > dp->maptable[dp->maptop-1].logical+CHUNK)
+ addmapping(dp);
+ }
+ return(n-count);
+}
+
+/*
+ * returns the current offset
+ * <offset> must be in the current buffer
+ * if <whence> is SEEK_CUR, physical offset converted to logical offset
+ * otherwise, logical offset is converted to physical offset
+ */
+#if __STD_C
+static Sfoff_t cur_offset(Dosdisc_t *dp, Sfoff_t offset,Sfio_t *iop,register int whence)
+#else
+static Sfoff_t cur_offset(dp, offset, iop, whence)
+Dosdisc_t *dp;
+Sfoff_t offset;
+Sfio_t *iop;
+register int whence;
+#endif
+{
+ register Sfoff_t n,m=0;
+ register char *cp;
+
+ if(whence==SEEK_CUR)
+ {
+ whence= -1;
+ n = offset - dp->plast;
+ iop->next = iop->data + n;
+ offset = dp->llast;
+ }
+ else
+ {
+ whence = 1;
+ n = offset - dp->llast;
+ offset = dp->plast;
+ }
+ offset +=n;
+ if((n -= dp->skip) > 0)
+ {
+ m=whence;
+ cp = (char*)dp->buff;
+ while(n--)
+ {
+ if(*cp++=='\r' && *cp=='\n')
+ {
+ m += whence;
+ if(whence>0)
+ n++;
+ }
+ }
+ }
+ if(whence<0)
+ iop->next += m;
+ return(offset+m);
+}
+
+#if __STD_C
+static Sfoff_t dos_seek(Sfio_t *iop, Sfoff_t offset, register int whence, Sfdisc_t* disc)
+#else
+static Sfoff_t dos_seek(iop, offset, whence, disc)
+Sfio_t *iop;
+Sfoff_t offset;
+register int whence;
+Sfdisc_t* disc;
+#endif
+{
+ register Dosdisc_t *dp = (Dosdisc_t*)disc;
+ struct map dummy, *mp=0;
+ Sfoff_t physical;
+ register int n,size;
+retry:
+ switch(whence)
+ {
+ case SEEK_CUR:
+ offset = sfsk(iop, (Sfoff_t)0,SEEK_CUR,disc);
+ if(offset<=dp->begin)
+ return(offset);
+ /* check for seek outside buffer */
+ if(offset==dp->phere)
+ return(dp->lhere);
+ else if(offset==dp->plast)
+ return(dp->llast);
+ else if(offset<dp->plast || offset>dp->phere)
+ mp = getmapping(dp,offset,whence);
+ break;
+ case SEEK_SET:
+ /* check for seek outside buffer */
+ if(offset<dp->llast || offset > dp->lhere)
+ mp = getmapping(dp,offset,whence);
+ break;
+ case SEEK_END:
+ if(!dp->maptable)
+ return(sfsk(iop,offset,SEEK_END,disc));
+ mp = &dummy;
+ mp->physical = dp->plast;
+ mp->logical = dp->llast;
+ break;
+ }
+ if(sfsetbuf(iop,(char*)iop,0))
+ size = sfvalue(iop);
+ else
+ size = iop->endb-iop->data;
+ if(mp)
+ {
+ sfsk(iop,mp->physical,SEEK_SET,disc);
+ dp->phere = mp->physical;
+ dp->lhere = mp->logical;
+ if((*disc->readf)(iop,iop->data,size,disc)<0)
+ return(-1);
+ }
+ while(1)
+ {
+ if(whence==SEEK_CUR && dp->phere>=offset)
+ break;
+ if(whence==SEEK_SET && dp->lhere>=offset)
+ break;
+ n=(*disc->readf)(iop,iop->data,size,disc);
+ if(n < 0)
+ return(-1);
+ if(n==0)
+ {
+ if(whence==SEEK_END && offset<0)
+ {
+ offset = dp->lhere;
+ whence=SEEK_SET;
+ goto retry;
+ }
+ break;
+ }
+ }
+ if(whence==SEEK_END)
+ offset += dp->lhere;
+ else
+ {
+ physical = cur_offset(dp,offset,iop,whence);
+ if(whence==SEEK_SET)
+ {
+ sfsk(iop, physical ,SEEK_SET,disc);
+ dp->phere = physical;
+ dp->lhere = offset;
+ }
+ else
+ offset = physical;
+ }
+ return(offset);
+}
+
+#if __STD_C
+static int dos_except(Sfio_t *iop, int type, void *arg, Sfdisc_t *disc)
+#else
+static int dos_except(iop, type, arg, disc)
+Sfio_t *iop;
+int type;
+void *arg;
+Sfdisc_t *disc;
+#endif
+{
+ register Dosdisc_t *dp = (Dosdisc_t*)disc;
+ if(type==SF_DPOP || type==SF_FINAL)
+ {
+ if(dp->bsize>0)
+ free((void*)dp->buff);
+ if(dp->mapsize)
+ free((void*)dp->maptable);
+ free((void*)disc);
+ }
+ return(0);
+}
+
+#if __STD_C
+int sfdcdos(Sfio_t *f)
+#else
+int sfdcdos(f)
+Sfio_t *f;
+#endif
+{
+ Dosdisc_t *dos;
+
+ /* this is a readonly discipline */
+ if(sfset(f,0,0)&SF_WRITE)
+ return(-1);
+
+ if(!(dos = (Dosdisc_t*)malloc(sizeof(Dosdisc_t))) )
+ return -1;
+ memset(dos,'\0',sizeof(Dosdisc_t));
+
+ dos->disc.readf = dos_read;
+ dos->disc.writef = NIL(Sfwrite_f);
+ dos->disc.seekf = dos_seek;
+ dos->disc.exceptf = dos_except;
+
+ if(sfdisc(f,(Sfdisc_t*)dos) != (Sfdisc_t*)dos)
+ { free(dos);
+ return -1;
+ }
+
+ return(0);
+}
diff --git a/src/lib/libast/disc/sfdcfilter.c b/src/lib/libast/disc/sfdcfilter.c
new file mode 100644
index 0000000..16a2219
--- /dev/null
+++ b/src/lib/libast/disc/sfdcfilter.c
@@ -0,0 +1,186 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+/* Discipline to invoke UNIX processes as data filters.
+** These processes must be able to fit in pipelines.
+**
+** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
+*/
+
+typedef struct _filter_s
+{ Sfdisc_t disc; /* discipline structure */
+ Sfio_t* filter; /* the filter stream */
+ char* next; /* data unwritten */
+ char* endb; /* end of data */
+ char raw[4096]; /* raw data buffer */
+} Filter_t;
+
+/* read data from the filter */
+#if __STD_C
+static ssize_t filterread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t filterread(f, buf, n, disc)
+Sfio_t* f; /* stream reading from */
+Void_t* buf; /* buffer to read into */
+size_t n; /* number of bytes requested */
+Sfdisc_t* disc; /* discipline */
+#endif
+{
+ Filter_t* fi;
+ ssize_t r, w;
+
+ fi = (Filter_t*)disc;
+ for(;;)
+ {
+ /* get some raw data to stuff down the pipe */
+ if(fi->next && fi->next >= fi->endb )
+ { if((r = sfrd(f,fi->raw,sizeof(fi->raw),disc)) > 0)
+ { fi->next = fi->raw;
+ fi->endb = fi->raw+r;
+ }
+ else
+ { /* eof, close write end of pipes */
+ sfset(fi->filter,SF_READ,0);
+ close(sffileno(fi->filter));
+ sfset(fi->filter,SF_READ,1);
+ fi->next = fi->endb = NIL(char*);
+ }
+ }
+
+ if(fi->next && (w = fi->endb - fi->next) > 0 )
+ { /* see if pipe is ready for write */
+ sfset(fi->filter, SF_READ, 0);
+ r = sfpoll(&fi->filter, 1, 1);
+ sfset(fi->filter, SF_READ, 1);
+
+ if(r == 1) /* non-blocking write */
+ { errno = 0;
+ if((w = sfwr(fi->filter, fi->next, w, 0)) > 0)
+ fi->next += w;
+ else if(errno != EAGAIN)
+ return 0;
+ }
+ }
+
+ /* see if pipe is ready for read */
+ sfset(fi->filter, SF_WRITE, 0);
+ w = sfpoll(&fi->filter, 1, fi->next ? 1 : -1);
+ sfset(fi->filter, SF_WRITE, 1);
+
+ if(!fi->next || w == 1) /* non-blocking read */
+ { errno = 0;
+ if((r = sfrd(fi->filter, buf, n, 0)) > 0)
+ return r;
+ if(errno != EAGAIN)
+ return 0;
+ }
+ }
+}
+
+#if __STD_C
+static ssize_t filterwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t filterwrite(f, buf, n, disc)
+Sfio_t* f; /* stream writing to */
+Void_t* buf; /* buffer to write into */
+size_t n; /* number of bytes requested */
+Sfdisc_t* disc; /* discipline */
+#endif
+{
+ return -1;
+}
+
+/* for the duration of this discipline, the stream is unseekable */
+#if __STD_C
+static Sfoff_t filterseek(Sfio_t* f, Sfoff_t addr, int offset, Sfdisc_t* disc)
+#else
+static Sfoff_t filterseek(f, addr, offset, disc)
+Sfio_t* f;
+Sfoff_t addr;
+int offset;
+Sfdisc_t* disc;
+#endif
+{ f = NIL(Sfio_t*);
+ addr = 0;
+ offset = 0;
+ disc = NIL(Sfdisc_t*);
+ return (Sfoff_t)(-1);
+}
+
+/* on close, remove the discipline */
+#if __STD_C
+static int filterexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
+#else
+static int filterexcept(f,type,data,disc)
+Sfio_t* f;
+int type;
+Void_t* data;
+Sfdisc_t* disc;
+#endif
+{
+ if(type == SF_FINAL || type == SF_DPOP)
+ { sfclose(((Filter_t*)disc)->filter);
+ free(disc);
+ }
+
+ return 0;
+}
+
+#if __STD_C
+int sfdcfilter(Sfio_t* f, const char* cmd)
+#else
+int sfdcfilter(f, cmd)
+Sfio_t* f; /* stream to filter data */
+char* cmd; /* program to run as a filter */
+#endif
+{
+ reg Filter_t* fi;
+ reg Sfio_t* filter;
+
+ /* open filter for read&write */
+ if(!(filter = sfpopen(NIL(Sfio_t*),cmd,"r+")) )
+ return -1;
+
+ /* unbuffered stream */
+ sfsetbuf(filter,NIL(Void_t*),0);
+
+ if(!(fi = (Filter_t*)malloc(sizeof(Filter_t))) )
+ { sfclose(filter);
+ return -1;
+ }
+
+ fi->disc.readf = filterread;
+ fi->disc.writef = filterwrite;
+ fi->disc.seekf = filterseek;
+ fi->disc.exceptf = filterexcept;
+ fi->filter = filter;
+ fi->next = fi->endb = fi->raw;
+
+ if(sfdisc(f,(Sfdisc_t*)fi) != (Sfdisc_t*)fi)
+ { sfclose(filter);
+ free(fi);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/lib/libast/disc/sfdchdr.h b/src/lib/libast/disc/sfdchdr.h
new file mode 100644
index 0000000..7e5bbca
--- /dev/null
+++ b/src/lib/libast/disc/sfdchdr.h
@@ -0,0 +1,28 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+/*
+ * common header for discipline functions
+ */
+
+#include "sfhdr.h"
+
+#include <sfdisc.h>
diff --git a/src/lib/libast/disc/sfdcmore.c b/src/lib/libast/disc/sfdcmore.c
new file mode 100644
index 0000000..900b55d
--- /dev/null
+++ b/src/lib/libast/disc/sfdcmore.c
@@ -0,0 +1,369 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+#if _PACKAGE_ast
+#include <ast_tty.h>
+#include <signal.h>
+#endif
+
+/*
+ * a simple but fast more style pager discipline
+ * if on sfstdout then sfstdin ops reset the page state
+ *
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * @(#)$Id: sfdcmore (AT&T Research) 1998-06-25 $
+ */
+
+typedef struct
+{
+ Sfdisc_t disc; /* sfio discipline */
+ Sfio_t* input; /* tied with this input stream */
+ Sfio_t* error; /* tied with this error stream */
+ int rows; /* max rows */
+ int cols; /* max cols */
+ int row; /* current row */
+ int col; /* current col */
+ int match; /* match length, 0 if none */
+ char pattern[128]; /* match pattern */
+ char prompt[1]; /* prompt string */
+} More_t;
+
+/*
+ * more read
+ * we assume line-at-a-time input
+ */
+
+#if __STD_C
+static ssize_t moreread(Sfio_t* f, void* buf, size_t n, Sfdisc_t* dp)
+#else
+static ssize_t moreread(f, buf, n, dp)
+Sfio_t* f;
+void* buf;
+size_t n;
+Sfdisc_t* dp;
+#endif
+{
+ register More_t* more = (More_t*)dp;
+
+ more->match = 0;
+ more->row = 2;
+ more->col = 1;
+ return sfrd(f, buf, n, dp);
+}
+
+/*
+ * output label on wfd and return next char on rfd with no echo
+ * return < -1 is -(signal + 1)
+ */
+
+#if __STD_C
+static int ttyquery(Sfio_t* rp, Sfio_t* wp, const char* label, Sfdisc_t* dp)
+#else
+static int ttyquery(rp, wp, label, dp)
+Sfio_t* rp;
+Sfio_t* wp;
+char* label;
+Sfdisc_t* dp;
+#endif
+{
+ register int r;
+ int n;
+
+#ifdef TCSADRAIN
+ unsigned char c;
+ struct termios old;
+ struct termios tty;
+ int rfd = sffileno(rp);
+ int wfd = sffileno(rp);
+
+ if (!label)
+ n = 0;
+ else if (n = strlen(label))
+ write(wfd, label, n);
+ tcgetattr(rfd, &old);
+ tty = old;
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ tty.c_lflag &= ~(ICANON|ECHO|ECHOK|ISIG);
+ tcsetattr(rfd, TCSADRAIN, &tty);
+ if ((r = read(rfd, &c, 1)) == 1)
+ {
+ if (c == old.c_cc[VEOF])
+ r = -1;
+ else if (c == old.c_cc[VINTR])
+ r = -(SIGINT + 1);
+ else if (c == old.c_cc[VQUIT])
+ r = -(SIGQUIT + 1);
+ else if (c == '\r')
+ r = '\n';
+ else
+ r = c;
+ }
+ tcsetattr(rfd, TCSADRAIN, &old);
+ if (n)
+ {
+ write(wfd, "\r", 1);
+ while (n-- > 0)
+ write(wfd, " ", 1);
+ write(wfd, "\r", 1);
+ }
+#else
+ register char* s;
+
+ if (label && (n = strlen(label)))
+ sfwr(wp, label, n, dp);
+ r = (s = sfgetr(rp, '\n', 0)) ? *s : -1;
+#endif
+ return r;
+}
+
+/*
+ * more write
+ */
+
+#if __STD_C
+static ssize_t morewrite(Sfio_t* f, const Void_t* buf, register size_t n, Sfdisc_t* dp)
+#else
+static ssize_t morewrite(f, buf, n, dp)
+Sfio_t* f;
+Void_t* buf;
+register size_t n;
+Sfdisc_t* dp;
+#endif
+{
+ register More_t* more = (More_t*)dp;
+ register char* b;
+ register char* s;
+ register char* e;
+ register ssize_t w;
+ register int r;
+
+ if (!more->row)
+ return n;
+ if (!more->col)
+ return sfwr(f, buf, n, dp);
+ w = 0;
+ b = (char*)buf;
+ s = b;
+ e = s + n;
+ if (more->match)
+ {
+ match:
+ for (r = more->pattern[0];; s++)
+ {
+ if (s >= e)
+ return n;
+ if (*s == '\n')
+ b = s + 1;
+ else if (*s == r && (e - s) >= more->match && !strncmp(s, more->pattern, more->match))
+ break;
+ }
+ s = b;
+ w += b - (char*)buf;
+ more->match = 0;
+ }
+ while (s < e)
+ {
+ switch (*s++)
+ {
+ case '\t':
+ more->col = ((more->col + 8) & ~7) - 1;
+ /*FALLTHROUGH*/
+ default:
+ if (++more->col <= more->cols || s < e && *s == '\n')
+ continue;
+ /*FALLTHROUGH*/
+ case '\n':
+ more->col = 1;
+ if (++more->row < more->rows)
+ continue;
+ break;
+ case '\b':
+ if (more->col > 1)
+ more->col--;
+ continue;
+ case '\r':
+ more->col = 1;
+ continue;
+ }
+ w += sfwr(f, b, s - b, dp);
+ b = s;
+ r = ttyquery(sfstdin, f, more->prompt, dp);
+ if (r == '/' || r == 'n')
+ {
+ if (r == '/')
+ {
+ sfwr(f, "/", 1, dp);
+ if ((s = sfgetr(sfstdin, '\n', 1)) && (n = sfvalue(sfstdin) - 1) > 0)
+ {
+ if (n >= sizeof(more->pattern))
+ n = sizeof(more->pattern) - 1;
+ memcpy(more->pattern, s, n);
+ more->pattern[n] = 0;
+ }
+ }
+ if (more->match = strlen(more->pattern))
+ {
+ more->row = 1;
+ more->col = 1;
+ goto match;
+ }
+ }
+ switch (r)
+ {
+ case '\n':
+ case '\r':
+ more->row--;
+ more->col = 1;
+ break;
+ case ' ':
+ more->row = 2;
+ more->col = 1;
+ break;
+ default:
+ more->row = 0;
+ return n;
+ }
+ }
+ if (s > b)
+ w += sfwr(f, b, s - b, dp);
+ return w;
+}
+
+/*
+ * remove the discipline on close
+ */
+
+#if __STD_C
+static int moreexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* dp)
+#else
+static int moreexcept(f, type, data, dp)
+Sfio_t* f;
+int type;
+Void_t* data;
+Sfdisc_t* dp;
+#endif
+{
+ register More_t* more = (More_t*)dp;
+
+ if (type == SF_FINAL || type == SF_DPOP)
+ {
+ if (f = more->input)
+ {
+ more->input = 0;
+ sfdisc(f, SF_POPDISC);
+ }
+ else if (f = more->error)
+ {
+ more->error = 0;
+ sfdisc(f, SF_POPDISC);
+ }
+ else
+ free(dp);
+ }
+ else if (type == SF_SYNC)
+ {
+ more->match = 0;
+ more->row = 1;
+ more->col = 1;
+ }
+ return 0;
+}
+
+/*
+ * push the more discipline on f
+ * if prompt==0 then a default ansi prompt is used
+ * if rows==0 or cols==0 then they are deterimined from the tty
+ * if f==sfstdout then input on sfstdin also resets the state
+ */
+
+#if __STD_C
+int sfdcmore(Sfio_t* f, const char* prompt, int rows, int cols)
+#else
+int sfdcmore(f, prompt, rows, cols)
+Sfio_t* f;
+char* prompt;
+int rows;
+int cols;
+#endif
+{
+ register More_t* more;
+ size_t n;
+
+ /*
+ * this is a writeonly discipline for interactive io
+ */
+
+ if (!(sfset(f, 0, 0) & SF_WRITE) || !isatty(sffileno(sfstdin)) || !isatty(sffileno(sfstdout)))
+ return -1;
+ if (!prompt)
+ prompt = "\033[7m More\033[m";
+ n = strlen(prompt) + 1;
+ if (!(more = (More_t*)malloc(sizeof(More_t) + n)))
+ return -1;
+ memset(more, 0, sizeof(*more));
+
+ more->disc.readf = moreread;
+ more->disc.writef = morewrite;
+ more->disc.exceptf = moreexcept;
+ memcpy(more->prompt, prompt, n);
+ if (!rows || !cols)
+ {
+#if _PACKAGE_ast
+ astwinsize(sffileno(sfstdin), &rows, &cols);
+#endif
+ if (!rows)
+ rows = 24;
+ if (!cols)
+ cols = 80;
+ }
+ more->rows = rows;
+ more->cols = cols;
+ more->row = 1;
+ more->col = 1;
+
+ if (sfdisc(f, &more->disc) != &more->disc)
+ {
+ free(more);
+ return -1;
+ }
+ if (f == sfstdout)
+ {
+ if (sfdisc(sfstdin, &more->disc) != &more->disc)
+ {
+ sfdisc(f, SF_POPDISC);
+ return -1;
+ }
+ more->input = sfstdin;
+ if (sfdisc(sfstderr, &more->disc) != &more->disc)
+ {
+ sfdisc(f, SF_POPDISC);
+ return -1;
+ }
+ more->error = sfstdin;
+ }
+
+ return 0;
+}
diff --git a/src/lib/libast/disc/sfdcprefix.c b/src/lib/libast/disc/sfdcprefix.c
new file mode 100644
index 0000000..29f3fd4
--- /dev/null
+++ b/src/lib/libast/disc/sfdcprefix.c
@@ -0,0 +1,153 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+/*
+ * a discipline that prepends a prefix string to each output line
+ *
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * @(#)$Id: sfdcprefix (AT&T Research) 1998-06-25 $
+ */
+
+typedef struct
+{
+ Sfdisc_t disc; /* sfio discipline */
+ size_t length; /* prefix length */
+ size_t empty; /* empty line prefix length */
+ int skip; /* this line already prefixed */
+ char prefix[1]; /* prefix string */
+} Prefix_t;
+
+/*
+ * prefix write
+ */
+
+#if __STD_C
+static ssize_t pfxwrite(Sfio_t* f, const Void_t* buf, register size_t n, Sfdisc_t* dp)
+#else
+static ssize_t pfxwrite(f, buf, n, dp)
+Sfio_t* f;
+Void_t* buf;
+register size_t n;
+Sfdisc_t* dp;
+#endif
+{
+ register Prefix_t* pfx = (Prefix_t*)dp;
+ register char* b;
+ register char* s;
+ register char* e;
+ register char* t;
+ register ssize_t w;
+ int skip;
+
+ skip = 0;
+ w = 0;
+ b = (char*)buf;
+ s = b;
+ e = s + n;
+ do
+ {
+ if (!(t = memchr(s, '\n', e - s)))
+ {
+ skip = 1;
+ t = e - 1;
+ }
+ n = t - s + 1;
+ if (pfx->skip)
+ pfx->skip = 0;
+ else
+ sfwr(f, pfx->prefix, n > 1 ? pfx->length : pfx->empty, dp);
+ w += sfwr(f, s, n, dp);
+ if ((s = t + 1) >= e)
+ return w;
+ } while ((s = t + 1) < e);
+ pfx->skip = skip;
+ return w;
+
+}
+
+/*
+ * remove the discipline on close
+ */
+
+#if __STD_C
+static int pfxexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* dp)
+#else
+static int pfxexcept(f, type, data, dp)
+Sfio_t* f;
+int type;
+Void_t* data;
+Sfdisc_t* dp;
+#endif
+{
+ if (type == SF_FINAL || type == SF_DPOP)
+ free(dp);
+ return 0;
+}
+
+/*
+ * push the prefix discipline on f
+ */
+
+#if __STD_C
+int sfdcprefix(Sfio_t* f, const char* prefix)
+#else
+int sfdcprefix(f, prefix)
+Sfio_t* f;
+char* prefix;
+#endif
+{
+ register Prefix_t* pfx;
+ register char* s;
+ size_t n;
+
+ /*
+ * this is a writeonly discipline
+ */
+
+ if (!prefix || !(n = strlen(prefix)) || !(sfset(f, 0, 0) & SF_WRITE))
+ return -1;
+ if (!(pfx = (Prefix_t*)malloc(sizeof(Prefix_t) + n)))
+ return -1;
+ memset(pfx, 0, sizeof(*pfx));
+
+ pfx->disc.writef = pfxwrite;
+ pfx->disc.exceptf = pfxexcept;
+ pfx->length = n;
+ memcpy(pfx->prefix, prefix, n);
+ s = (char*)prefix + n;
+ while (--s > (char*)prefix && (*s == ' ' || *s == '\t'));
+ n = s - (char*)prefix;
+ if (*s != ' ' || *s != '\t')
+ n++;
+ pfx->empty = n;
+
+ if (sfdisc(f, &pfx->disc) != &pfx->disc)
+ {
+ free(pfx);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/lib/libast/disc/sfdcseekable.c b/src/lib/libast/disc/sfdcseekable.c
new file mode 100644
index 0000000..23c5b93
--- /dev/null
+++ b/src/lib/libast/disc/sfdcseekable.c
@@ -0,0 +1,227 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+/* Discipline to make an unseekable read stream seekable
+**
+** sfraise(f,SFSK_DISCARD,0) discards previous seek data
+** but seeks from current offset on still allowed
+**
+** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
+*/
+
+typedef struct _skable_s
+{ Sfdisc_t disc; /* sfio discipline */
+ Sfio_t* shadow; /* to shadow data */
+ Sfoff_t discard;/* sfseek(f,-1,SEEK_SET) discarded data */
+ Sfoff_t extent; /* shadow extent */
+ int eof; /* if eof has been reached */
+} Seek_t;
+
+#if __STD_C
+static ssize_t skwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t skwrite(f, buf, n, disc)
+Sfio_t* f; /* stream involved */
+Void_t* buf; /* buffer to read into */
+size_t n; /* number of bytes to read */
+Sfdisc_t* disc; /* discipline */
+#endif
+{
+ return (ssize_t)(-1);
+}
+
+#if __STD_C
+static ssize_t skread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t skread(f, buf, n, disc)
+Sfio_t* f; /* stream involved */
+Void_t* buf; /* buffer to read into */
+size_t n; /* number of bytes to read */
+Sfdisc_t* disc; /* discipline */
+#endif
+{
+ Seek_t* sk;
+ Sfio_t* sf;
+ Sfoff_t addr;
+ ssize_t r, w, p;
+
+ sk = (Seek_t*)disc;
+ sf = sk->shadow;
+ if(sk->eof)
+ return sfread(sf,buf,n);
+
+ addr = sfseek(sf,(Sfoff_t)0,SEEK_CUR);
+
+ if(addr+n <= sk->extent)
+ return sfread(sf,buf,n);
+
+ if((r = (ssize_t)(sk->extent-addr)) > 0)
+ { if((w = sfread(sf,buf,r)) != r)
+ return w;
+ buf = (char*)buf + r;
+ n -= r;
+ }
+
+ /* do a raw read */
+ if((w = sfrd(f,buf,n,disc)) <= 0)
+ { sk->eof = 1;
+ w = 0;
+ }
+ else
+ {
+ if((p = sfwrite(sf,buf,w)) != w)
+ sk->eof = 1;
+ if(p > 0)
+ sk->extent += p;
+ }
+
+ return r+w;
+}
+
+#if __STD_C
+static Sfoff_t skseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
+#else
+static Sfoff_t skseek(f, addr, type, disc)
+Sfio_t* f;
+Sfoff_t addr;
+int type;
+Sfdisc_t* disc;
+#endif
+{
+ Seek_t* sk;
+ Sfio_t* sf;
+ char buf[SF_BUFSIZE];
+ ssize_t r, w;
+
+ sk = (Seek_t*)disc;
+ sf = sk->shadow;
+
+ switch (type)
+ {
+ case SEEK_SET:
+ addr -= sk->discard;
+ break;
+ case SEEK_CUR:
+ addr += sftell(sf);
+ break;
+ case SEEK_END:
+ addr += sk->extent;
+ break;
+ default:
+ return -1;
+ }
+
+ if(addr < 0)
+ return (Sfoff_t)(-1);
+ else if(addr > sk->extent)
+ { if(sk->eof)
+ return (Sfoff_t)(-1);
+
+ /* read enough to reach the seek point */
+ while(addr > sk->extent)
+ { if(addr > sk->extent+sizeof(buf) )
+ w = sizeof(buf);
+ else w = (int)(addr-sk->extent);
+ if((r = sfrd(f,buf,w,disc)) <= 0)
+ w = r-1;
+ else if((w = sfwrite(sf,buf,r)) > 0)
+ sk->extent += w;
+ if(w != r)
+ { sk->eof = 1;
+ break;
+ }
+ }
+
+ if(addr > sk->extent)
+ return (Sfoff_t)(-1);
+ }
+
+ return sfseek(sf,addr,SEEK_SET) + sk->discard;
+}
+
+/* on close, remove the discipline */
+#if __STD_C
+static int skexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
+#else
+static int skexcept(f,type,data,disc)
+Sfio_t* f;
+int type;
+Void_t* data;
+Sfdisc_t* disc;
+#endif
+{
+ Seek_t* sk;
+
+ sk = (Seek_t*)disc;
+
+ switch (type)
+ {
+ case SF_FINAL:
+ case SF_DPOP:
+ sfclose(sk->shadow);
+ free(disc);
+ break;
+ case SFSK_DISCARD:
+ sk->eof = 0;
+ sk->discard += sk->extent;
+ sk->extent = 0;
+ sfseek(sk->shadow,(Sfoff_t)0,SEEK_SET);
+ break;
+ }
+ return 0;
+}
+
+#if __STD_C
+int sfdcseekable(Sfio_t* f)
+#else
+int sfdcseekable(f)
+Sfio_t* f;
+#endif
+{
+ reg Seek_t* sk;
+
+ /* see if already seekable */
+ if(sfseek(f,(Sfoff_t)0,SEEK_CUR) >= 0)
+ return 0;
+
+ if(!(sk = (Seek_t*)malloc(sizeof(Seek_t))) )
+ return -1;
+ memset(sk, 0, sizeof(*sk));
+
+ sk->disc.readf = skread;
+ sk->disc.writef = skwrite;
+ sk->disc.seekf = skseek;
+ sk->disc.exceptf = skexcept;
+ sk->shadow = sftmp(SF_BUFSIZE);
+ sk->discard = 0;
+ sk->extent = 0;
+ sk->eof = 0;
+
+ if(sfdisc(f, (Sfdisc_t*)sk) != (Sfdisc_t*)sk)
+ { sfclose(sk->shadow);
+ free(sk);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/lib/libast/disc/sfdcslow.c b/src/lib/libast/disc/sfdcslow.c
new file mode 100644
index 0000000..e75f438
--- /dev/null
+++ b/src/lib/libast/disc/sfdcslow.c
@@ -0,0 +1,84 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+/* Make a stream op return immediately on interrupts.
+** This is useful on slow streams (hence the name).
+**
+** Written by Glenn Fowler (03/18/1998).
+*/
+
+#if __STD_C
+static int slowexcept(Sfio_t* f, int type, Void_t* v, Sfdisc_t* disc)
+#else
+static int slowexcept(f, type, v, disc)
+Sfio_t* f;
+int type;
+Void_t* v;
+Sfdisc_t* disc;
+#endif
+{
+ NOTUSED(f);
+ NOTUSED(v);
+ NOTUSED(disc);
+
+ switch (type)
+ {
+ case SF_FINAL:
+ case SF_DPOP:
+ free(disc);
+ break;
+ case SF_READ:
+ case SF_WRITE:
+ if (errno == EINTR)
+ return(-1);
+ break;
+ }
+
+ return(0);
+}
+
+#if __STD_C
+int sfdcslow(Sfio_t* f)
+#else
+int sfdcslow(f)
+Sfio_t* f;
+#endif
+{
+ Sfdisc_t* disc;
+
+ if(!(disc = (Sfdisc_t*)malloc(sizeof(Sfdisc_t))) )
+ return(-1);
+
+ disc->readf = NIL(Sfread_f);
+ disc->writef = NIL(Sfwrite_f);
+ disc->seekf = NIL(Sfseek_f);
+ disc->exceptf = slowexcept;
+
+ if(sfdisc(f,disc) != disc)
+ { free(disc);
+ return(-1);
+ }
+ sfset(f,SF_IOINTR,1);
+
+ return(0);
+}
diff --git a/src/lib/libast/disc/sfdcsubstr.c b/src/lib/libast/disc/sfdcsubstr.c
new file mode 100644
index 0000000..c0fae9b
--- /dev/null
+++ b/src/lib/libast/disc/sfdcsubstr.c
@@ -0,0 +1,217 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+
+/* Discipline to treat a contiguous segment of a stream as a stream
+** in its own right. The hard part in all this is to allow multiple
+** segments of the stream to be used as substreams at the same time.
+**
+** Written by David G. Korn and Kiem-Phong Vo (03/18/1998)
+*/
+
+typedef struct _subfile_s
+{
+ Sfdisc_t disc; /* sfio discipline */
+ Sfio_t* parent; /* parent stream */
+ Sfoff_t offset; /* starting offset */
+ Sfoff_t extent; /* size wanted */
+ Sfoff_t here; /* current seek location */
+} Subfile_t;
+
+#if __STD_C
+static ssize_t streamio(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc, int type)
+#else
+static ssize_t streamio(f, buf, n, disc, type)
+Sfio_t* f;
+Void_t* buf;
+size_t n;
+Sfdisc_t* disc;
+int type;
+#endif
+{
+ reg Subfile_t *su;
+ reg Sfoff_t here, parent;
+ reg ssize_t io;
+
+ su = (Subfile_t*)disc;
+
+ /* read just what we need */
+ if(su->extent >= 0 && (ssize_t)n > (io = (ssize_t)(su->extent - su->here)) )
+ n = io;
+ if(n <= 0)
+ return n;
+
+ /* save current location in parent stream */
+ parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc);
+
+ /* read data */
+ here = su->here + su->offset;
+ if(sfsk(f,here,SEEK_SET,disc) != here)
+ io = 0;
+ else
+ { if(type == SF_WRITE)
+ io = sfwr(f,buf,n,disc);
+ else io = sfrd(f,buf,n,disc);
+ if(io > 0)
+ su->here += io;
+ }
+
+ /* restore parent current position */
+ sfsk(f,parent,SEEK_SET,disc);
+
+ return io;
+}
+
+#if __STD_C
+static ssize_t streamwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t streamwrite(f, buf, n, disc)
+Sfio_t* f;
+Void_t* buf;
+size_t n;
+Sfdisc_t* disc;
+#endif
+{
+ return streamio(f,(Void_t*)buf,n,disc,SF_WRITE);
+}
+
+#if __STD_C
+static ssize_t streamread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t streamread(f, buf, n, disc)
+Sfio_t* f;
+Void_t* buf;
+size_t n;
+Sfdisc_t* disc;
+#endif
+{
+ return streamio(f,buf,n,disc,SF_READ);
+}
+
+#if __STD_C
+static Sfoff_t streamseek(Sfio_t* f, Sfoff_t pos, int type, Sfdisc_t* disc)
+#else
+static Sfoff_t streamseek(f, pos, type, disc)
+Sfio_t* f;
+Sfoff_t pos;
+int type;
+Sfdisc_t* disc;
+#endif
+{
+ reg Subfile_t* su;
+ reg Sfoff_t here, parent;
+
+ su = (Subfile_t*)disc;
+
+ switch(type)
+ {
+ case SEEK_SET:
+ here = 0;
+ break;
+ case SEEK_CUR:
+ here = su->here;
+ break;
+ case SEEK_END:
+ if(su->extent >= 0)
+ here = su->extent;
+ else
+ { parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc);
+ if((here = sfsk(f,(Sfoff_t)0,SEEK_END,disc)) < 0)
+ return -1;
+ else here -= su->offset;
+ sfsk(f,parent,SEEK_SET,disc);
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ pos += here;
+ if(pos < 0 || (su->extent >= 0 && pos >= su->extent))
+ return -1;
+
+ return (su->here = pos);
+}
+
+#if __STD_C
+static int streamexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
+#else
+static int streamexcept(f, type, data, disc)
+Sfio_t* f;
+int type;
+Void_t* data;
+Sfdisc_t* disc;
+#endif
+{
+ if(type == SF_FINAL || type == SF_DPOP)
+ free(disc);
+ return 0;
+}
+
+#if __STD_C
+Sfio_t* sfdcsubstream(Sfio_t* f, Sfio_t* parent, Sfoff_t offset, Sfoff_t extent)
+#else
+Sfio_t* sfdcsubstream(f, parent, offset, extent)
+Sfio_t* f; /* stream */
+Sfio_t* parent; /* parent stream */
+Sfoff_t offset; /* offset in f */
+Sfoff_t extent; /* desired size */
+#endif
+{
+ reg Sfio_t* sp;
+ reg Subfile_t* su;
+ reg Sfoff_t here;
+
+ /* establish that we can seek to offset */
+ if((here = sfseek(parent,(Sfoff_t)0,SEEK_CUR)) < 0 || sfseek(parent,offset,SEEK_SET) < 0)
+ return 0;
+ else sfseek(parent,here,SEEK_SET);
+ sfpurge(parent);
+
+ if (!(sp = f) && !(sp = sfnew(NIL(Sfio_t*), NIL(Void_t*), (size_t)SF_UNBOUND, dup(sffileno(parent)), parent->flags)))
+ return 0;
+
+ if(!(su = (Subfile_t*)malloc(sizeof(Subfile_t))))
+ { if(sp != f)
+ sfclose(sp);
+ return 0;
+ }
+ memset(su, 0, sizeof(*su));
+
+ su->disc.readf = streamread;
+ su->disc.writef = streamwrite;
+ su->disc.seekf = streamseek;
+ su->disc.exceptf = streamexcept;
+ su->parent = parent;
+ su->offset = offset;
+ su->extent = extent;
+
+ if(sfdisc(sp, (Sfdisc_t*)su) != (Sfdisc_t*)su)
+ { free(su);
+ if(sp != f)
+ sfclose(sp);
+ return 0;
+ }
+
+ return sp;
+}
diff --git a/src/lib/libast/disc/sfdctee.c b/src/lib/libast/disc/sfdctee.c
new file mode 100644
index 0000000..66bf71e
--- /dev/null
+++ b/src/lib/libast/disc/sfdctee.c
@@ -0,0 +1,102 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+/* A discipline to tee the output to a stream to another stream.
+** This is similar to what the "tee" program does. As implemented
+** this discipline only works with file streams.
+**
+** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
+*/
+
+/* the discipline structure for tee-ing */
+typedef struct _tee_s
+{ Sfdisc_t disc; /* the sfio discipline structure */
+ Sfio_t* tee; /* the stream to tee to */
+ int status; /* if tee stream is still ok */
+} Tee_t;
+
+/* write to the teed stream. */
+#if __STD_C
+static ssize_t teewrite(Sfio_t* f, const Void_t* buf, size_t size, Sfdisc_t* disc)
+#else
+static ssize_t teewrite(f,buf,size,disc)
+Sfio_t* f; /* the stream being written to */
+Void_t* buf; /* the buffer of data being output */
+size_t size; /* the data size */
+Sfdisc_t* disc; /* the tee discipline */
+#endif
+{
+ reg Tee_t* te = (Tee_t*)disc;
+
+ /* tee data if still ok */
+ if(te->status == 0 && sfwrite(te->tee,buf,size) != (ssize_t)size)
+ te->status = -1;
+
+ /* do the actual write */
+ return sfwr(f,buf,size,disc);
+}
+
+/* on close, remove the discipline */
+#if __STD_C
+static int teeexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
+#else
+static int teeexcept(f,type,data,disc)
+Sfio_t* f;
+int type;
+Void_t* data;
+Sfdisc_t* disc;
+#endif
+{
+ if(type == SF_FINAL || type == SF_DPOP)
+ free(disc);
+
+ return 0;
+}
+
+#if __STD_C
+int sfdctee(Sfio_t* f, Sfio_t* tee)
+#else
+int sfdctee(f, tee)
+Sfio_t* f; /* stream to tee from */
+Sfio_t* tee; /* stream to tee to */
+#endif
+{
+ reg Tee_t* te;
+
+ if(!(te = (Tee_t*)malloc(sizeof(Tee_t))) )
+ return -1;
+
+ te->disc.readf = NIL(Sfread_f);
+ te->disc.seekf = NIL(Sfseek_f);
+ te->disc.writef = teewrite;
+ te->disc.exceptf = teeexcept;
+ te->tee = tee;
+ te->status = 0;
+
+ if(sfdisc(f,(Sfdisc_t*)te) != (Sfdisc_t*)te)
+ { free(te);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/lib/libast/disc/sfdcunion.c b/src/lib/libast/disc/sfdcunion.c
new file mode 100644
index 0000000..1f45909
--- /dev/null
+++ b/src/lib/libast/disc/sfdcunion.c
@@ -0,0 +1,203 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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> *
+* *
+***********************************************************************/
+#include "sfdchdr.h"
+
+
+/* Make a sequence of streams act like a single stream.
+** This is for reading only.
+**
+** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
+*/
+
+#define UNSEEKABLE 1
+
+typedef struct _file_s
+{ Sfio_t* f; /* the stream */
+ Sfoff_t lower; /* its lowest end */
+} File_t;
+
+typedef struct _union_s
+{
+ Sfdisc_t disc; /* discipline structure */
+ short type; /* type of streams */
+ short c; /* current stream */
+ short n; /* number of streams */
+ Sfoff_t here; /* current location */
+ File_t f[1]; /* array of streams */
+} Union_t;
+
+#if __STD_C
+static ssize_t unwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t unwrite(f, buf, n, disc)
+Sfio_t* f; /* stream involved */
+Void_t* buf; /* buffer to read into */
+size_t n; /* number of bytes to read */
+Sfdisc_t* disc; /* discipline */
+#endif
+{
+ return -1;
+}
+
+#if __STD_C
+static ssize_t unread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
+#else
+static ssize_t unread(f, buf, n, disc)
+Sfio_t* f; /* stream involved */
+Void_t* buf; /* buffer to read into */
+size_t n; /* number of bytes to read */
+Sfdisc_t* disc; /* discipline */
+#endif
+{
+ reg Union_t* un;
+ reg ssize_t r, m;
+
+ un = (Union_t*)disc;
+ m = n;
+ f = un->f[un->c].f;
+ while(1)
+ { if((r = sfread(f,buf,m)) < 0 || (r == 0 && un->c == un->n-1) )
+ break;
+
+ m -= r;
+ un->here += r;
+
+ if(m == 0)
+ break;
+
+ buf = (char*)buf + r;
+ if(sfeof(f) && un->c < un->n-1)
+ f = un->f[un->c += 1].f;
+ }
+ return n-m;
+}
+
+#if __STD_C
+static Sfoff_t unseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
+#else
+static Sfoff_t unseek(f, addr, type, disc)
+Sfio_t* f;
+Sfoff_t addr;
+int type;
+Sfdisc_t* disc;
+#endif
+{
+ reg Union_t* un;
+ reg int i;
+ reg Sfoff_t extent, s;
+
+ un = (Union_t*)disc;
+ if(un->type&UNSEEKABLE)
+ return -1L;
+
+ if(type == 2)
+ { extent = 0;
+ for(i = 0; i < un->n; ++i)
+ extent += (sfsize(un->f[i].f) - un->f[i].lower);
+ addr += extent;
+ }
+ else if(type == 1)
+ addr += un->here;
+
+ if(addr < 0)
+ return -1;
+
+ /* find the stream where the addr could be in */
+ extent = 0;
+ for(i = 0; i < un->n-1; ++i)
+ { s = sfsize(un->f[i].f) - un->f[i].lower;
+ if(addr < extent + s)
+ break;
+ extent += s;
+ }
+
+ s = (addr-extent) + un->f[i].lower;
+ if(sfseek(un->f[i].f,s,0) != s)
+ return -1;
+
+ un->c = i;
+ un->here = addr;
+
+ for(i += 1; i < un->n; ++i)
+ sfseek(un->f[i].f,un->f[i].lower,0);
+
+ return addr;
+}
+
+/* on close, remove the discipline */
+#if __STD_C
+static int unexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
+#else
+static int unexcept(f,type,data,disc)
+Sfio_t* f;
+int type;
+Void_t* data;
+Sfdisc_t* disc;
+#endif
+{
+ if(type == SF_FINAL || type == SF_DPOP)
+ free(disc);
+
+ return 0;
+}
+
+#if __STD_C
+int sfdcunion(Sfio_t* f, Sfio_t** array, int n)
+#else
+int sfdcunion(f, array, n)
+Sfio_t* f;
+Sfio_t** array;
+int n;
+#endif
+{
+ reg Union_t* un;
+ reg int i;
+
+ if(n <= 0)
+ return -1;
+
+ if(!(un = (Union_t*)malloc(sizeof(Union_t)+(n-1)*sizeof(File_t))) )
+ return -1;
+ memset(un, 0, sizeof(*un));
+
+ un->disc.readf = unread;
+ un->disc.writef = unwrite;
+ un->disc.seekf = unseek;
+ un->disc.exceptf = unexcept;
+ un->n = n;
+
+ for(i = 0; i < n; ++i)
+ { un->f[i].f = array[i];
+ if(!(un->type&UNSEEKABLE))
+ { un->f[i].lower = sfseek(array[i],(Sfoff_t)0,1);
+ if(un->f[i].lower < 0)
+ un->type |= UNSEEKABLE;
+ }
+ }
+
+ if(sfdisc(f,(Sfdisc_t*)un) != (Sfdisc_t*)un)
+ { free(un);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/lib/libast/disc/sfkeyprintf.c b/src/lib/libast/disc/sfkeyprintf.c
new file mode 100644
index 0000000..c63fe37
--- /dev/null
+++ b/src/lib/libast/disc/sfkeyprintf.c
@@ -0,0 +1,392 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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
+
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * keyword printf support
+ */
+
+#define _AST_API_H 1
+
+#include <ast.h>
+#include <ccode.h>
+#include <ctype.h>
+#include <sfdisc.h>
+#include <regex.h>
+
+#define FMT_case 1
+#define FMT_edit 2
+
+typedef struct
+{
+ Sffmt_t fmt;
+ void* handle;
+ Sf_key_lookup_t lookup;
+ Sf_key_convert_t convert;
+ Sfio_t* tmp[2];
+ regex_t red[2];
+ regex_t* re[2];
+ int invisible;
+ int level;
+ int version;
+} Fmt_t;
+
+typedef struct
+{
+ char* next;
+ int delimiter;
+ int first;
+} Field_t;
+
+typedef union
+{
+ char** p;
+ char* s;
+ Sflong_t q;
+ long l;
+ int i;
+ short h;
+ char c;
+} Value_t;
+
+#define initfield(f,s) ((f)->first = (f)->delimiter = *((f)->next = (s)))
+
+static char*
+getfield(register Field_t* f, int restore)
+{
+ register char* s;
+ register int n;
+ register int c;
+ register int lp;
+ register int rp;
+ char* b;
+
+ if (!f->delimiter)
+ return 0;
+ s = f->next;
+ if (f->first)
+ f->first = 0;
+ else if (restore)
+ *s = f->delimiter;
+ b = ++s;
+ lp = rp = n = 0;
+ for (;;)
+ {
+ if (!(c = *s++))
+ {
+ f->delimiter = 0;
+ break;
+ }
+ else if (c == CC_esc || c == '\\')
+ {
+ if (*s)
+ s++;
+ }
+ else if (c == lp)
+ n++;
+ else if (c == rp)
+ n--;
+ else if (n <= 0)
+ {
+ if (c == '(' && restore)
+ {
+ lp = '(';
+ rp = ')';
+ n = 1;
+ }
+ else if (c == '[' && restore)
+ {
+ lp = '[';
+ rp = ']';
+ n = 1;
+ }
+ else if (c == f->delimiter)
+ {
+ *(f->next = --s) = 0;
+ break;
+ }
+ }
+ }
+ return b;
+}
+
+/*
+ * sfio %! extension function
+ */
+
+static int
+getfmt(Sfio_t* sp, void* vp, Sffmt_t* dp)
+{
+ register Fmt_t* fp = (Fmt_t*)dp;
+ Value_t* value = (Value_t*)vp;
+ register char* v;
+ char* t;
+ char* b;
+ char* a = 0;
+ char* s = 0;
+ Sflong_t n = 0;
+ int h = 0;
+ int i = 0;
+ int x = 0;
+ int d;
+ Field_t f;
+ regmatch_t match[10];
+
+ fp->level++;
+ if (fp->fmt.t_str && fp->fmt.n_str > 0 && (v = fmtbuf(fp->fmt.n_str + 1)))
+ {
+ memcpy(v, fp->fmt.t_str, fp->fmt.n_str);
+ v[fp->fmt.n_str] = 0;
+ b = v;
+ for (;;)
+ {
+ switch (*v++)
+ {
+ case 0:
+ break;
+ case '(':
+ h++;
+ continue;
+ case ')':
+ h--;
+ continue;
+ case '=':
+ case ':':
+ case ',':
+ if (h <= 0)
+ {
+ a = v;
+ break;
+ }
+ continue;
+ default:
+ continue;
+ }
+ if (i = *--v)
+ {
+ *v = 0;
+ if (i == ':' && fp->fmt.fmt == 's' && strlen(a) > 4 && !isalnum(*(a + 4)))
+ {
+ d = *(a + 4);
+ *(a + 4) = 0;
+ if (streq(a, "case"))
+ x = FMT_case;
+ else if (streq(a, "edit"))
+ x = FMT_edit;
+ *(a + 4) = d;
+ if (x)
+ a = 0;
+ }
+ }
+ break;
+ }
+ n = i;
+ t = fp->fmt.t_str;
+ fp->fmt.t_str = b;
+ h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
+ fp->fmt.t_str = t;
+ if (i)
+ *v++ = i;
+ }
+ else
+ {
+ h = (*fp->lookup)(fp->handle, &fp->fmt, a, &s, &n);
+ v = 0;
+ }
+ fp->fmt.flags |= SFFMT_VALUE;
+ switch (fp->fmt.fmt)
+ {
+ case 'c':
+ value->c = s ? *s : n;
+ break;
+ case 'd':
+ case 'i':
+ fp->fmt.size = sizeof(Sflong_t);
+ value->q = (Sflong_t)(s ? strtoll(s, NiL, 0) : n);
+ break;
+ case 'o':
+ case 'u':
+ case 'x':
+ fp->fmt.size = sizeof(Sflong_t);
+ value->q = s ? (Sflong_t)strtoull(s, NiL, 0) : n;
+ break;
+ case 'p':
+ if (s)
+ n = strtoll(s, NiL, 0);
+ value->p = pointerof(n);
+ break;
+ case 'q':
+ if (s)
+ {
+ fp->fmt.fmt = 's';
+ value->s = fmtquote(s, "$'", "'", strlen(s), 0);
+ }
+ else
+ {
+ fp->fmt.fmt = 'd';
+ value->q = n;
+ }
+ break;
+ case 's':
+ if (!s && (!h || !fp->tmp[1] && !(fp->tmp[1] = sfstropen()) || sfprintf(fp->tmp[1], "%I*d", sizeof(n), n) <= 0 || !(s = sfstruse(fp->tmp[1]))))
+ s = "";
+ if (x)
+ {
+ h = 0;
+ d = initfield(&f, v + 4);
+ switch (x)
+ {
+ case FMT_case:
+ while ((a = getfield(&f, 1)) && (v = getfield(&f, 0)))
+ {
+ if (strmatch(s, a))
+ {
+ Fmt_t fmt;
+
+ fmt = *fp;
+ fmt.fmt.form = v;
+ for (h = 0; h < elementsof(fmt.tmp); h++)
+ fmt.tmp[h] = 0;
+ if (!fp->tmp[0] && !(fp->tmp[0] = sfstropen()) || sfprintf(fp->tmp[0], "%!", &fmt) <= 0 || !(s = sfstruse(fp->tmp[0])))
+ s = "";
+ *(v - 1) = d;
+ if (f.delimiter)
+ *f.next = d;
+ for (h = 0; h < elementsof(fmt.tmp); h++)
+ if (fmt.tmp[h])
+ sfclose(fmt.tmp[h]);
+ h = 1;
+ break;
+ }
+ *(v - 1) = d;
+ }
+ break;
+ case FMT_edit:
+ for (x = 0; *f.next; x ^= 1)
+ {
+ if (fp->re[x])
+ regfree(fp->re[x]);
+ else
+ fp->re[x] = &fp->red[x];
+ if (regcomp(fp->re[x], f.next, REG_DELIMITED|REG_NULL))
+ break;
+ f.next += fp->re[x]->re_npat;
+ if (regsubcomp(fp->re[x], f.next, NiL, 0, 0))
+ break;
+ f.next += fp->re[x]->re_npat;
+ if (!regexec(fp->re[x], s, elementsof(match), match, 0) && !regsubexec(fp->re[x], s, elementsof(match), match))
+ {
+ s = fp->re[x]->re_sub->re_buf;
+ if (fp->re[x]->re_sub->re_flags & REG_SUB_STOP)
+ break;
+ }
+ }
+ h = 1;
+ break;
+ }
+ if (!h)
+ s = "";
+ }
+ value->s = s;
+ if (fp->level == 1)
+ while ((s = strchr(s, CC_esc)) && *(s + 1) == '[')
+ do fp->invisible++; while (*s && !islower(*s++));
+ break;
+ case 'Z':
+ fp->fmt.fmt = 'c';
+ value->c = 0;
+ break;
+ case '\n':
+ value->s = "\n";
+ break;
+ case '.':
+ value->i = n;
+ break;
+ default:
+ if ((!fp->convert || !(value->s = (*fp->convert)(fp->handle, &fp->fmt, a, s, n))) && (!fp->tmp[0] && !(fp->tmp[0] = sfstropen()) || sfprintf(fp->tmp[0], "%%%c", fp->fmt.fmt) <= 0 || !(value->s = sfstruse(fp->tmp[0]))))
+ value->s = "";
+ break;
+ }
+ fp->level--;
+ return 0;
+}
+
+/*
+ * this is the original interface
+ */
+
+int
+sfkeyprintf(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
+{
+ register int i;
+ int r;
+ Fmt_t fmt;
+
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.fmt.version = SFIO_VERSION;
+ fmt.fmt.form = (char*)format;
+ fmt.fmt.extf = getfmt;
+ fmt.handle = handle;
+ fmt.lookup = lookup;
+ fmt.convert = convert;
+ r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
+ for (i = 0; i < elementsof(fmt.tmp); i++)
+ if (fmt.tmp[i])
+ sfclose(fmt.tmp[i]);
+ for (i = 0; i < elementsof(fmt.re); i++)
+ if (fmt.re[i])
+ regfree(fmt.re[i]);
+ return r;
+}
+
+#undef _AST_API_H
+
+#include <ast_api.h>
+
+/*
+ * Sffmt_t* callback args
+ */
+
+int
+sfkeyprintf_20000308(Sfio_t* sp, void* handle, const char* format, Sf_key_lookup_t lookup, Sf_key_convert_t convert)
+{
+ register int i;
+ int r;
+ Fmt_t fmt;
+
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.version = 20030909;
+ fmt.fmt.version = SFIO_VERSION;
+ fmt.fmt.form = (char*)format;
+ fmt.fmt.extf = getfmt;
+ fmt.handle = handle;
+ fmt.lookup = lookup;
+ fmt.convert = convert;
+ r = sfprintf(sp, "%!", &fmt) - fmt.invisible;
+ for (i = 0; i < elementsof(fmt.tmp); i++)
+ if (fmt.tmp[i])
+ sfclose(fmt.tmp[i]);
+ return r;
+}
diff --git a/src/lib/libast/disc/sfstrtmp.c b/src/lib/libast/disc/sfstrtmp.c
new file mode 100644
index 0000000..beed91b
--- /dev/null
+++ b/src/lib/libast/disc/sfstrtmp.c
@@ -0,0 +1,62 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2011 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* 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
+/*
+ * Glenn Fowler
+ * AT&T Research
+ *
+ * sfio tmp string buffer support
+ */
+
+#include <sfio_t.h>
+#include <ast.h>
+
+#if __OBSOLETE__ >= 20070101 /* sfstr* macros now use sfsetbuf() */
+
+NoN(sfstrtmp)
+
+#else
+
+#if defined(__EXPORT__)
+#define extern __EXPORT__
+#endif
+
+/*
+ * replace buffer in string stream f for either SF_READ or SF_WRITE
+ */
+
+extern int
+sfstrtmp(register Sfio_t* f, int mode, void* buf, size_t siz)
+{
+ if (!(f->_flags & SF_STRING))
+ return -1;
+ if (f->_flags & SF_MALLOC)
+ free(f->_data);
+ f->_flags &= ~(SF_ERROR|SF_MALLOC);
+ f->mode = mode;
+ f->_next = f->_data = (unsigned char*)buf;
+ f->_endw = f->_endr = f->_endb = f->_data + siz;
+ f->_size = siz;
+ return 0;
+}
+
+#endif