2127c9757bffa428a0dfb0ad624eca3f9db1c1fb
[kopensolaris-gnu/glibc.git] / stdio / fseek.c
1 /* Copyright (C) 1991, 92, 93, 95, 96 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <errno.h>
21 #include <stdio.h>
22
23
24 /* Move the file position of STREAM to OFFSET
25    bytes from the beginning of the file if WHENCE
26    is SEEK_SET, the end of the file is it is SEEK_END,
27    or the current position if it is SEEK_CUR.  */
28 int
29 DEFUN(fseek, (stream, offset, whence),
30       register FILE *stream AND long int offset AND int whence)
31 {
32   long int o;
33
34   if (!__validfp (stream))
35     {
36       errno = EINVAL;
37       return EOF;
38     }
39
40   /* Write out any pending data.  */
41   if (stream->__mode.__write && __flshfp (stream, EOF) == EOF)
42     return EOF;
43
44   /* Make sure we know the current offset info.  */
45   stream->__offset = -1;
46   if (__stdio_check_offset (stream) == EOF)
47     return EOF;
48
49   /* We are moving the file position, so we are no longer at EOF.  */
50   stream->__eof = 0;
51
52   if (stream->__pushed_back)
53     {
54       /* Discard the character pushed back by ungetc.  */
55       stream->__bufp = stream->__pushback_bufp;
56       stream->__pushed_back = 0;
57     }
58
59   /* Check the WHENCE argument for validity, and process OFFSET
60      into an absolute position in O.  By the end of this switch,
61      either we have returned, or O contains an absolute position.  */
62   o = offset;
63   switch (whence)
64     {
65     default:
66       errno = EINVAL;
67       return EOF;
68
69     case SEEK_END:
70       /* We don't know where the end of the file is,
71          so seek to the position in the file the user asked
72          for, and then look where that is.  */
73       if (stream->__io_funcs.__seek == NULL)
74         {
75           errno = ESPIPE;
76           return EOF;
77         }
78       else
79         {
80           fpos_t pos = (fpos_t) o;
81           if ((*stream->__io_funcs.__seek)
82               (stream->__cookie, &pos, SEEK_END) < 0)
83             {
84               if (errno == ESPIPE)
85                 stream->__io_funcs.__seek = NULL;
86               return EOF;
87             }
88           stream->__offset = pos;
89           /* Make O be absolute, rather than
90              relative to the end of the file.  */
91           o = pos;
92         }
93
94       /* Fall through to try an absolute seek.  */
95
96     case SEEK_SET:
97       /* Make O be relative to the buffer.  */
98       o -= stream->__target;
99       /* Make O be relative to the current position in the buffer.  */
100       o -= stream->__bufp - stream->__buffer;
101
102       /* Fall through to see if we can do it by
103          moving the pointer around in the buffer.  */
104
105     case SEEK_CUR:
106       /* If the offset is small enough, we can just
107          move the pointer around in the buffer.  */
108
109 #if 0   /* Why did I think this would ever work???  */
110       if (stream->__put_limit > stream->__buffer)
111         {
112           /* We are writing.  */
113           if (stream->__bufp + o >= stream->__buffer &&
114               stream->__put_limit > stream->__bufp + o &&
115               stream->__get_limit > stream->__bufp + o)
116             {
117               /* We have read all the data we will change soon.
118                  We can just move the pointer around.  */
119               stream->__bufp += o;
120               return 0;
121             }
122           else
123             {
124               /* Flush the buffer.  */
125               if (__flshfp(stream, EOF) == EOF)
126                 return EOF;
127             }
128         } else
129 #endif
130       if (o < 0 ?
131           (-o <= stream->__bufp - stream->__buffer) :
132           (o <= stream->__get_limit - stream->__bufp))
133         {
134           stream->__bufp += o;
135           return 0;
136         }
137
138       /* Turn it into an absolute seek.  */
139       o += stream->__bufp - stream->__buffer;
140       o += stream->__target;
141       break;
142     }
143
144   if (o < 0)
145     {
146       /* Negative file position is meaningless.  */
147       errno = EINVAL;
148       return -1;
149     }
150
151   /* O is now an absolute position, the new target.  */
152   stream->__target = o;
153
154   /* Set bufp and both end pointers to the beginning of the buffer.
155      The next i/o will force a call to the input/output room function.  */
156   stream->__bufp
157     = stream->__get_limit = stream->__put_limit = stream->__buffer;
158
159   /* Make sure __flshfp doesn't think the put_limit is at the beginning
160      of the buffer because of line-buffering magic.  */
161   stream->__linebuf_active = 0;
162
163   /* If there is no seek function, seeks always fail.  */
164   if (stream->__io_funcs.__seek == NULL)
165     {
166       /* This is preemptive, since we don't actually do the seeking.
167          But it makes more sense for fseek to to fail with ESPIPE
168          than for the next reading or writing operation to fail
169          that way.  */
170       errno = ESPIPE;
171       return EOF;
172     }
173
174   /* Don't actually seek.  The next reading or writing operation
175      will force a call to the input or output room function,
176      which will move to the target file position before reading or writing.  */
177   return 0;
178 }