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