2 * Copyright (c) 1990 The Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 <<fseek>>, <<fseeko>>---set file position
33 int fseek(FILE *<[fp]>, long <[offset]>, int <[whence]>)
34 int fseeko(FILE *<[fp]>, off_t <[offset]>, int <[whence]>)
35 int _fseek_r(struct _reent *<[ptr]>, FILE *<[fp]>,
36 long <[offset]>, int <[whence]>)
37 int _fseeko_r(struct _reent *<[ptr]>, FILE *<[fp]>,
38 off_t <[offset]>, int <[whence]>)
42 int fseek(<[fp]>, <[offset]>, <[whence]>)
47 int fseeko(<[fp]>, <[offset]>, <[whence]>)
52 int _fseek_r(<[ptr]>, <[fp]>, <[offset]>, <[whence]>)
53 struct _reent *<[ptr]>;
58 int _fseeko_r(<[ptr]>, <[fp]>, <[offset]>, <[whence]>)
59 struct _reent *<[ptr]>;
65 Objects of type <<FILE>> can have a ``position'' that records how much
66 of the file your program has already read. Many of the <<stdio>> functions
67 depend on this position, and many change it as a side effect.
69 You can use <<fseek>>/<<fseeko>> to set the position for the file identified by
70 <[fp]>. The value of <[offset]> determines the new position, in one
71 of three ways selected by the value of <[whence]> (defined as macros
74 <<SEEK_SET>>---<[offset]> is the absolute file position (an offset
75 from the beginning of the file) desired. <[offset]> must be positive.
77 <<SEEK_CUR>>---<[offset]> is relative to the current file position.
78 <[offset]> can meaningfully be either positive or negative.
80 <<SEEK_END>>---<[offset]> is relative to the current end of file.
81 <[offset]> can meaningfully be either positive (to increase the size
82 of the file) or negative.
84 See <<ftell>>/<<ftello>> to determine the current file position.
87 <<fseek>>/<<fseeko>> return <<0>> when successful. On failure, the
88 result is <<EOF>>. The reason for failure is indicated in <<errno>>:
89 either <<ESPIPE>> (the stream identified by <[fp]> doesn't support
90 repositioning) or <<EINVAL>> (invalid file position).
93 ANSI C requires <<fseek>>.
95 <<fseeko>> is defined by the Single Unix specification.
97 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
98 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
106 #include <sys/stat.h>
109 #define POS_ERR (-(_fpos_t)1)
112 * Seek the given file to the given offset.
113 * `Whence' must be one of the three SEEK_* macros.
117 _DEFUN (_fseek_r
, (ptr
, fp
, offset
, whence
),
118 struct _reent
*ptr _AND
119 register FILE *fp _AND
123 _fpos_t
_EXFUN ((*seekfn
), (void *, _fpos_t
, int));
124 _fpos_t target
, curoff
;
131 /* Make sure stdio is set up. */
135 /* If we've been doing some writing, and we're in append mode
136 then we don't really know where the filepos is. */
138 if (fp
->_flags
& __SAPP
&& fp
->_flags
& __SWR
)
140 /* So flush the buffer and seek to the end. */
144 /* Have to be able to seek. */
146 if ((seekfn
= fp
->_seek
) == NULL
)
148 ptr
->_errno
= ESPIPE
; /* ??? */
154 * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
155 * After this, whence is either SEEK_SET or SEEK_END.
162 * In order to seek relative to the current stream offset,
163 * we have to first find the current stream offset a la
164 * ftell (see ftell for details).
166 fflush(fp
); /* may adjust seek offset on append stream */
167 if (fp
->_flags
& __SOFF
)
168 curoff
= fp
->_offset
;
171 curoff
= (*seekfn
) (fp
->_cookie
, (_fpos_t
) 0, SEEK_CUR
);
178 if (fp
->_flags
& __SRD
)
184 else if (fp
->_flags
& __SWR
&& fp
->_p
!= NULL
)
185 curoff
+= fp
->_p
- fp
->_bf
._base
;
198 ptr
->_errno
= EINVAL
;
204 * Can only optimise if:
205 * reading (and not reading-and-writing);
206 * not unbuffered; and
207 * this is a `regular' Unix file (and hence seekfn==__sseek).
208 * We must check __NBF first, because it is possible to have __NBF
209 * and __SOPT both set.
212 if (fp
->_bf
._base
== NULL
)
214 if (fp
->_flags
& (__SWR
| __SRW
| __SNBF
| __SNPT
))
216 if ((fp
->_flags
& __SOPT
) == 0)
218 if (seekfn
!= __sseek
220 #ifdef __USE_INTERNAL_STAT64
221 || _fstat64_r (ptr
, fp
->_file
, &st
)
223 || _fstat_r (ptr
, fp
->_file
, &st
)
225 || (st
.st_mode
& S_IFMT
) != S_IFREG
)
227 fp
->_flags
|= __SNPT
;
231 fp
->_blksize
= st
.st_blksize
;
235 fp
->_flags
|= __SOPT
;
239 * We are reading; we can try to optimise.
240 * Figure out where we are going and where we are now.
243 if (whence
== SEEK_SET
)
247 #ifdef __USE_INTERNAL_STAT64
248 if (_fstat64_r (ptr
, fp
->_file
, &st
))
250 if (_fstat_r (ptr
, fp
->_file
, &st
))
253 target
= st
.st_size
+ offset
;
258 if (fp
->_flags
& __SOFF
)
259 curoff
= fp
->_offset
;
262 curoff
= (*seekfn
) (fp
->_cookie
, 0L, SEEK_CUR
);
263 if (curoff
== POS_ERR
)
272 * Compute the number of bytes in the input buffer (pretending
273 * that any ungetc() input has been discarded). Adjust current
274 * offset backwards by this count so that it represents the
275 * file offset for the first byte in the current input buffer.
280 curoff
+= fp
->_r
; /* kill off ungetc */
281 n
= fp
->_up
- fp
->_bf
._base
;
287 n
= fp
->_p
- fp
->_bf
._base
;
293 * If the target offset is within the current buffer,
294 * simply adjust the pointers, clear EOF, undo ungetc(),
295 * and return. (If the buffer was modified, we have to
296 * skip this; see fgetline.c.)
299 if ((fp
->_flags
& __SMOD
) == 0 &&
300 target
>= curoff
&& target
< curoff
+ n
)
302 register int o
= target
- curoff
;
304 fp
->_p
= fp
->_bf
._base
+ o
;
308 fp
->_flags
&= ~__SEOF
;
314 * The place we want to get to is not within the current buffer,
315 * but we can still be kind to the kernel copyout mechanism.
316 * By aligning the file offset to a block boundary, we can let
317 * the kernel use the VM hardware to map pages instead of
318 * copying bytes laboriously. Using a block boundary also
319 * ensures that we only read one block, rather than two.
322 curoff
= target
& ~(fp
->_blksize
- 1);
323 if ((*seekfn
) (fp
->_cookie
, curoff
, SEEK_SET
) == POS_ERR
)
326 fp
->_p
= fp
->_bf
._base
;
329 fp
->_flags
&= ~__SEOF
;
333 if (__srefill (fp
) || fp
->_r
< n
)
342 * We get here if we cannot optimise the seek ... just
343 * do it. Allow the seek function to change fp->_bf._base.
347 if (fflush (fp
) || (*seekfn
) (fp
->_cookie
, offset
, whence
) == POS_ERR
)
352 /* success: clear EOF indicator and discard ungetc() data */
355 fp
->_p
= fp
->_bf
._base
;
357 /* fp->_w = 0; *//* unnecessary (I think...) */
358 fp
->_flags
&= ~__SEOF
;
366 _DEFUN (fseek
, (fp
, offset
, whence
),
367 register FILE *fp _AND
371 return _fseek_r (_REENT
, fp
, offset
, whence
);
374 #endif /* !_REENT_ONLY */