Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdio / fseeko.c
blob6fcc8ef0672c077951212e5b44cefcba906dc748
1 /*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
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 * and/or 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.
19 FUNCTION
20 <<fseek>>, <<fseeko>>---set file position
22 INDEX
23 fseek
24 INDEX
25 fseeko
26 INDEX
27 _fseek_r
28 INDEX
29 _fseeko_r
31 SYNOPSIS
32 #include <stdio.h>
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]>)
40 DESCRIPTION
41 Objects of type <<FILE>> can have a ``position'' that records how much
42 of the file your program has already read. Many of the <<stdio>> functions
43 depend on this position, and many change it as a side effect.
45 You can use <<fseek>>/<<fseeko>> to set the position for the file identified by
46 <[fp]>. The value of <[offset]> determines the new position, in one
47 of three ways selected by the value of <[whence]> (defined as macros
48 in `<<stdio.h>>'):
50 <<SEEK_SET>>---<[offset]> is the absolute file position (an offset
51 from the beginning of the file) desired. <[offset]> must be positive.
53 <<SEEK_CUR>>---<[offset]> is relative to the current file position.
54 <[offset]> can meaningfully be either positive or negative.
56 <<SEEK_END>>---<[offset]> is relative to the current end of file.
57 <[offset]> can meaningfully be either positive (to increase the size
58 of the file) or negative.
60 See <<ftell>>/<<ftello>> to determine the current file position.
62 RETURNS
63 <<fseek>>/<<fseeko>> return <<0>> when successful. On failure, the
64 result is <<EOF>>. The reason for failure is indicated in <<errno>>:
65 either <<ESPIPE>> (the stream identified by <[fp]> doesn't support
66 repositioning) or <<EINVAL>> (invalid file position).
68 PORTABILITY
69 ANSI C requires <<fseek>>.
71 <<fseeko>> is defined by the Single Unix specification.
73 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
74 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
77 #include <_ansi.h>
78 #include <reent.h>
79 #include <stdio.h>
80 #include <string.h>
81 #include <time.h>
82 #include <fcntl.h>
83 #include <stdlib.h>
84 #include <errno.h>
85 #include <sys/stat.h>
86 #include "local.h"
88 #define POS_ERR (-(_fpos_t)1)
91 * Seek the given file to the given offset.
92 * `Whence' must be one of the three SEEK_* macros.
95 int
96 _fseeko_r (struct _reent *ptr,
97 register FILE *fp,
98 _off_t offset,
99 int whence)
101 _fpos_t (*seekfn) (struct _reent *, void *, _fpos_t, int);
102 _fpos_t target;
103 _fpos_t curoff = 0;
104 size_t n;
105 #ifdef __USE_INTERNAL_STAT64
106 struct stat64 st;
107 #else
108 struct stat st;
109 #endif
110 int havepos;
112 /* Make sure stdio is set up. */
114 CHECK_INIT (ptr, fp);
116 _newlib_flockfile_start (fp);
118 /* If we've been doing some writing, and we're in append mode
119 then we don't really know where the filepos is. */
121 if (fp->_flags & __SAPP && fp->_flags & __SWR)
123 /* So flush the buffer and seek to the end. */
124 _fflush_r (ptr, fp);
127 /* Have to be able to seek. */
129 if ((seekfn = fp->_seek) == NULL)
131 _REENT_ERRNO(ptr) = ESPIPE; /* ??? */
132 _newlib_flockfile_exit (fp);
133 return EOF;
137 * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
138 * After this, whence is either SEEK_SET or SEEK_END.
141 switch (whence)
143 case SEEK_CUR:
145 * In order to seek relative to the current stream offset,
146 * we have to first find the current stream offset a la
147 * ftell (see ftell for details).
149 _fflush_r (ptr, fp); /* may adjust seek offset on append stream */
150 if (fp->_flags & __SOFF)
151 curoff = fp->_offset;
152 else
154 curoff = seekfn (ptr, fp->_cookie, (_fpos_t) 0, SEEK_CUR);
155 if (curoff == -1L)
157 _newlib_flockfile_exit (fp);
158 return EOF;
161 if (fp->_flags & __SRD)
163 curoff -= fp->_r;
164 if (HASUB (fp))
165 curoff -= fp->_ur;
167 else if (fp->_flags & __SWR && fp->_p != NULL)
168 curoff += fp->_p - fp->_bf._base;
170 offset += curoff;
171 whence = SEEK_SET;
172 havepos = 1;
173 break;
175 case SEEK_SET:
176 case SEEK_END:
177 havepos = 0;
178 break;
180 default:
181 _REENT_ERRNO(ptr) = EINVAL;
182 _newlib_flockfile_exit (fp);
183 return (EOF);
187 * Can only optimise if:
188 * reading (and not reading-and-writing);
189 * not unbuffered; and
190 * this is a `regular' Unix file (and hence seekfn==__sseek).
191 * We must check __NBF first, because it is possible to have __NBF
192 * and __SOPT both set.
195 if (fp->_bf._base == NULL)
196 __smakebuf_r (ptr, fp);
198 #ifdef _FSEEK_OPTIMIZATION
199 if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
200 goto dumb;
201 if ((fp->_flags & __SOPT) == 0)
203 if (seekfn != __sseek
204 || fp->_file < 0
205 #ifdef __USE_INTERNAL_STAT64
206 || _fstat64_r (ptr, fp->_file, &st)
207 #else
208 || _fstat_r (ptr, fp->_file, &st)
209 #endif
210 || (st.st_mode & S_IFMT) != S_IFREG)
212 fp->_flags |= __SNPT;
213 goto dumb;
215 #ifdef HAVE_BLKSIZE
216 fp->_blksize = st.st_blksize;
217 #else
218 fp->_blksize = 1024;
219 #endif
220 fp->_flags |= __SOPT;
224 * We are reading; we can try to optimise.
225 * Figure out where we are going and where we are now.
228 if (whence == SEEK_SET)
229 target = offset;
230 else
232 #ifdef __USE_INTERNAL_STAT64
233 if (_fstat64_r (ptr, fp->_file, &st))
234 #else
235 if (_fstat_r (ptr, fp->_file, &st))
236 #endif
237 goto dumb;
238 target = st.st_size + offset;
241 if (!havepos)
243 if (fp->_flags & __SOFF)
244 curoff = fp->_offset;
245 else
247 curoff = seekfn (ptr, fp->_cookie, 0L, SEEK_CUR);
248 if (curoff == POS_ERR)
249 goto dumb;
251 curoff -= fp->_r;
252 if (HASUB (fp))
253 curoff -= fp->_ur;
257 * Compute the number of bytes in the input buffer (pretending
258 * that any ungetc() input has been discarded). Adjust current
259 * offset backwards by this count so that it represents the
260 * file offset for the first byte in the current input buffer.
263 if (HASUB (fp))
265 curoff += fp->_r; /* kill off ungetc */
266 n = fp->_up - fp->_bf._base;
267 curoff -= n;
268 n += fp->_ur;
270 else
272 n = fp->_p - fp->_bf._base;
273 curoff -= n;
274 n += fp->_r;
278 * If the target offset is within the current buffer,
279 * simply adjust the pointers, clear EOF, undo ungetc(),
280 * and return.
283 if (target >= curoff && target < curoff + n)
285 register int o = target - curoff;
287 fp->_p = fp->_bf._base + o;
288 fp->_r = n - o;
289 if (HASUB (fp))
290 FREEUB (ptr, fp);
291 fp->_flags &= ~__SEOF;
292 memset (&fp->_mbstate, 0, sizeof (_mbstate_t));
293 _newlib_flockfile_exit (fp);
294 return 0;
298 * The place we want to get to is not within the current buffer,
299 * but we can still be kind to the kernel copyout mechanism.
300 * By aligning the file offset to a block boundary, we can let
301 * the kernel use the VM hardware to map pages instead of
302 * copying bytes laboriously. Using a block boundary also
303 * ensures that we only read one block, rather than two.
306 curoff = target & ~(fp->_blksize - 1);
307 if (seekfn (ptr, fp->_cookie, curoff, SEEK_SET) == POS_ERR)
308 goto dumb;
309 fp->_r = 0;
310 fp->_p = fp->_bf._base;
311 if (HASUB (fp))
312 FREEUB (ptr, fp);
313 fp->_flags &= ~__SEOF;
314 n = target - curoff;
315 if (n)
317 if (__srefill_r (ptr, fp) || fp->_r < n)
318 goto dumb;
319 fp->_p += n;
320 fp->_r -= n;
322 memset (&fp->_mbstate, 0, sizeof (_mbstate_t));
323 _newlib_flockfile_exit (fp);
324 return 0;
327 * We get here if we cannot optimise the seek ... just
328 * do it. Allow the seek function to change fp->_bf._base.
330 #endif
332 dumb:
333 if (_fflush_r (ptr, fp)
334 || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR)
336 _newlib_flockfile_exit (fp);
337 return EOF;
339 /* success: clear EOF indicator and discard ungetc() data */
340 if (HASUB (fp))
341 FREEUB (ptr, fp);
342 fp->_p = fp->_bf._base;
343 fp->_r = 0;
344 /* fp->_w = 0; *//* unnecessary (I think...) */
345 fp->_flags &= ~__SEOF;
346 /* Reset no-optimization flag after successful seek. The
347 no-optimization flag may be set in the case of a read
348 stream that is flushed which by POSIX/SUSv3 standards,
349 means that a corresponding seek must not optimize. The
350 optimization is then allowed if no subsequent flush
351 is performed. */
352 fp->_flags &= ~__SNPT;
353 memset (&fp->_mbstate, 0, sizeof (_mbstate_t));
354 _newlib_flockfile_end (fp);
355 return 0;
358 #ifndef _REENT_ONLY
361 fseeko (register FILE *fp,
362 _off_t offset,
363 int whence)
365 return _fseeko_r (_REENT, fp, offset, whence);
368 #endif /* !_REENT_ONLY */