1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
24 /* Reserve a segment of data or buffer.
26 ** Written by Kiem-Phong Vo.
30 Void_t
* sfreserve(Sfio_t
* f
, ssize_t size
, int type
)
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 */
38 reg ssize_t n
, now
, sz
, iosz
;
44 SFMTXENTER(f
,NIL(Void_t
*));
46 sz
= size
< 0 ? -size
: size
;
48 /* see if we need to bias toward SF_WRITE instead of the default SF_READ */
51 else if((mode
= type
&SF_WRITE
) )
54 /* return the last record */
56 { if((n
= f
->endb
- f
->next
) > 0 && n
== f
->val
)
57 { data
= (Void_t
*)f
->next
;
60 else if((rsrv
= f
->rsrv
) && (n
= -rsrv
->slen
) > 0)
63 data
= (Void_t
*)rsrv
->data
;
74 { if(type
== 1 ) /* upward compatibility mode */
76 else if(type
!= SF_LOCKR
)
77 SFMTXRETURN(f
, NIL(Void_t
*));
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
*));
85 if((n
= f
->endb
- f
->next
) < 0)
91 /* iterate until get to a stream that has data or buffer space */
92 for(local
= 0;; local
= SF_LOCAL
)
95 if(!mode
&& !(mode
= f
->flags
&SF_READ
) )
97 if((int)f
->mode
!= mode
&& _sfmode(f
,mode
,local
) < 0)
99 SFMTXRETURN(f
, NIL(Void_t
*));
104 if((n
= now
= f
->endb
- f
->next
) < 0)
106 if(n
> 0 && n
>= sz
) /* all done */
109 /* set amount to perform IO */
110 if(size
== 0 || (f
->mode
&SF_WRITE
))
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
;
116 iosz
= sz
; /* so only get what is asked for */
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 */
126 /* do a buffer refill or flush */
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 */
133 (void)SFFILBUF(f
, iosz
);
135 if((n
= f
->endb
- f
->next
) < sz
)
136 { if(f
->mode
&SF_PKRD
)
137 { f
->endb
= f
->endr
= f
->next
;
144 { /* sfreserve(f,0,0) == sfread(f, sfreserve(f,-1,SF_LOCKR), 0) */
145 if(size
== 0 && type
== 0)
148 (void)SFFILBUF(f
, iosz
);
151 if((n
= f
->endb
- f
->next
) <= 0)
154 if(n
>= sz
) /* got it */
157 if(n
== now
|| sferror(f
) || sfeof(f
)) /* no progress */
160 /* request was only to assess data availability */
161 if(type
== SF_LOCKR
&& size
> 0 && n
> 0 )
165 done
: /* compute the buffer to be returned */
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
;
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
;
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
;
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
;
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
;
202 { if(data
== (Void_t
*)f
->next
)
203 f
->next
+= (size
>= 0 ? size
: n
);
207 _Sfi
= f
->val
= n
; /* return true buffer size */
209 SFMTXRETURN(f
, data
);