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