|
Packit Service |
a8c26c |
/***********************************************************************
|
|
Packit Service |
a8c26c |
* *
|
|
Packit Service |
a8c26c |
* This software is part of the ast package *
|
|
Packit Service |
a8c26c |
* Copyright (c) 1985-2011 AT&T Intellectual Property *
|
|
Packit Service |
a8c26c |
* and is licensed under the *
|
|
Packit Service |
a8c26c |
* Eclipse Public License, Version 1.0 *
|
|
Packit Service |
a8c26c |
* by AT&T Intellectual Property *
|
|
Packit Service |
a8c26c |
* *
|
|
Packit Service |
a8c26c |
* A copy of the License is available at *
|
|
Packit Service |
a8c26c |
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
Packit Service |
a8c26c |
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
Packit Service |
a8c26c |
* *
|
|
Packit Service |
a8c26c |
* Information and Software Systems Research *
|
|
Packit Service |
a8c26c |
* AT&T Research *
|
|
Packit Service |
a8c26c |
* Florham Park NJ *
|
|
Packit Service |
a8c26c |
* *
|
|
Packit Service |
a8c26c |
* Glenn Fowler <gsf@research.att.com> *
|
|
Packit Service |
a8c26c |
* David Korn <dgk@research.att.com> *
|
|
Packit Service |
a8c26c |
* Phong Vo <kpv@research.att.com> *
|
|
Packit Service |
a8c26c |
* *
|
|
Packit Service |
a8c26c |
***********************************************************************/
|
|
Packit Service |
a8c26c |
#include "sfhdr.h"
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* Add a new discipline to the discipline stack. Each discipline
|
|
Packit Service |
a8c26c |
** provides alternative I/O functions that are analogues of the
|
|
Packit Service |
a8c26c |
** system calls.
|
|
Packit Service |
a8c26c |
**
|
|
Packit Service |
a8c26c |
** When the application fills or flushes the stream buffer, data
|
|
Packit Service |
a8c26c |
** will be processed through discipline functions. A case deserving
|
|
Packit Service |
a8c26c |
** consideration is stacking a discipline onto a read stream. Each
|
|
Packit Service |
a8c26c |
** discipline operation implies buffer synchronization so the stream
|
|
Packit Service |
a8c26c |
** buffer should be empty. However, a read stream representing an
|
|
Packit Service |
a8c26c |
** unseekable device (eg, a pipe) may not be synchronizable. In that
|
|
Packit Service |
a8c26c |
** case, any buffered data must then be fed to the new discipline
|
|
Packit Service |
a8c26c |
** to preserve data processing semantics. This is done by creating
|
|
Packit Service |
a8c26c |
** a temporary discipline to cache such buffered data and feed
|
|
Packit Service |
a8c26c |
** them to the new discipline when its readf() asks for new data.
|
|
Packit Service |
a8c26c |
** Care must then be taken to remove this temporary discipline
|
|
Packit Service |
a8c26c |
** when it runs out of cached data.
|
|
Packit Service |
a8c26c |
**
|
|
Packit Service |
a8c26c |
** Written by Kiem-Phong Vo
|
|
Packit Service |
a8c26c |
*/
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
typedef struct _dccache_s
|
|
Packit Service |
a8c26c |
{ Sfdisc_t disc;
|
|
Packit Service |
a8c26c |
uchar* data;
|
|
Packit Service |
a8c26c |
uchar* endb;
|
|
Packit Service |
a8c26c |
} Dccache_t;
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
#if __STD_C
|
|
Packit Service |
a8c26c |
static int _dccaexcept(Sfio_t* f, int type, Void_t* val, Sfdisc_t* disc)
|
|
Packit Service |
a8c26c |
#else
|
|
Packit Service |
a8c26c |
static int _dccaexcept(f,type,val,disc)
|
|
Packit Service |
a8c26c |
Sfio_t* f;
|
|
Packit Service |
a8c26c |
int type;
|
|
Packit Service |
a8c26c |
Void_t* val;
|
|
Packit Service |
a8c26c |
Sfdisc_t* disc;
|
|
Packit Service |
a8c26c |
#endif
|
|
Packit Service |
a8c26c |
{
|
|
Packit Service |
a8c26c |
if(disc && type == SF_FINAL)
|
|
Packit Service |
a8c26c |
free(disc);
|
|
Packit Service |
a8c26c |
return 0;
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
#if __STD_C
|
|
Packit Service |
a8c26c |
static ssize_t _dccaread(Sfio_t* f, Void_t* buf, size_t size, Sfdisc_t* disc)
|
|
Packit Service |
a8c26c |
#else
|
|
Packit Service |
a8c26c |
static ssize_t _dccaread(f, buf, size, disc)
|
|
Packit Service |
a8c26c |
Sfio_t* f;
|
|
Packit Service |
a8c26c |
Void_t* buf;
|
|
Packit Service |
a8c26c |
size_t size;
|
|
Packit Service |
a8c26c |
Sfdisc_t* disc;
|
|
Packit Service |
a8c26c |
#endif
|
|
Packit Service |
a8c26c |
{
|
|
Packit Service |
a8c26c |
ssize_t sz;
|
|
Packit Service |
a8c26c |
Sfdisc_t *prev;
|
|
Packit Service |
a8c26c |
Dccache_t *dcca;
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
if(!f) /* bad stream */
|
|
Packit Service |
a8c26c |
return -1;
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* make sure that this is on the discipline stack */
|
|
Packit Service |
a8c26c |
for(prev = f->disc; prev; prev = prev->disc)
|
|
Packit Service |
a8c26c |
if(prev->disc == disc)
|
|
Packit Service |
a8c26c |
break;
|
|
Packit Service |
a8c26c |
if(!prev)
|
|
Packit Service |
a8c26c |
return -1;
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
if(size <= 0) /* nothing to do */
|
|
Packit Service |
a8c26c |
return size;
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* read from available data */
|
|
Packit Service |
a8c26c |
dcca = (Dccache_t*)disc;
|
|
Packit Service |
a8c26c |
if((sz = dcca->endb - dcca->data) > (ssize_t)size)
|
|
Packit Service |
a8c26c |
sz = (ssize_t)size;
|
|
Packit Service |
a8c26c |
memcpy(buf, dcca->data, sz);
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
if((dcca->data += sz) >= dcca->endb) /* free empty cache */
|
|
Packit Service |
a8c26c |
{ prev->disc = disc->disc;
|
|
Packit Service |
a8c26c |
free(disc);
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
return sz;
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
#if __STD_C
|
|
Packit Service |
a8c26c |
Sfdisc_t* sfdisc(Sfio_t* f, Sfdisc_t* disc)
|
|
Packit Service |
a8c26c |
#else
|
|
Packit Service |
a8c26c |
Sfdisc_t* sfdisc(f,disc)
|
|
Packit Service |
a8c26c |
Sfio_t* f;
|
|
Packit Service |
a8c26c |
Sfdisc_t* disc;
|
|
Packit Service |
a8c26c |
#endif
|
|
Packit Service |
a8c26c |
{
|
|
Packit Service |
a8c26c |
Sfdisc_t *d, *rdisc;
|
|
Packit Service |
a8c26c |
Sfread_f oreadf;
|
|
Packit Service |
a8c26c |
Sfwrite_f owritef;
|
|
Packit Service |
a8c26c |
Sfseek_f oseekf;
|
|
Packit Service |
a8c26c |
ssize_t n;
|
|
Packit Service |
a8c26c |
Dccache_t *dcca = NIL(Dccache_t*);
|
|
Packit Service |
a8c26c |
SFMTXDECL(f); /* declare a local stream variable for multithreading */
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
SFMTXENTER(f, NIL(Sfdisc_t*));
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
if((Sfio_t*)disc == f) /* special case to get the top discipline */
|
|
Packit Service |
a8c26c |
SFMTXRETURN(f,f->disc);
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
if((f->flags&SF_READ) && f->proc && (f->mode&SF_WRITE) )
|
|
Packit Service |
a8c26c |
{ /* make sure in read mode to check for read-ahead data */
|
|
Packit Service |
a8c26c |
if(_sfmode(f,SF_READ,0) < 0)
|
|
Packit Service |
a8c26c |
SFMTXRETURN(f, NIL(Sfdisc_t*));
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
else
|
|
Packit Service |
a8c26c |
{ if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
|
|
Packit Service |
a8c26c |
SFMTXRETURN(f, NIL(Sfdisc_t*));
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
SFLOCK(f,0);
|
|
Packit Service |
a8c26c |
rdisc = NIL(Sfdisc_t*);
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* disallow popping while there is cached data */
|
|
Packit Service |
a8c26c |
if(!disc && f->disc && f->disc->disc && f->disc->disc->readf == _dccaread )
|
|
Packit Service |
a8c26c |
goto done;
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* synchronize before switching to a new discipline */
|
|
Packit Service |
a8c26c |
if(!(f->flags&SF_STRING))
|
|
Packit Service |
a8c26c |
{ (void)SFSYNC(f); /* do a silent buffer synch */
|
|
Packit Service |
a8c26c |
if((f->mode&SF_READ) && (f->mode&SF_SYNCED) )
|
|
Packit Service |
a8c26c |
{ f->mode &= ~SF_SYNCED;
|
|
Packit Service |
a8c26c |
f->endb = f->next = f->endr = f->endw = f->data;
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* if there is buffered data, ask app before proceeding */
|
|
Packit Service |
a8c26c |
if(((f->mode&SF_WRITE) && (n = f->next-f->data) > 0) ||
|
|
Packit Service |
a8c26c |
((f->mode&SF_READ) && (n = f->endb-f->next) > 0) )
|
|
Packit Service |
a8c26c |
{ int rv = 0;
|
|
Packit Service |
a8c26c |
if(rv == 0 && f->disc && f->disc->exceptf) /* ask current discipline */
|
|
Packit Service |
a8c26c |
{ SFOPEN(f,0);
|
|
Packit Service |
a8c26c |
rv = (*f->disc->exceptf)(f, SF_DBUFFER, &n, f->disc);
|
|
Packit Service |
a8c26c |
SFLOCK(f,0);
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
if(rv == 0 && disc && disc->exceptf) /* ask discipline being pushed */
|
|
Packit Service |
a8c26c |
{ SFOPEN(f,0);
|
|
Packit Service |
a8c26c |
rv = (*disc->exceptf)(f, SF_DBUFFER, &n, disc);
|
|
Packit Service |
a8c26c |
SFLOCK(f,0);
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
if(rv < 0)
|
|
Packit Service |
a8c26c |
goto done;
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* trick the new discipline into processing already buffered data */
|
|
Packit Service |
a8c26c |
if((f->mode&SF_READ) && n > 0 && disc && disc->readf )
|
|
Packit Service |
a8c26c |
{ if(!(dcca = (Dccache_t*)malloc(sizeof(Dccache_t)+n)) )
|
|
Packit Service |
a8c26c |
goto done;
|
|
Packit Service |
a8c26c |
memclear(dcca, sizeof(Dccache_t));
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
dcca->disc.readf = _dccaread;
|
|
Packit Service |
a8c26c |
dcca->disc.exceptf = _dccaexcept;
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* move buffered data into the temp discipline */
|
|
Packit Service |
a8c26c |
dcca->data = ((uchar*)dcca) + sizeof(Dccache_t);
|
|
Packit Service |
a8c26c |
dcca->endb = dcca->data + n;
|
|
Packit Service |
a8c26c |
memcpy(dcca->data, f->next, n);
|
|
Packit Service |
a8c26c |
f->endb = f->next = f->endr = f->endw = f->data;
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* save old readf, writef, and seekf to see if stream need reinit */
|
|
Packit Service |
a8c26c |
#define GETDISCF(func,iof,type) \
|
|
Packit Service |
a8c26c |
{ for(d = f->disc; d && !d->iof; d = d->disc) ; \
|
|
Packit Service |
a8c26c |
func = d ? d->iof : NIL(type); \
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
GETDISCF(oreadf,readf,Sfread_f);
|
|
Packit Service |
a8c26c |
GETDISCF(owritef,writef,Sfwrite_f);
|
|
Packit Service |
a8c26c |
GETDISCF(oseekf,seekf,Sfseek_f);
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
if(disc == SF_POPDISC)
|
|
Packit Service |
a8c26c |
{ /* popping, warn the being popped discipline */
|
|
Packit Service |
a8c26c |
if(!(d = f->disc) )
|
|
Packit Service |
a8c26c |
goto done;
|
|
Packit Service |
a8c26c |
disc = d->disc;
|
|
Packit Service |
a8c26c |
if(d->exceptf)
|
|
Packit Service |
a8c26c |
{ SFOPEN(f,0);
|
|
Packit Service |
a8c26c |
if((*(d->exceptf))(f,SF_DPOP,(Void_t*)disc,d) < 0 )
|
|
Packit Service |
a8c26c |
goto done;
|
|
Packit Service |
a8c26c |
SFLOCK(f,0);
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
f->disc = disc;
|
|
Packit Service |
a8c26c |
rdisc = d;
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
else
|
|
Packit Service |
a8c26c |
{ /* pushing, warn being pushed discipline */
|
|
Packit Service |
a8c26c |
do
|
|
Packit Service |
a8c26c |
{ /* loop to handle the case where d may pop itself */
|
|
Packit Service |
a8c26c |
d = f->disc;
|
|
Packit Service |
a8c26c |
if(d && d->exceptf)
|
|
Packit Service |
a8c26c |
{ SFOPEN(f,0);
|
|
Packit Service |
a8c26c |
if( (*(d->exceptf))(f,SF_DPUSH,(Void_t*)disc,d) < 0 )
|
|
Packit Service |
a8c26c |
goto done;
|
|
Packit Service |
a8c26c |
SFLOCK(f,0);
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
} while(d != f->disc);
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* make sure we are not creating an infinite loop */
|
|
Packit Service |
a8c26c |
for(; d; d = d->disc)
|
|
Packit Service |
a8c26c |
if(d == disc)
|
|
Packit Service |
a8c26c |
goto done;
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
/* set new disc */
|
|
Packit Service |
a8c26c |
if(dcca) /* insert the discipline with cached data */
|
|
Packit Service |
a8c26c |
{ dcca->disc.disc = f->disc;
|
|
Packit Service |
a8c26c |
disc->disc = &dcca->disc;
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
else disc->disc = f->disc;
|
|
Packit Service |
a8c26c |
f->disc = disc;
|
|
Packit Service |
a8c26c |
rdisc = disc;
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
if(!(f->flags&SF_STRING) )
|
|
Packit Service |
a8c26c |
{ /* this stream may have to be reinitialized */
|
|
Packit Service |
a8c26c |
reg int reinit = 0;
|
|
Packit Service |
a8c26c |
#define DISCF(dst,iof,type) (dst ? dst->iof : NIL(type))
|
|
Packit Service |
a8c26c |
#define REINIT(oiof,iof,type) \
|
|
Packit Service |
a8c26c |
if(!reinit) \
|
|
Packit Service |
a8c26c |
{ for(d = f->disc; d && !d->iof; d = d->disc) ; \
|
|
Packit Service |
a8c26c |
if(DISCF(d,iof,type) != oiof) \
|
|
Packit Service |
a8c26c |
reinit = 1; \
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
REINIT(oreadf,readf,Sfread_f);
|
|
Packit Service |
a8c26c |
REINIT(owritef,writef,Sfwrite_f);
|
|
Packit Service |
a8c26c |
REINIT(oseekf,seekf,Sfseek_f);
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
if(reinit)
|
|
Packit Service |
a8c26c |
{ SETLOCAL(f);
|
|
Packit Service |
a8c26c |
f->bits &= ~SF_NULL; /* turn off /dev/null handling */
|
|
Packit Service |
a8c26c |
if((f->bits&SF_MMAP) || (f->mode&SF_INIT))
|
|
Packit Service |
a8c26c |
sfsetbuf(f,NIL(Void_t*),(size_t)SF_UNBOUND);
|
|
Packit Service |
a8c26c |
else if(f->data == f->tiny)
|
|
Packit Service |
a8c26c |
sfsetbuf(f,NIL(Void_t*),0);
|
|
Packit Service |
a8c26c |
else
|
|
Packit Service |
a8c26c |
{ int flags = f->flags;
|
|
Packit Service |
a8c26c |
sfsetbuf(f,(Void_t*)f->data,f->size);
|
|
Packit Service |
a8c26c |
f->flags |= (flags&SF_MALLOC);
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
}
|
|
Packit Service |
a8c26c |
|
|
Packit Service |
a8c26c |
done :
|
|
Packit Service |
a8c26c |
SFOPEN(f,0);
|
|
Packit Service |
a8c26c |
SFMTXRETURN(f, rdisc);
|
|
Packit Service |
a8c26c |
}
|