1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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