fixes for host gcc 4.6.1
[zpugcc/jano.git] / toolchain / gcc / newlib / libc / stdio / fseek.c
blob4747e21569488e06a16414e5c6a627d974da2679
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 * 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.
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 ANSI_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 TRAD_SYNOPSIS
41 #include <stdio.h>
42 int fseek(<[fp]>, <[offset]>, <[whence]>)
43 FILE *<[fp]>;
44 long <[offset]>;
45 int <[whence]>;
47 int fseeko(<[fp]>, <[offset]>, <[whence]>)
48 FILE *<[fp]>;
49 off_t <[offset]>;
50 int <[whence]>;
52 int _fseek_r(<[ptr]>, <[fp]>, <[offset]>, <[whence]>)
53 struct _reent *<[ptr]>;
54 FILE *<[fp]>;
55 long <[offset]>;
56 int <[whence]>;
58 int _fseeko_r(<[ptr]>, <[fp]>, <[offset]>, <[whence]>)
59 struct _reent *<[ptr]>;
60 FILE *<[fp]>;
61 off_t <[offset]>;
62 int <[whence]>;
64 DESCRIPTION
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
72 in `<<stdio.h>>'):
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.
86 RETURNS
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).
92 PORTABILITY
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>>.
101 #include <stdio.h>
102 #include <time.h>
103 #include <fcntl.h>
104 #include <stdlib.h>
105 #include <errno.h>
106 #include <sys/stat.h>
107 #include "local.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
120 long offset _AND
121 int whence)
123 _fpos_t _EXFUN ((*seekfn), (void *, _fpos_t, int));
124 _fpos_t target, curoff;
125 size_t n;
126 struct stat st;
127 int havepos;
129 _flockfile(fp);
131 /* Make sure stdio is set up. */
133 CHECK_INIT (fp);
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. */
141 fflush (fp);
144 /* Have to be able to seek. */
146 if ((seekfn = fp->_seek) == NULL)
148 ptr->_errno = ESPIPE; /* ??? */
149 _funlockfile(fp);
150 return EOF;
154 * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
155 * After this, whence is either SEEK_SET or SEEK_END.
158 switch (whence)
160 case SEEK_CUR:
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;
169 else
171 curoff = (*seekfn) (fp->_cookie, (_fpos_t) 0, SEEK_CUR);
172 if (curoff == -1L)
174 _funlockfile(fp);
175 return EOF;
178 if (fp->_flags & __SRD)
180 curoff -= fp->_r;
181 if (HASUB (fp))
182 curoff -= fp->_ur;
184 else if (fp->_flags & __SWR && fp->_p != NULL)
185 curoff += fp->_p - fp->_bf._base;
187 offset += curoff;
188 whence = SEEK_SET;
189 havepos = 1;
190 break;
192 case SEEK_SET:
193 case SEEK_END:
194 havepos = 0;
195 break;
197 default:
198 ptr->_errno = EINVAL;
199 _funlockfile(fp);
200 return (EOF);
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)
213 __smakebuf (fp);
214 if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
215 goto dumb;
216 if ((fp->_flags & __SOPT) == 0)
218 if (seekfn != __sseek
219 || fp->_file < 0
220 #ifdef __USE_INTERNAL_STAT64
221 || _fstat64_r (ptr, fp->_file, &st)
222 #else
223 || _fstat_r (ptr, fp->_file, &st)
224 #endif
225 || (st.st_mode & S_IFMT) != S_IFREG)
227 fp->_flags |= __SNPT;
228 goto dumb;
230 #ifdef HAVE_BLKSIZE
231 fp->_blksize = st.st_blksize;
232 #else
233 fp->_blksize = 1024;
234 #endif
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)
244 target = offset;
245 else
247 #ifdef __USE_INTERNAL_STAT64
248 if (_fstat64_r (ptr, fp->_file, &st))
249 #else
250 if (_fstat_r (ptr, fp->_file, &st))
251 #endif
252 goto dumb;
253 target = st.st_size + offset;
256 if (!havepos)
258 if (fp->_flags & __SOFF)
259 curoff = fp->_offset;
260 else
262 curoff = (*seekfn) (fp->_cookie, 0L, SEEK_CUR);
263 if (curoff == POS_ERR)
264 goto dumb;
266 curoff -= fp->_r;
267 if (HASUB (fp))
268 curoff -= fp->_ur;
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.
278 if (HASUB (fp))
280 curoff += fp->_r; /* kill off ungetc */
281 n = fp->_up - fp->_bf._base;
282 curoff -= n;
283 n += fp->_ur;
285 else
287 n = fp->_p - fp->_bf._base;
288 curoff -= n;
289 n += fp->_r;
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;
305 fp->_r = n - o;
306 if (HASUB (fp))
307 FREEUB (fp);
308 fp->_flags &= ~__SEOF;
309 _funlockfile(fp);
310 return 0;
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)
324 goto dumb;
325 fp->_r = 0;
326 fp->_p = fp->_bf._base;
327 if (HASUB (fp))
328 FREEUB (fp);
329 fp->_flags &= ~__SEOF;
330 n = target - curoff;
331 if (n)
333 if (__srefill (fp) || fp->_r < n)
334 goto dumb;
335 fp->_p += n;
336 fp->_r -= n;
338 _funlockfile(fp);
339 return 0;
342 * We get here if we cannot optimise the seek ... just
343 * do it. Allow the seek function to change fp->_bf._base.
346 dumb:
347 if (fflush (fp) || (*seekfn) (fp->_cookie, offset, whence) == POS_ERR)
349 _funlockfile(fp);
350 return EOF;
352 /* success: clear EOF indicator and discard ungetc() data */
353 if (HASUB (fp))
354 FREEUB (fp);
355 fp->_p = fp->_bf._base;
356 fp->_r = 0;
357 /* fp->_w = 0; *//* unnecessary (I think...) */
358 fp->_flags &= ~__SEOF;
359 _funlockfile(fp);
360 return 0;
363 #ifndef _REENT_ONLY
366 _DEFUN (fseek, (fp, offset, whence),
367 register FILE *fp _AND
368 long offset _AND
369 int whence)
371 return _fseek_r (_REENT, fp, offset, whence);
374 #endif /* !_REENT_ONLY */