xref: /titanic_51/usr/src/lib/libast/common/sfio/sfreserve.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #include	"sfhdr.h"
23da2e3ebdSchin 
24da2e3ebdSchin /*	Reserve a segment of data or buffer.
25da2e3ebdSchin **
26da2e3ebdSchin **	Written by Kiem-Phong Vo.
27da2e3ebdSchin */
28da2e3ebdSchin 
29da2e3ebdSchin #if __STD_C
sfreserve(Sfio_t * f,ssize_t size,int type)307c2fbfb3SApril Chin Void_t* sfreserve(Sfio_t* f, ssize_t size, int type)
31da2e3ebdSchin #else
32da2e3ebdSchin Void_t* sfreserve(f,size,type)
337c2fbfb3SApril Chin Sfio_t*		f;	/* file to peek */
34da2e3ebdSchin ssize_t		size;	/* size of peek */
35da2e3ebdSchin int		type;	/* LOCKR: lock stream, LASTR: last record */
36da2e3ebdSchin #endif
37da2e3ebdSchin {
38da2e3ebdSchin 	reg ssize_t	n, now, sz, iosz;
39da2e3ebdSchin 	reg Sfrsrv_t*	rsrv;
40da2e3ebdSchin 	reg Void_t*	data;
41da2e3ebdSchin 	reg int		mode, local;
427c2fbfb3SApril Chin 	SFMTXDECL(f);
43da2e3ebdSchin 
447c2fbfb3SApril Chin 	SFMTXENTER(f,NIL(Void_t*));
45da2e3ebdSchin 
46da2e3ebdSchin 	sz = size < 0 ? -size : size;
47da2e3ebdSchin 
48da2e3ebdSchin 	/* see if we need to bias toward SF_WRITE instead of the default SF_READ */
49da2e3ebdSchin 	if(type < 0)
50da2e3ebdSchin 		mode = 0;
51da2e3ebdSchin 	else if((mode = type&SF_WRITE) )
52da2e3ebdSchin 		type &= ~SF_WRITE;
53da2e3ebdSchin 
54da2e3ebdSchin 	/* return the last record */
55da2e3ebdSchin 	if(type == SF_LASTR )
56da2e3ebdSchin 	{	if((n = f->endb - f->next) > 0 && n == f->val )
57da2e3ebdSchin 		{	data = (Void_t*)f->next;
58da2e3ebdSchin 			f->next += n;
59da2e3ebdSchin 		}
60da2e3ebdSchin 		else if((rsrv = f->rsrv) && (n = -rsrv->slen) > 0)
61da2e3ebdSchin 		{	rsrv->slen = 0;
62da2e3ebdSchin 			_Sfi = f->val = n;
63da2e3ebdSchin 			data = (Void_t*)rsrv->data;
64da2e3ebdSchin 		}
65da2e3ebdSchin 		else
66da2e3ebdSchin 		{	_Sfi = f->val = -1;
67da2e3ebdSchin 			data = NIL(Void_t*);
68da2e3ebdSchin 		}
69da2e3ebdSchin 
70da2e3ebdSchin 		SFMTXRETURN(f, data);
71da2e3ebdSchin 	}
72da2e3ebdSchin 
73da2e3ebdSchin 	if(type > 0)
74da2e3ebdSchin 	{	if(type == 1 ) /* upward compatibility mode */
75da2e3ebdSchin 			type = SF_LOCKR;
76da2e3ebdSchin 		else if(type != SF_LOCKR)
77da2e3ebdSchin 			SFMTXRETURN(f, NIL(Void_t*));
78da2e3ebdSchin 	}
79da2e3ebdSchin 
80da2e3ebdSchin 	if(size == 0 && (type < 0 || type == SF_LOCKR) )
81da2e3ebdSchin 	{	if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
82da2e3ebdSchin 			SFMTXRETURN(f, NIL(Void_t*));
83da2e3ebdSchin 
84da2e3ebdSchin 		SFLOCK(f,0);
85da2e3ebdSchin 		if((n = f->endb - f->next) < 0)
86da2e3ebdSchin 			n = 0;
87da2e3ebdSchin 
88da2e3ebdSchin 		goto done;
89da2e3ebdSchin 	}
90da2e3ebdSchin 
91da2e3ebdSchin 	/* iterate until get to a stream that has data or buffer space */
92da2e3ebdSchin 	for(local = 0;; local = SF_LOCAL)
93da2e3ebdSchin 	{	_Sfi = f->val = -1;
94da2e3ebdSchin 
95da2e3ebdSchin 		if(!mode && !(mode = f->flags&SF_READ) )
96da2e3ebdSchin 			mode = SF_WRITE;
97da2e3ebdSchin 		if((int)f->mode != mode && _sfmode(f,mode,local) < 0)
98da2e3ebdSchin 		{	SFOPEN(f,0);
99da2e3ebdSchin 			SFMTXRETURN(f, NIL(Void_t*));
100da2e3ebdSchin 		}
101da2e3ebdSchin 
102da2e3ebdSchin 		SFLOCK(f,local);
103da2e3ebdSchin 
104da2e3ebdSchin 		if((n = now = f->endb - f->next) < 0)
105da2e3ebdSchin 			n = 0;
106da2e3ebdSchin 		if(n > 0 && n >= sz) /* all done */
107da2e3ebdSchin 			break;
108da2e3ebdSchin 
1097c2fbfb3SApril Chin 		/* set amount to perform IO */
110da2e3ebdSchin 		if(size == 0 || (f->mode&SF_WRITE))
111da2e3ebdSchin 			iosz = -1;
1127c2fbfb3SApril Chin 		else if(size < 0 && n == 0 && f->push) /* maybe stack-pop */
11334f9b3eeSRoland Mainz 		{	if((iosz = f->push->endb - f->push->next) == 0)
11434f9b3eeSRoland Mainz 				iosz = f->push->size;
11534f9b3eeSRoland Mainz 			if(iosz < sz)
1167c2fbfb3SApril Chin 				iosz = sz; /* so only get what is asked for */
11734f9b3eeSRoland Mainz 		}
118da2e3ebdSchin 		else
1197c2fbfb3SApril Chin 		{	iosz = sz - n; /* get enough to fulfill requirement */
1207c2fbfb3SApril Chin 			if(size < 0 && iosz < (f->size - n) )
1217c2fbfb3SApril Chin 				iosz = f->size - n; /* get as much as possible */
1227c2fbfb3SApril Chin 			if(iosz <= 0) /* nothing to do */
123da2e3ebdSchin 				break;
124da2e3ebdSchin 		}
125da2e3ebdSchin 
126da2e3ebdSchin 		/* do a buffer refill or flush */
127da2e3ebdSchin 		now = n;
128da2e3ebdSchin 		if(f->mode&SF_WRITE)
129da2e3ebdSchin 			(void)SFFLSBUF(f, iosz);
130da2e3ebdSchin 		else if(type == SF_LOCKR && f->extent < 0 && (f->flags&SF_SHARE) )
131da2e3ebdSchin 		{	if(n == 0) /* peek-read only if there is no buffered data */
132da2e3ebdSchin 			{	f->mode |= SF_RV;
133da2e3ebdSchin 				(void)SFFILBUF(f, iosz );
134da2e3ebdSchin 			}
135da2e3ebdSchin 			if((n = f->endb - f->next) < sz)
136da2e3ebdSchin 			{	if(f->mode&SF_PKRD)
137da2e3ebdSchin 				{	f->endb = f->endr = f->next;
138da2e3ebdSchin 					f->mode &= ~SF_PKRD;
139da2e3ebdSchin 				}
140da2e3ebdSchin 				break;
141da2e3ebdSchin 			}
142da2e3ebdSchin 		}
1437c2fbfb3SApril Chin 		else
1447c2fbfb3SApril Chin 		{	/* sfreserve(f,0,0) == sfread(f, sfreserve(f,-1,SF_LOCKR), 0) */
1457c2fbfb3SApril Chin 			if(size == 0 && type == 0)
1467c2fbfb3SApril Chin 				f->mode |= SF_RV;
1477c2fbfb3SApril Chin 
1487c2fbfb3SApril Chin 			(void)SFFILBUF(f, iosz );
1497c2fbfb3SApril Chin 		}
150da2e3ebdSchin 
151da2e3ebdSchin 		if((n = f->endb - f->next) <= 0)
152da2e3ebdSchin 			n = 0;
153da2e3ebdSchin 
154da2e3ebdSchin 		if(n >= sz) /* got it */
155da2e3ebdSchin 			break;
156da2e3ebdSchin 
157da2e3ebdSchin 		if(n == now || sferror(f) || sfeof(f)) /* no progress */
158da2e3ebdSchin 			break;
159da2e3ebdSchin 
160da2e3ebdSchin 		/* request was only to assess data availability */
161da2e3ebdSchin 		if(type == SF_LOCKR && size > 0 && n > 0 )
162da2e3ebdSchin 			break;
163da2e3ebdSchin 	}
164da2e3ebdSchin 
165da2e3ebdSchin done:	/* compute the buffer to be returned */
166da2e3ebdSchin 	data = NIL(Void_t*);
167da2e3ebdSchin 	if(size == 0 || n == 0)
168da2e3ebdSchin 	{	if(n > 0) /* got data */
169da2e3ebdSchin 			data = (Void_t*)f->next;
170da2e3ebdSchin 		else if(type == SF_LOCKR && size == 0 && (rsrv = _sfrsrv(f,0)) )
171da2e3ebdSchin 			data = (Void_t*)rsrv->data;
172da2e3ebdSchin 	}
173da2e3ebdSchin 	else if(n >= sz) /* got data */
174da2e3ebdSchin 		data = (Void_t*)f->next;
175da2e3ebdSchin 	else if(f->flags&SF_STRING) /* try extending string buffer */
176da2e3ebdSchin 	{	if((f->mode&SF_WRITE) && (f->flags&SF_MALLOC) )
177da2e3ebdSchin 		{	(void)SFWR(f,f->next,sz,f->disc);
178da2e3ebdSchin 			if((n = f->endb - f->next) >= sz )
179da2e3ebdSchin 				data = (Void_t*)f->next;
180da2e3ebdSchin 		}
181da2e3ebdSchin 	}
182da2e3ebdSchin 	else if(f->mode&SF_WRITE) /* allocate side buffer */
183da2e3ebdSchin 	{	if(type == SF_LOCKR && (rsrv = _sfrsrv(f, sz)) )
184da2e3ebdSchin 			data = (Void_t*)rsrv->data;
185da2e3ebdSchin 	}
186da2e3ebdSchin 	else if(type != SF_LOCKR && sz > f->size && (rsrv = _sfrsrv(f,sz)) )
187da2e3ebdSchin 	{	if((n = SFREAD(f,(Void_t*)rsrv->data,sz)) >= sz) /* read side buffer */
188da2e3ebdSchin 			data = (Void_t*)rsrv->data;
189da2e3ebdSchin 		else	rsrv->slen = -n;
190da2e3ebdSchin 	}
191da2e3ebdSchin 
192da2e3ebdSchin 	SFOPEN(f,0);
193da2e3ebdSchin 
194da2e3ebdSchin 	if(data)
195da2e3ebdSchin 	{	if(type == SF_LOCKR)
196da2e3ebdSchin 		{	f->mode |= SF_PEEK;
197da2e3ebdSchin 			if((f->mode & SF_READ) && size == 0 && data != f->next)
198da2e3ebdSchin 				f->mode |= SF_GETR; /* so sfread() will unlock */
199da2e3ebdSchin 			f->endr = f->endw = f->data;
200da2e3ebdSchin 		}
201da2e3ebdSchin 		else
202da2e3ebdSchin 		{	if(data == (Void_t*)f->next)
203da2e3ebdSchin 				f->next += (size >= 0 ? size : n);
204da2e3ebdSchin 		}
205da2e3ebdSchin 	}
206da2e3ebdSchin 
207da2e3ebdSchin 	_Sfi = f->val = n; /* return true buffer size */
208da2e3ebdSchin 
209da2e3ebdSchin 	SFMTXRETURN(f, data);
210da2e3ebdSchin }
211