14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #include "sfdchdr.h"
234887Schin
244887Schin /* Discipline to make an unseekable read stream seekable
254887Schin **
264887Schin ** sfraise(f,SFSK_DISCARD,0) discards previous seek data
274887Schin ** but seeks from current offset on still allowed
284887Schin **
294887Schin ** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
304887Schin */
314887Schin
324887Schin typedef struct _skable_s
334887Schin { Sfdisc_t disc; /* sfio discipline */
344887Schin Sfio_t* shadow; /* to shadow data */
354887Schin Sfoff_t discard;/* sfseek(f,-1,SEEK_SET) discarded data */
364887Schin Sfoff_t extent; /* shadow extent */
374887Schin int eof; /* if eof has been reached */
384887Schin } Seek_t;
394887Schin
404887Schin #if __STD_C
skwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)414887Schin static ssize_t skwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
424887Schin #else
434887Schin static ssize_t skwrite(f, buf, n, disc)
444887Schin Sfio_t* f; /* stream involved */
454887Schin Void_t* buf; /* buffer to read into */
464887Schin size_t n; /* number of bytes to read */
474887Schin Sfdisc_t* disc; /* discipline */
484887Schin #endif
494887Schin {
504887Schin return (ssize_t)(-1);
514887Schin }
524887Schin
534887Schin #if __STD_C
skread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)544887Schin static ssize_t skread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
554887Schin #else
564887Schin static ssize_t skread(f, buf, n, disc)
574887Schin Sfio_t* f; /* stream involved */
584887Schin Void_t* buf; /* buffer to read into */
594887Schin size_t n; /* number of bytes to read */
604887Schin Sfdisc_t* disc; /* discipline */
614887Schin #endif
624887Schin {
634887Schin Seek_t* sk;
644887Schin Sfio_t* sf;
654887Schin Sfoff_t addr;
664887Schin ssize_t r, w, p;
674887Schin
684887Schin sk = (Seek_t*)disc;
694887Schin sf = sk->shadow;
704887Schin if(sk->eof)
714887Schin return sfread(sf,buf,n);
724887Schin
734887Schin addr = sfseek(sf,(Sfoff_t)0,SEEK_CUR);
744887Schin
754887Schin if(addr+n <= sk->extent)
764887Schin return sfread(sf,buf,n);
774887Schin
784887Schin if((r = (ssize_t)(sk->extent-addr)) > 0)
794887Schin { if((w = sfread(sf,buf,r)) != r)
804887Schin return w;
814887Schin buf = (char*)buf + r;
824887Schin n -= r;
834887Schin }
844887Schin
854887Schin /* do a raw read */
864887Schin if((w = sfrd(f,buf,n,disc)) <= 0)
874887Schin { sk->eof = 1;
884887Schin w = 0;
894887Schin }
904887Schin else
914887Schin {
924887Schin if((p = sfwrite(sf,buf,w)) != w)
934887Schin sk->eof = 1;
944887Schin if(p > 0)
954887Schin sk->extent += p;
964887Schin }
974887Schin
984887Schin return r+w;
994887Schin }
1004887Schin
1014887Schin #if __STD_C
skseek(Sfio_t * f,Sfoff_t addr,int type,Sfdisc_t * disc)1024887Schin static Sfoff_t skseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
1034887Schin #else
1044887Schin static Sfoff_t skseek(f, addr, type, disc)
1054887Schin Sfio_t* f;
1064887Schin Sfoff_t addr;
1074887Schin int type;
1084887Schin Sfdisc_t* disc;
1094887Schin #endif
1104887Schin {
1114887Schin Seek_t* sk;
1124887Schin Sfio_t* sf;
1134887Schin char buf[SF_BUFSIZE];
1144887Schin ssize_t r, w;
1154887Schin
1164887Schin sk = (Seek_t*)disc;
1174887Schin sf = sk->shadow;
1184887Schin
1194887Schin switch (type)
1204887Schin {
1214887Schin case SEEK_SET:
1224887Schin addr -= sk->discard;
1234887Schin break;
1244887Schin case SEEK_CUR:
1254887Schin addr += sftell(sf);
1264887Schin break;
1274887Schin case SEEK_END:
1284887Schin addr += sk->extent;
1294887Schin break;
1304887Schin default:
1314887Schin return -1;
1324887Schin }
1334887Schin
1344887Schin if(addr < 0)
1354887Schin return (Sfoff_t)(-1);
1364887Schin else if(addr > sk->extent)
1374887Schin { if(sk->eof)
1384887Schin return (Sfoff_t)(-1);
1394887Schin
1404887Schin /* read enough to reach the seek point */
1414887Schin while(addr > sk->extent)
1424887Schin { if(addr > sk->extent+sizeof(buf) )
1434887Schin w = sizeof(buf);
1444887Schin else w = (int)(addr-sk->extent);
1454887Schin if((r = sfrd(f,buf,w,disc)) <= 0)
1464887Schin w = r-1;
1474887Schin else if((w = sfwrite(sf,buf,r)) > 0)
1484887Schin sk->extent += w;
1494887Schin if(w != r)
1504887Schin { sk->eof = 1;
1514887Schin break;
1524887Schin }
1534887Schin }
1544887Schin
1554887Schin if(addr > sk->extent)
1564887Schin return (Sfoff_t)(-1);
1574887Schin }
1584887Schin
1594887Schin return sfseek(sf,addr,SEEK_SET) + sk->discard;
1604887Schin }
1614887Schin
1624887Schin /* on close, remove the discipline */
1634887Schin #if __STD_C
skexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)1644887Schin static int skexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
1654887Schin #else
1664887Schin static int skexcept(f,type,data,disc)
1674887Schin Sfio_t* f;
1684887Schin int type;
1694887Schin Void_t* data;
1704887Schin Sfdisc_t* disc;
1714887Schin #endif
1724887Schin {
1734887Schin Seek_t* sk;
1744887Schin
1754887Schin sk = (Seek_t*)disc;
1764887Schin
1774887Schin switch (type)
1784887Schin {
1794887Schin case SF_FINAL:
1804887Schin case SF_DPOP:
1814887Schin sfclose(sk->shadow);
1824887Schin free(disc);
1834887Schin break;
1844887Schin case SFSK_DISCARD:
1854887Schin sk->eof = 0;
1864887Schin sk->discard += sk->extent;
1874887Schin sk->extent = 0;
1884887Schin sfseek(sk->shadow,(Sfoff_t)0,SEEK_SET);
1894887Schin break;
1904887Schin }
1914887Schin return 0;
1924887Schin }
1934887Schin
1944887Schin #if __STD_C
sfdcseekable(Sfio_t * f)1954887Schin int sfdcseekable(Sfio_t* f)
1964887Schin #else
1974887Schin int sfdcseekable(f)
1984887Schin Sfio_t* f;
1994887Schin #endif
2004887Schin {
2014887Schin reg Seek_t* sk;
2024887Schin
2034887Schin /* see if already seekable */
2044887Schin if(sfseek(f,(Sfoff_t)0,SEEK_CUR) >= 0)
2054887Schin return 0;
2064887Schin
2074887Schin if(!(sk = (Seek_t*)malloc(sizeof(Seek_t))) )
2084887Schin return -1;
2094887Schin memset(sk, 0, sizeof(*sk));
2104887Schin
2114887Schin sk->disc.readf = skread;
2124887Schin sk->disc.writef = skwrite;
2134887Schin sk->disc.seekf = skseek;
2144887Schin sk->disc.exceptf = skexcept;
2154887Schin sk->shadow = sftmp(SF_BUFSIZE);
2164887Schin sk->discard = 0;
2174887Schin sk->extent = 0;
2184887Schin sk->eof = 0;
2194887Schin
2204887Schin if(sfdisc(f, (Sfdisc_t*)sk) != (Sfdisc_t*)sk)
2214887Schin { sfclose(sk->shadow);
2224887Schin free(sk);
2234887Schin return -1;
2244887Schin }
2254887Schin
2264887Schin return 0;
2274887Schin }
228