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 /* Set the IO pointer to a specific location in the stream
26 ** Written by Kiem-Phong Vo.
30 static void newpos(Sfio_t
* f
, Sfoff_t p
)
32 static void newpos(f
, p
)
38 if((f
->bits
&SF_MMAP
) && f
->data
)
39 { SFMUNMAP(f
, f
->data
, f
->endb
-f
->data
);
40 f
->data
= NIL(uchar
*);
43 f
->next
= f
->endr
= f
->endw
= f
->data
;
44 f
->endb
= (f
->mode
&SF_WRITE
) ? f
->data
+f
->size
: f
->data
;
52 Sfoff_t
sfseek(Sfio_t
* f
, Sfoff_t p
, int type
)
54 Sfoff_t
sfseek(f
,p
,type
)
55 Sfio_t
* f
; /* seek to a new location in this stream */
56 Sfoff_t p
; /* place to seek to */
57 int type
; /* 0: from org, 1: from here, 2: from end */
61 int mode
, local
, hardseek
, mustsync
;
64 SFMTXENTER(f
, (Sfoff_t
)(-1));
68 hardseek
= (type
|f
->flags
)&(SF_SHARE
|SF_PUBLIC
);
70 if(hardseek
&& f
->mode
== (SF_READ
|SF_SYNCED
) )
75 /* set and initialize the stream to a definite mode */
76 if((int)SFMODE(f
,local
) != (mode
= f
->mode
&SF_RDWR
))
77 { int flags
= f
->flags
;
79 if(hardseek
&SF_PUBLIC
) /* seek ptr must follow file descriptor */
80 f
->flags
|= SF_SHARE
|SF_PUBLIC
;
81 mode
= _sfmode(f
,mode
,local
);
82 if(hardseek
&SF_PUBLIC
)
86 SFMTXRETURN(f
, (Sfoff_t
)(-1));
89 mustsync
= (type
&SF_SHARE
) && !(type
&SF_PUBLIC
) &&
90 (f
->mode
&SF_READ
) && !(f
->flags
&SF_STRING
);
93 if((type
&= (SEEK_SET
|SEEK_CUR
|SEEK_END
)) != SEEK_SET
&&
94 type
!= SEEK_CUR
&& type
!= SEEK_END
)
96 SFMTXRETURN(f
, (Sfoff_t
)(-1));
100 { /* let system call set errno */
101 (void)SFSK(f
,(Sfoff_t
)0,SEEK_CUR
,f
->disc
);
102 SFMTXRETURN(f
, (Sfoff_t
)(-1));
105 /* throw away ungetc data */
106 if(f
->disc
== _Sfudisc
)
107 (void)sfclose((*_Sfstack
)(f
,NIL(Sfio_t
*)));
109 /* lock the stream for internal manipulations */
112 /* clear error and eof bits */
113 f
->flags
&= ~(SF_EOF
|SF_ERROR
);
115 while(f
->flags
&SF_STRING
)
119 r
= p
+ (f
->next
- f
->data
);
120 else if(type
== SEEK_END
)
124 if(r
>= 0 && r
<= f
->size
)
129 memclear((char*)(f
->data
+f
->extent
),(int)(p
-f
->extent
));
133 /* check exception handler, note that this may pop stream */
134 if(SFSK(f
,r
,SEEK_SET
,f
->disc
) != r
)
138 else if(!(f
->flags
&SF_STRING
))
145 { /* see if we can avoid flushing buffer */
146 if(!hardseek
&& type
< SEEK_END
&& !(f
->flags
&SF_APPENDWR
) )
147 { s
= f
->here
+ (f
->next
- f
->data
);
148 r
= p
+ (type
== SEEK_SET
? 0 : s
);
155 if(f
->next
> f
->data
&& SFSYNC(f
) < 0)
161 if(type
== SEEK_END
|| (f
->mode
&SF_WRITE
) )
162 { if((hardseek
&SF_PUBLIC
) || type
== SEEK_END
)
163 p
= SFSK(f
, p
, type
, f
->disc
);
165 { r
= p
+ (type
== SEEK_CUR
? f
->here
: 0);
166 p
= (hardseek
|| r
!= f
->here
) ? SFSK(f
,r
,SEEK_SET
,f
->disc
) : r
;
174 /* if get here, must be a read stream */
175 s
= f
->here
- (f
->endb
- f
->next
);
176 r
= p
+ (type
== SEEK_CUR
? s
: 0);
177 if(r
<= f
->here
&& r
>= (f
->here
- (f
->endb
-f
->data
)) )
178 { if((hardseek
|| (type
== SEEK_CUR
&& p
== 0)) )
179 { if((s
= SFSK(f
, (Sfoff_t
)0, SEEK_CUR
, f
->disc
)) == f
->here
||
180 (s
>= 0 && !(hardseek
&SF_PUBLIC
) &&
181 (s
= SFSK(f
, f
->here
, SEEK_SET
, f
->disc
)) == f
->here
) )
194 f
->next
= f
->endb
- (f
->here
- r
);
200 /* desired position */
201 if((p
+= type
== SEEK_CUR
? s
: 0) < 0)
206 { /* if mmap is not great, stop mmaping if moving around too much */
208 if((f
->next
- f
->data
) < ((f
->endb
- f
->data
)/4) )
209 { SFSETBUF(f
,(Void_t
*)f
->tiny
,(size_t)SF_UNBOUND
);
210 hardseek
= 1; /* this forces a hard seek below */
214 { /* for mmap, f->here can be virtual except for hardseek */
222 if(f
->endb
> f
->next
)
223 { /* reduce wastage in future buffer fillings */
224 f
->iosz
= (f
->next
- f
->data
) + (f
->endb
- f
->next
)/2;
225 f
->iosz
= ((f
->iosz
+ f
->blksz
-1)/f
->blksz
)*f
->blksz
;
227 if(f
->iosz
>= f
->size
)
230 /* buffer is now considered empty */
231 f
->next
= f
->endr
= f
->endb
= f
->data
;
233 /* small backseeks often come in bunches, so seek back as far as possible */
234 if(p
< f
->lpos
&& f
->size
> f
->blksz
&& (p
+ f
->blksz
) > s
)
235 { if((r
= s
- f
->size
) < 0)
238 /* try to align buffer to block boundary to enhance I/O speed */
239 else if(f
->blksz
> 0 && f
->size
>= 2*f
->blksz
)
240 r
= p
- (p
%f
->blksz
);
244 /* seeking around and wasting data, be conservative */
245 if(f
->iosz
> 0 && (p
> f
->lpos
|| p
< f
->lpos
-f
->size
) )
246 f
->bits
|= SF_JUSTSEEK
;
249 if((hardseek
|| r
!= f
->here
) && (f
->here
= SFSK(f
,r
,SEEK_SET
,f
->disc
)) != r
)
250 { if(r
< p
) /* now try to just get to p */
251 f
->here
= SFSK(f
,p
,SEEK_SET
,f
->disc
);
257 if(r
< p
) /* read to cover p */
258 { (void)SFRD(f
, f
->data
, f
->size
, f
->disc
);
259 if(p
<= f
->here
&& p
>= (f
->here
- (f
->endb
- f
->data
)) )
260 f
->next
= f
->endb
- (size_t)(f
->here
-p
);
261 else /* recover from read failure by just seeking to p */
262 { f
->next
= f
->endb
= f
->data
;
263 if((f
->here
= SFSK(f
,p
,SEEK_SET
,f
->disc
)) != p
)
269 if(f
->here
< 0) /* hasn't been the best of time */