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 "sfhdr.h"
234887Schin
244887Schin /* Reserve a segment of data or buffer.
254887Schin **
264887Schin ** Written by Kiem-Phong Vo.
274887Schin */
284887Schin
294887Schin #if __STD_C
sfreserve(Sfio_t * f,ssize_t size,int type)308462SApril.Chin@Sun.COM Void_t* sfreserve(Sfio_t* f, ssize_t size, int type)
314887Schin #else
324887Schin Void_t* sfreserve(f,size,type)
338462SApril.Chin@Sun.COM Sfio_t* f; /* file to peek */
344887Schin ssize_t size; /* size of peek */
354887Schin int type; /* LOCKR: lock stream, LASTR: last record */
364887Schin #endif
374887Schin {
384887Schin reg ssize_t n, now, sz, iosz;
394887Schin reg Sfrsrv_t* rsrv;
404887Schin reg Void_t* data;
414887Schin reg int mode, local;
428462SApril.Chin@Sun.COM SFMTXDECL(f);
434887Schin
448462SApril.Chin@Sun.COM SFMTXENTER(f,NIL(Void_t*));
454887Schin
464887Schin sz = size < 0 ? -size : size;
474887Schin
484887Schin /* see if we need to bias toward SF_WRITE instead of the default SF_READ */
494887Schin if(type < 0)
504887Schin mode = 0;
514887Schin else if((mode = type&SF_WRITE) )
524887Schin type &= ~SF_WRITE;
534887Schin
544887Schin /* return the last record */
554887Schin if(type == SF_LASTR )
564887Schin { if((n = f->endb - f->next) > 0 && n == f->val )
574887Schin { data = (Void_t*)f->next;
584887Schin f->next += n;
594887Schin }
604887Schin else if((rsrv = f->rsrv) && (n = -rsrv->slen) > 0)
614887Schin { rsrv->slen = 0;
624887Schin _Sfi = f->val = n;
634887Schin data = (Void_t*)rsrv->data;
644887Schin }
654887Schin else
664887Schin { _Sfi = f->val = -1;
674887Schin data = NIL(Void_t*);
684887Schin }
694887Schin
704887Schin SFMTXRETURN(f, data);
714887Schin }
724887Schin
734887Schin if(type > 0)
744887Schin { if(type == 1 ) /* upward compatibility mode */
754887Schin type = SF_LOCKR;
764887Schin else if(type != SF_LOCKR)
774887Schin SFMTXRETURN(f, NIL(Void_t*));
784887Schin }
794887Schin
804887Schin if(size == 0 && (type < 0 || type == SF_LOCKR) )
814887Schin { if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
824887Schin SFMTXRETURN(f, NIL(Void_t*));
834887Schin
844887Schin SFLOCK(f,0);
854887Schin if((n = f->endb - f->next) < 0)
864887Schin n = 0;
874887Schin
884887Schin goto done;
894887Schin }
904887Schin
914887Schin /* iterate until get to a stream that has data or buffer space */
924887Schin for(local = 0;; local = SF_LOCAL)
934887Schin { _Sfi = f->val = -1;
944887Schin
954887Schin if(!mode && !(mode = f->flags&SF_READ) )
964887Schin mode = SF_WRITE;
974887Schin if((int)f->mode != mode && _sfmode(f,mode,local) < 0)
984887Schin { SFOPEN(f,0);
994887Schin SFMTXRETURN(f, NIL(Void_t*));
1004887Schin }
1014887Schin
1024887Schin SFLOCK(f,local);
1034887Schin
1044887Schin if((n = now = f->endb - f->next) < 0)
1054887Schin n = 0;
1064887Schin if(n > 0 && n >= sz) /* all done */
1074887Schin break;
1084887Schin
1098462SApril.Chin@Sun.COM /* set amount to perform IO */
1108462SApril.Chin@Sun.COM if(size == 0 || (f->mode&SF_WRITE))
1114887Schin iosz = -1;
1128462SApril.Chin@Sun.COM else if(size < 0 && n == 0 && f->push) /* maybe stack-pop */
11310898Sroland.mainz@nrubsig.org { if((iosz = f->push->endb - f->push->next) == 0)
11410898Sroland.mainz@nrubsig.org iosz = f->push->size;
11510898Sroland.mainz@nrubsig.org if(iosz < sz)
11610898Sroland.mainz@nrubsig.org iosz = sz; /* so only get what is asked for */
11710898Sroland.mainz@nrubsig.org }
1184887Schin else
1198462SApril.Chin@Sun.COM { iosz = sz - n; /* get enough to fulfill requirement */
1208462SApril.Chin@Sun.COM if(size < 0 && iosz < (f->size - n) )
1218462SApril.Chin@Sun.COM iosz = f->size - n; /* get as much as possible */
1228462SApril.Chin@Sun.COM if(iosz <= 0) /* nothing to do */
1234887Schin break;
1244887Schin }
1254887Schin
1264887Schin /* do a buffer refill or flush */
1274887Schin now = n;
1284887Schin if(f->mode&SF_WRITE)
1294887Schin (void)SFFLSBUF(f, iosz);
1304887Schin else if(type == SF_LOCKR && f->extent < 0 && (f->flags&SF_SHARE) )
1314887Schin { if(n == 0) /* peek-read only if there is no buffered data */
1324887Schin { f->mode |= SF_RV;
1334887Schin (void)SFFILBUF(f, iosz );
1344887Schin }
1354887Schin if((n = f->endb - f->next) < sz)
1364887Schin { if(f->mode&SF_PKRD)
1374887Schin { f->endb = f->endr = f->next;
1384887Schin f->mode &= ~SF_PKRD;
1394887Schin }
1404887Schin break;
1414887Schin }
1424887Schin }
1438462SApril.Chin@Sun.COM else
1448462SApril.Chin@Sun.COM { /* sfreserve(f,0,0) == sfread(f, sfreserve(f,-1,SF_LOCKR), 0) */
1458462SApril.Chin@Sun.COM if(size == 0 && type == 0)
1468462SApril.Chin@Sun.COM f->mode |= SF_RV;
1478462SApril.Chin@Sun.COM
1488462SApril.Chin@Sun.COM (void)SFFILBUF(f, iosz );
1498462SApril.Chin@Sun.COM }
1504887Schin
1514887Schin if((n = f->endb - f->next) <= 0)
1524887Schin n = 0;
1534887Schin
1544887Schin if(n >= sz) /* got it */
1554887Schin break;
1564887Schin
1574887Schin if(n == now || sferror(f) || sfeof(f)) /* no progress */
1584887Schin break;
1594887Schin
1604887Schin /* request was only to assess data availability */
1614887Schin if(type == SF_LOCKR && size > 0 && n > 0 )
1624887Schin break;
1634887Schin }
1644887Schin
1654887Schin done: /* compute the buffer to be returned */
1664887Schin data = NIL(Void_t*);
1674887Schin if(size == 0 || n == 0)
1684887Schin { if(n > 0) /* got data */
1694887Schin data = (Void_t*)f->next;
1704887Schin else if(type == SF_LOCKR && size == 0 && (rsrv = _sfrsrv(f,0)) )
1714887Schin data = (Void_t*)rsrv->data;
1724887Schin }
1734887Schin else if(n >= sz) /* got data */
1744887Schin data = (Void_t*)f->next;
1754887Schin else if(f->flags&SF_STRING) /* try extending string buffer */
1764887Schin { if((f->mode&SF_WRITE) && (f->flags&SF_MALLOC) )
1774887Schin { (void)SFWR(f,f->next,sz,f->disc);
1784887Schin if((n = f->endb - f->next) >= sz )
1794887Schin data = (Void_t*)f->next;
1804887Schin }
1814887Schin }
1824887Schin else if(f->mode&SF_WRITE) /* allocate side buffer */
1834887Schin { if(type == SF_LOCKR && (rsrv = _sfrsrv(f, sz)) )
1844887Schin data = (Void_t*)rsrv->data;
1854887Schin }
1864887Schin else if(type != SF_LOCKR && sz > f->size && (rsrv = _sfrsrv(f,sz)) )
1874887Schin { if((n = SFREAD(f,(Void_t*)rsrv->data,sz)) >= sz) /* read side buffer */
1884887Schin data = (Void_t*)rsrv->data;
1894887Schin else rsrv->slen = -n;
1904887Schin }
1914887Schin
1924887Schin SFOPEN(f,0);
1934887Schin
1944887Schin if(data)
1954887Schin { if(type == SF_LOCKR)
1964887Schin { f->mode |= SF_PEEK;
1974887Schin if((f->mode & SF_READ) && size == 0 && data != f->next)
1984887Schin f->mode |= SF_GETR; /* so sfread() will unlock */
1994887Schin f->endr = f->endw = f->data;
2004887Schin }
2014887Schin else
2024887Schin { if(data == (Void_t*)f->next)
2034887Schin f->next += (size >= 0 ? size : n);
2044887Schin }
2054887Schin }
2064887Schin
2074887Schin _Sfi = f->val = n; /* return true buffer size */
2084887Schin
2094887Schin SFMTXRETURN(f, data);
2104887Schin }
211