source: trunk/libs/newlib/src/newlib/libc/stdio/fseeko.c @ 567

Last change on this file since 567 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 9.2 KB
Line 
1/*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
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.
16 */
17
18/*
19FUNCTION
20<<fseek>>, <<fseeko>>---set file position
21
22INDEX
23        fseek
24INDEX
25        fseeko
26INDEX
27        _fseek_r
28INDEX
29        _fseeko_r
30
31SYNOPSIS
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]>)
39
40DESCRIPTION
41Objects of type <<FILE>> can have a ``position'' that records how much
42of the file your program has already read.  Many of the <<stdio>> functions
43depend on this position, and many change it as a side effect.
44
45You 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
47of three ways selected by the value of <[whence]> (defined as macros
48in `<<stdio.h>>'):
49
50<<SEEK_SET>>---<[offset]> is the absolute file position (an offset
51from the beginning of the file) desired.  <[offset]> must be positive.
52
53<<SEEK_CUR>>---<[offset]> is relative to the current file position.
54<[offset]> can meaningfully be either positive or negative.
55
56<<SEEK_END>>---<[offset]> is relative to the current end of file.
57<[offset]> can meaningfully be either positive (to increase the size
58of the file) or negative.
59
60See <<ftell>>/<<ftello>> to determine the current file position.
61
62RETURNS
63<<fseek>>/<<fseeko>> return <<0>> when successful.  On failure, the
64result is <<EOF>>.  The reason for failure is indicated in <<errno>>:
65either <<ESPIPE>> (the stream identified by <[fp]> doesn't support
66repositioning) or <<EINVAL>> (invalid file position).
67
68PORTABILITY
69ANSI C requires <<fseek>>.
70
71<<fseeko>> is defined by the Single Unix specification.
72
73Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
74<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
75*/
76
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"
87
88#define POS_ERR (-(_fpos_t)1)
89
90/*
91 * Seek the given file to the given offset.
92 * `Whence' must be one of the three SEEK_* macros.
93 */
94
95int
96_fseeko_r (struct _reent *ptr,
97       register FILE *fp,
98       _off_t offset,
99       int whence)
100{
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;
111
112  /* Make sure stdio is set up.  */
113
114  CHECK_INIT (ptr, fp);
115
116  _newlib_flockfile_start (fp);
117
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.  */
120
121  if (fp->_flags & __SAPP && fp->_flags & __SWR)
122    {
123      /* So flush the buffer and seek to the end.  */
124      _fflush_r (ptr, fp);
125    }
126
127  /* Have to be able to seek.  */
128
129  if ((seekfn = fp->_seek) == NULL)
130    {
131      ptr->_errno = ESPIPE;     /* ??? */
132      _newlib_flockfile_exit (fp);
133      return EOF;
134    }
135
136  /*
137   * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
138   * After this, whence is either SEEK_SET or SEEK_END.
139   */
140
141  switch (whence)
142    {
143    case SEEK_CUR:
144      /*
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).
148       */
149      _fflush_r (ptr, fp);   /* may adjust seek offset on append stream */
150      if (fp->_flags & __SOFF)
151        curoff = fp->_offset;
152      else
153        {
154          curoff = seekfn (ptr, fp->_cookie, (_fpos_t) 0, SEEK_CUR);
155          if (curoff == -1L)
156            {
157              _newlib_flockfile_exit (fp);
158              return EOF;
159            }
160        }
161      if (fp->_flags & __SRD)
162        {
163          curoff -= fp->_r;
164          if (HASUB (fp))
165            curoff -= fp->_ur;
166        }
167      else if (fp->_flags & __SWR && fp->_p != NULL)
168        curoff += fp->_p - fp->_bf._base;
169
170      offset += curoff;
171      whence = SEEK_SET;
172      havepos = 1;
173      break;
174
175    case SEEK_SET:
176    case SEEK_END:
177      havepos = 0;
178      break;
179
180    default:
181      ptr->_errno = EINVAL;
182      _newlib_flockfile_exit (fp);
183      return (EOF);
184    }
185
186  /*
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.
193   */
194
195  if (fp->_bf._base == NULL)
196    __smakebuf_r (ptr, fp);
197
198#ifdef _FSEEK_OPTIMIZATION
199  if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
200    goto dumb;
201  if ((fp->_flags & __SOPT) == 0)
202    {
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)
211        {
212          fp->_flags |= __SNPT;
213          goto dumb;
214        }
215#ifdef  HAVE_BLKSIZE
216      fp->_blksize = st.st_blksize;
217#else
218      fp->_blksize = 1024;
219#endif
220      fp->_flags |= __SOPT;
221    }
222
223  /*
224   * We are reading; we can try to optimise.
225   * Figure out where we are going and where we are now.
226   */
227
228  if (whence == SEEK_SET)
229    target = offset;
230  else
231    {
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;
239    }
240
241  if (!havepos)
242    {
243      if (fp->_flags & __SOFF)
244        curoff = fp->_offset;
245      else
246        {
247          curoff = seekfn (ptr, fp->_cookie, 0L, SEEK_CUR);
248          if (curoff == POS_ERR)
249            goto dumb;
250        }
251      curoff -= fp->_r;
252      if (HASUB (fp))
253        curoff -= fp->_ur;
254    }
255
256  /*
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.
261   */
262
263  if (HASUB (fp))
264    {
265      curoff += fp->_r;       /* kill off ungetc */
266      n = fp->_up - fp->_bf._base;
267      curoff -= n;
268      n += fp->_ur;
269    }
270  else
271    {
272      n = fp->_p - fp->_bf._base;
273      curoff -= n;
274      n += fp->_r;
275    }
276
277  /*
278   * If the target offset is within the current buffer,
279   * simply adjust the pointers, clear EOF, undo ungetc(),
280   * and return.
281   */
282
283  if (target >= curoff && target < curoff + n)
284    {
285      register int o = target - curoff;
286
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;
295    }
296
297  /*
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.
304   */
305
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)
316    {
317      if (__srefill_r (ptr, fp) || fp->_r < n)
318        goto dumb;
319      fp->_p += n;
320      fp->_r -= n;
321    }
322  memset (&fp->_mbstate, 0, sizeof (_mbstate_t));
323  _newlib_flockfile_exit (fp);
324  return 0;
325
326  /*
327   * We get here if we cannot optimise the seek ... just
328   * do it.  Allow the seek function to change fp->_bf._base.
329   */
330#endif
331
332dumb:
333  if (_fflush_r (ptr, fp)
334      || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR)
335    {
336      _newlib_flockfile_exit (fp);
337      return EOF;
338    }
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;
356}
357
358#ifndef _REENT_ONLY
359
360int
361fseeko (register FILE *fp,
362       _off_t offset,
363       int whence)
364{
365  return _fseeko_r (_REENT, fp, offset, whence);
366}
367
368#endif /* !_REENT_ONLY */
Note: See TracBrowser for help on using the repository browser.