1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#include "sfdchdr.h"
1N/A
1N/A/* Discipline to make an unseekable read stream seekable
1N/A**
1N/A** sfraise(f,SFSK_DISCARD,0) discards previous seek data
1N/A** but seeks from current offset on still allowed
1N/A**
1N/A** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
1N/A*/
1N/A
1N/Atypedef struct _skable_s
1N/A{ Sfdisc_t disc; /* sfio discipline */
1N/A Sfio_t* shadow; /* to shadow data */
1N/A Sfoff_t discard;/* sfseek(f,-1,SEEK_SET) discarded data */
1N/A Sfoff_t extent; /* shadow extent */
1N/A int eof; /* if eof has been reached */
1N/A} Seek_t;
1N/A
1N/A#if __STD_C
1N/Astatic ssize_t skwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
1N/A#else
1N/Astatic ssize_t skwrite(f, buf, n, disc)
1N/ASfio_t* f; /* stream involved */
1N/AVoid_t* buf; /* buffer to read into */
1N/Asize_t n; /* number of bytes to read */
1N/ASfdisc_t* disc; /* discipline */
1N/A#endif
1N/A{
1N/A return (ssize_t)(-1);
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic ssize_t skread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
1N/A#else
1N/Astatic ssize_t skread(f, buf, n, disc)
1N/ASfio_t* f; /* stream involved */
1N/AVoid_t* buf; /* buffer to read into */
1N/Asize_t n; /* number of bytes to read */
1N/ASfdisc_t* disc; /* discipline */
1N/A#endif
1N/A{
1N/A Seek_t* sk;
1N/A Sfio_t* sf;
1N/A Sfoff_t addr;
1N/A ssize_t r, w, p;
1N/A
1N/A sk = (Seek_t*)disc;
1N/A sf = sk->shadow;
1N/A if(sk->eof)
1N/A return sfread(sf,buf,n);
1N/A
1N/A addr = sfseek(sf,(Sfoff_t)0,SEEK_CUR);
1N/A
1N/A if(addr+n <= sk->extent)
1N/A return sfread(sf,buf,n);
1N/A
1N/A if((r = (ssize_t)(sk->extent-addr)) > 0)
1N/A { if((w = sfread(sf,buf,r)) != r)
1N/A return w;
1N/A buf = (char*)buf + r;
1N/A n -= r;
1N/A }
1N/A
1N/A /* do a raw read */
1N/A if((w = sfrd(f,buf,n,disc)) <= 0)
1N/A { sk->eof = 1;
1N/A w = 0;
1N/A }
1N/A else
1N/A {
1N/A if((p = sfwrite(sf,buf,w)) != w)
1N/A sk->eof = 1;
1N/A if(p > 0)
1N/A sk->extent += p;
1N/A }
1N/A
1N/A return r+w;
1N/A}
1N/A
1N/A#if __STD_C
1N/Astatic Sfoff_t skseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
1N/A#else
1N/Astatic Sfoff_t skseek(f, addr, type, disc)
1N/ASfio_t* f;
1N/ASfoff_t addr;
1N/Aint type;
1N/ASfdisc_t* disc;
1N/A#endif
1N/A{
1N/A Seek_t* sk;
1N/A Sfio_t* sf;
1N/A char buf[SF_BUFSIZE];
1N/A ssize_t r, w;
1N/A
1N/A sk = (Seek_t*)disc;
1N/A sf = sk->shadow;
1N/A
1N/A switch (type)
1N/A {
1N/A case SEEK_SET:
1N/A addr -= sk->discard;
1N/A break;
1N/A case SEEK_CUR:
1N/A addr += sftell(sf);
1N/A break;
1N/A case SEEK_END:
1N/A addr += sk->extent;
1N/A break;
1N/A default:
1N/A return -1;
1N/A }
1N/A
1N/A if(addr < 0)
1N/A return (Sfoff_t)(-1);
1N/A else if(addr > sk->extent)
1N/A { if(sk->eof)
1N/A return (Sfoff_t)(-1);
1N/A
1N/A /* read enough to reach the seek point */
1N/A while(addr > sk->extent)
1N/A { if(addr > sk->extent+sizeof(buf) )
1N/A w = sizeof(buf);
1N/A else w = (int)(addr-sk->extent);
1N/A if((r = sfrd(f,buf,w,disc)) <= 0)
1N/A w = r-1;
1N/A else if((w = sfwrite(sf,buf,r)) > 0)
1N/A sk->extent += w;
1N/A if(w != r)
1N/A { sk->eof = 1;
1N/A break;
1N/A }
1N/A }
1N/A
1N/A if(addr > sk->extent)
1N/A return (Sfoff_t)(-1);
1N/A }
1N/A
1N/A return sfseek(sf,addr,SEEK_SET) + sk->discard;
1N/A}
1N/A
1N/A/* on close, remove the discipline */
1N/A#if __STD_C
1N/Astatic int skexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
1N/A#else
1N/Astatic int skexcept(f,type,data,disc)
1N/ASfio_t* f;
1N/Aint type;
1N/AVoid_t* data;
1N/ASfdisc_t* disc;
1N/A#endif
1N/A{
1N/A Seek_t* sk;
1N/A
1N/A sk = (Seek_t*)disc;
1N/A
1N/A switch (type)
1N/A {
1N/A case SF_FINAL:
1N/A case SF_DPOP:
1N/A sfclose(sk->shadow);
1N/A free(disc);
1N/A break;
1N/A case SFSK_DISCARD:
1N/A sk->eof = 0;
1N/A sk->discard += sk->extent;
1N/A sk->extent = 0;
1N/A sfseek(sk->shadow,(Sfoff_t)0,SEEK_SET);
1N/A break;
1N/A }
1N/A return 0;
1N/A}
1N/A
1N/A#if __STD_C
1N/Aint sfdcseekable(Sfio_t* f)
1N/A#else
1N/Aint sfdcseekable(f)
1N/ASfio_t* f;
1N/A#endif
1N/A{
1N/A reg Seek_t* sk;
1N/A
1N/A /* see if already seekable */
1N/A if(sfseek(f,(Sfoff_t)0,SEEK_CUR) >= 0)
1N/A return 0;
1N/A
1N/A if(!(sk = (Seek_t*)malloc(sizeof(Seek_t))) )
1N/A return -1;
1N/A memset(sk, 0, sizeof(*sk));
1N/A
1N/A sk->disc.readf = skread;
1N/A sk->disc.writef = skwrite;
1N/A sk->disc.seekf = skseek;
1N/A sk->disc.exceptf = skexcept;
1N/A sk->shadow = sftmp(SF_BUFSIZE);
1N/A sk->discard = 0;
1N/A sk->extent = 0;
1N/A sk->eof = 0;
1N/A
1N/A if(sfdisc(f, (Sfdisc_t*)sk) != (Sfdisc_t*)sk)
1N/A { sfclose(sk->shadow);
1N/A free(sk);
1N/A return -1;
1N/A }
1N/A
1N/A return 0;
1N/A}