OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [newlib/] [newlib/] [libc/] [stdio/] [fseek.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 39 lampret
/*
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
/*
19
FUNCTION
20
<<fseek>>---set file position
21
 
22
INDEX
23
        fseek
24
 
25
ANSI_SYNOPSIS
26
        #include <stdio.h>
27
        int fseek(FILE *<[fp]>, long <[offset]>, int <[whence]>)
28
 
29
TRAD_SYNOPSIS
30
        #include <stdio.h>
31
        int fseek(<[fp]>, <[offset]>, <[whence]>)
32
        FILE *<[fp]>;
33
        long <[offset]>;
34
        int <[whence]>;
35
 
36
DESCRIPTION
37
Objects of type <<FILE>> can have a ``position'' that records how much
38
of the file your program has already read.  Many of the <<stdio>> functions
39
depend on this position, and many change it as a side effect.
40
 
41
You can use <<fseek>> to set the position for the file identified by
42
<[fp]>.  The value of <[offset]> determines the new position, in one
43
of three ways selected by the value of <[whence]> (defined as macros
44
in `<<stdio.h>>'):
45
 
46
<<SEEK_SET>>---<[offset]> is the absolute file position (an offset
47
from the beginning of the file) desired.  <[offset]> must be positive.
48
 
49
<<SEEK_CUR>>---<[offset]> is relative to the current file position.
50
<[offset]> can meaningfully be either positive or negative.
51
 
52
<<SEEK_END>>---<[offset]> is relative to the current end of file.
53
<[offset]> can meaningfully be either positive (to increase the size
54
of the file) or negative.
55
 
56
See <<ftell>> to determine the current file position.
57
 
58
RETURNS
59
<<fseek>> returns <<0>> when successful.  If <<fseek>> fails, the
60
result is <<EOF>>.  The reason for failure is indicated in <<errno>>:
61
either <<ESPIPE>> (the stream identified by <[fp]> doesn't support
62
repositioning) or <<EINVAL>> (invalid file position).
63
 
64
PORTABILITY
65
ANSI C requires <<fseek>>.
66
 
67
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
68
<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
69
*/
70
 
71
#include <stdio.h>
72
#include <time.h>
73
#include <fcntl.h>
74
#include <stdlib.h>
75
#include <errno.h>
76
#include <sys/stat.h>
77
#include "local.h"
78
 
79
#define POS_ERR (-(fpos_t)1)
80
 
81
/*
82
 * Seek the given file to the given offset.
83
 * `Whence' must be one of the three SEEK_* macros.
84
 */
85
 
86
int
87
fseek (fp, offset, whence)
88
     register FILE *fp;
89
     long offset;
90
     int whence;
91
{
92
  struct _reent *ptr;
93
  fpos_t _EXFUN ((*seekfn), (void *, fpos_t, int));
94
  fpos_t target, curoff;
95
  size_t n;
96
  struct stat st;
97
  int havepos;
98
 
99
  /* Make sure stdio is set up.  */
100
 
101
  CHECK_INIT (fp);
102
  ptr = fp->_data;
103
 
104
  /* If we've been doing some writing, and we're in append mode
105
     then we don't really know where the filepos is.  */
106
 
107
  if (fp->_flags & __SAPP && fp->_flags & __SWR)
108
    {
109
      /* So flush the buffer and seek to the end.  */
110
      fflush (fp);
111
    }
112
 
113
  /* Have to be able to seek.  */
114
 
115
  if ((seekfn = fp->_seek) == NULL)
116
    {
117
      ptr->_errno = ESPIPE;     /* ??? */
118
      return EOF;
119
    }
120
 
121
  /*
122
   * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
123
   * After this, whence is either SEEK_SET or SEEK_END.
124
   */
125
 
126
  switch (whence)
127
    {
128
    case SEEK_CUR:
129
      /*
130
       * In order to seek relative to the current stream offset,
131
       * we have to first find the current stream offset a la
132
       * ftell (see ftell for details).
133
       */
134
      fflush(fp);   /* may adjust seek offset on append stream */
135
      if (fp->_flags & __SOFF)
136
        curoff = fp->_offset;
137
      else
138
        {
139
          curoff = (*seekfn) (fp->_cookie, (fpos_t) 0, SEEK_CUR);
140
          if (curoff == -1L)
141
            return EOF;
142
        }
143
      if (fp->_flags & __SRD)
144
        {
145
          curoff -= fp->_r;
146
          if (HASUB (fp))
147
            curoff -= fp->_ur;
148
        }
149
      else if (fp->_flags & __SWR && fp->_p != NULL)
150
        curoff += fp->_p - fp->_bf._base;
151
 
152
      offset += curoff;
153
      whence = SEEK_SET;
154
      havepos = 1;
155
      break;
156
 
157
    case SEEK_SET:
158
    case SEEK_END:
159
      havepos = 0;
160
      break;
161
 
162
    default:
163
      ptr->_errno = EINVAL;
164
      return (EOF);
165
    }
166
 
167
  /*
168
   * Can only optimise if:
169
   *    reading (and not reading-and-writing);
170
   *    not unbuffered; and
171
   *    this is a `regular' Unix file (and hence seekfn==__sseek).
172
   * We must check __NBF first, because it is possible to have __NBF
173
   * and __SOPT both set.
174
   */
175
 
176
  if (fp->_bf._base == NULL)
177
    __smakebuf (fp);
178
  if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
179
    goto dumb;
180
  if ((fp->_flags & __SOPT) == 0)
181
    {
182
      if (seekfn != __sseek
183
          || fp->_file < 0
184
          || _fstat_r (ptr, fp->_file, &st)
185
          || (st.st_mode & S_IFMT) != S_IFREG)
186
        {
187
          fp->_flags |= __SNPT;
188
          goto dumb;
189
        }
190
#ifdef  HAVE_BLKSIZE
191
      fp->_blksize = st.st_blksize;
192
#else
193
      fp->_blksize = 1024;
194
#endif
195
      fp->_flags |= __SOPT;
196
    }
197
 
198
  /*
199
   * We are reading; we can try to optimise.
200
   * Figure out where we are going and where we are now.
201
   */
202
 
203
  if (whence == SEEK_SET)
204
    target = offset;
205
  else
206
    {
207
      if (_fstat_r (ptr, fp->_file, &st))
208
        goto dumb;
209
      target = st.st_size + offset;
210
    }
211
 
212
  if (!havepos)
213
    {
214
      if (fp->_flags & __SOFF)
215
        curoff = fp->_offset;
216
      else
217
        {
218
          curoff = (*seekfn) (fp->_cookie, 0L, SEEK_CUR);
219
          if (curoff == POS_ERR)
220
            goto dumb;
221
        }
222
      curoff -= fp->_r;
223
      if (HASUB (fp))
224
        curoff -= fp->_ur;
225
    }
226
 
227
  /*
228
   * Compute the number of bytes in the input buffer (pretending
229
   * that any ungetc() input has been discarded).  Adjust current
230
   * offset backwards by this count so that it represents the
231
   * file offset for the first byte in the current input buffer.
232
   */
233
 
234
  if (HASUB (fp))
235
    {
236
      curoff += fp->_r;       /* kill off ungetc */
237
      n = fp->_up - fp->_bf._base;
238
      curoff -= n;
239
      n += fp->_ur;
240
    }
241
  else
242
    {
243
      n = fp->_p - fp->_bf._base;
244
      curoff -= n;
245
      n += fp->_r;
246
    }
247
 
248
  /*
249
   * If the target offset is within the current buffer,
250
   * simply adjust the pointers, clear EOF, undo ungetc(),
251
   * and return.  (If the buffer was modified, we have to
252
   * skip this; see fgetline.c.)
253
   */
254
 
255
  if ((fp->_flags & __SMOD) == 0 &&
256
      target >= curoff && target < curoff + n)
257
    {
258
      register int o = target - curoff;
259
 
260
      fp->_p = fp->_bf._base + o;
261
      fp->_r = n - o;
262
      if (HASUB (fp))
263
        FREEUB (fp);
264
      fp->_flags &= ~__SEOF;
265
      return 0;
266
    }
267
 
268
  /*
269
   * The place we want to get to is not within the current buffer,
270
   * but we can still be kind to the kernel copyout mechanism.
271
   * By aligning the file offset to a block boundary, we can let
272
   * the kernel use the VM hardware to map pages instead of
273
   * copying bytes laboriously.  Using a block boundary also
274
   * ensures that we only read one block, rather than two.
275
   */
276
 
277
  curoff = target & ~(fp->_blksize - 1);
278
  if ((*seekfn) (fp->_cookie, curoff, SEEK_SET) == POS_ERR)
279
    goto dumb;
280
  fp->_r = 0;
281
  if (HASUB (fp))
282
    FREEUB (fp);
283
  fp->_flags &= ~__SEOF;
284
  n = target - curoff;
285
  if (n)
286
    {
287
      if (__srefill (fp) || fp->_r < n)
288
        goto dumb;
289
      fp->_p += n;
290
      fp->_r -= n;
291
    }
292
  return 0;
293
 
294
  /*
295
   * We get here if we cannot optimise the seek ... just
296
   * do it.  Allow the seek function to change fp->_bf._base.
297
   */
298
 
299
dumb:
300
  if (fflush (fp) || (*seekfn) (fp->_cookie, offset, whence) == POS_ERR)
301
    return EOF;
302
  /* success: clear EOF indicator and discard ungetc() data */
303
  if (HASUB (fp))
304
    FREEUB (fp);
305
  fp->_p = fp->_bf._base;
306
  fp->_r = 0;
307
  /* fp->_w = 0; *//* unnecessary (I think...) */
308
  fp->_flags &= ~__SEOF;
309
  return 0;
310
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.