Update contrib.
3 * Portions Copyright (c) 1990-2004 Nokia Corporation and/or its subsidiary(-ies).
8 * Copyright (c) 1990 The Regents of the University of California.
11 * Redistribution and use in source and binary forms are permitted
12 * provided that the above copyright notice and this paragraph are
13 * duplicated in all such forms and that any documentation,
14 * advertising materials, and other materials related to such
15 * distribution and use acknowledge that the software was developed
16 * by the University of California, Berkeley. The name of the
17 * University may not be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 <<fseek>>---set file position
33 int fseek(FILE *<[fp]>, long <[offset]>, int <[whence]>)
37 int fseek(<[fp]>, <[offset]>, <[whence]>)
43 Objects of type <<FILE>> can have a ``position'' that records how much
44 of the file your program has already read. Many of the <<stdio>> functions
45 depend on this position, and many change it as a side effect.
47 You can use <<fseek>> to set the position for the file identified by
48 <[fp]>. The value of <[offset]> determines the new position, in one
49 of three ways selected by the value of <[whence]> (defined as macros
52 <<SEEK_SET>>---<[offset]> is the absolute file position (an offset
53 from the beginning of the file) desired. <[offset]> must be positive.
55 <<SEEK_CUR>>---<[offset]> is relative to the current file position.
56 <[offset]> can meaningfully be either positive or negative.
58 <<SEEK_END>>---<[offset]> is relative to the current end of file.
59 <[offset]> can meaningfully be either positive (to increase the size
60 of the file) or negative.
62 See <<ftell>> to determine the current file position.
65 <<fseek>> returns <<0>> when successful. If <<fseek>> fails, the
66 result is <<EOF>>. The reason for failure is indicated in <<errno>>:
67 either <<ESPIPE>> (the stream identified by <[fp]> doesn't support
68 repositioning) or <<EINVAL>> (invalid file position).
71 ANSI C requires <<fseek>>.
73 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
74 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
85 #define POS_ERR (-(fpos_t)1)
88 * Seek the given file to the given offset.
89 * `Whence' must be one of the three SEEK_* macros.
93 Reposition stream's position indicator.
94 @return If successful the function returns 0. Otherwise it returns nonzero.
95 @param fp Pointer to an open file.
96 @param offset Number of bytes from origin.
97 @param whence Initial position from where offset is applied.
100 fseek (register FILE *fp,long offset,int whence)
103 fpos_t (*seekfn)(void *, fpos_t, int);
104 fpos_t target, curoff = -1;
109 /* Make sure stdio is set up. */
114 /* If we've been doing some writing, and we're in append mode
115 then we don't really know where the filepos is. */
117 if (fp->_flags & __SAPP && fp->_flags & __SWR)
119 /* So flush the buffer and seek to the end. */
123 /* Have to be able to seek. */
125 if ((seekfn = fp->_seek) == NULL)
127 ptr->_errno = ESPIPE; /* ??? */
132 * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
133 * After this, whence is either SEEK_SET or SEEK_END.
140 * In order to seek relative to the current stream offset,
141 * we have to first find the current stream offset a la
142 * ftell (see ftell for details).
144 if (fp->_flags & __SOFF)
145 curoff = fp->_offset;
148 curoff = (*seekfn) (fp->_cookie, (fpos_t) 0, SEEK_CUR);
152 if (fp->_flags & __SRD)
158 else if (fp->_flags & __SWR && fp->_p != NULL)
159 curoff += fp->_p - fp->_bf._base;
172 ptr->_errno = EINVAL;
177 * Can only optimise if:
178 * reading (and not reading-and-writing);
179 * not unbuffered; and
180 * this is a `regular' Unix file (and hence seekfn==__sseek).
181 * We must check __NBF first, because it is possible to have __NBF
182 * and __SOPT both set.
185 if (fp->_bf._base == NULL)
187 if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
189 if ((fp->_flags & __SOPT) == 0)
191 if (seekfn != __sseek
193 || _fstat_r (ptr, fp->_file, &st)
194 || (st.st_mode & S_IFMT) != S_IFREG)
196 fp->_flags |= __SNPT;
200 fp->_blksize = st.st_blksize;
204 fp->_flags |= __SOPT;
208 * We are reading; we can try to optimise.
209 * Figure out where we are going and where we are now.
212 if (whence == SEEK_SET)
216 if (_fstat_r (ptr, fp->_file, &st))
218 target = st.st_size + offset;
223 if (fp->_flags & __SOFF)
224 curoff = fp->_offset;
227 curoff = (*seekfn) (fp->_cookie, 0L, SEEK_CUR);
228 if (curoff == POS_ERR)
237 * Compute the number of bytes in the input buffer (pretending
238 * that any ungetc() input has been discarded). Adjust current
239 * offset backwards by this count so that it represents the
240 * file offset for the first byte in the current input buffer.
245 n = fp->_up - fp->_bf._base;
251 n = fp->_p - fp->_bf._base;
257 * If the target offset is within the current buffer,
258 * simply adjust the pointers, clear EOF, undo ungetc(),
259 * and return. (If the buffer was modified, we have to
260 * skip this; see fgetline.c.)
263 if ((fp->_flags & __SMOD) == 0 &&
264 target >= curoff && target < (fpos_t)(curoff + n))
266 register int o = target - curoff;
268 fp->_p = fp->_bf._base + o;
272 fp->_flags &= ~__SEOF;
277 * The place we want to get to is not within the current buffer,
278 * but we can still be kind to the kernel copyout mechanism.
279 * By aligning the file offset to a block boundary, we can let
280 * the kernel use the VM hardware to map pages instead of
281 * copying bytes laboriously. Using a block boundary also
282 * ensures that we only read one block, rather than two.
285 curoff = target & ~(fp->_blksize - 1);
286 if ((*seekfn) (fp->_cookie, curoff, SEEK_SET) == POS_ERR)
291 fp->_flags &= ~__SEOF;
295 if (__srefill (fp) || fp->_r < (fpos_t)n)
303 * We get here if we cannot optimise the seek ... just
304 * do it. Allow the seek function to change fp->_bf._base.
308 if (fflush (fp) || (*seekfn) (fp->_cookie, offset, whence) == POS_ERR)
310 /* success: clear EOF indicator and discard ungetc() data */
313 fp->_p = fp->_bf._base;
315 /* fp->_w = 0; *//* unnecessary (I think...) */
316 fp->_flags &= ~__SEOF;