]>
Commit | Line | Data |
---|---|---|
c84142e8 UD |
1 | /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 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 not, | |
16 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
17 | Boston, MA 02111-1307, USA. */ | |
28f540f4 | 18 | |
28f540f4 RM |
19 | #include <errno.h> |
20 | #include <stdio.h> | |
21 | #include <stdlib.h> | |
22 | #include <string.h> | |
23 | ||
24 | ||
25 | /* Make sure that FP has its functions set. */ | |
26 | void | |
ebe3b3eb | 27 | __stdio_check_funcs (register FILE *fp) |
28f540f4 RM |
28 | { |
29 | if (!fp->__seen) | |
30 | { | |
31 | /* Initialize the stream's info, including buffering info. | |
32 | This may give a buffer, change I/O functions, etc. | |
33 | If no buffer is set (and the stream is not made explicitly | |
34 | unbuffered), we allocate a buffer below, using the bufsize | |
35 | set by this function. */ | |
c4029823 | 36 | extern void __stdio_init_stream __P ((FILE *)); |
28f540f4 RM |
37 | fp->__room_funcs = __default_room_functions; |
38 | fp->__io_funcs = __default_io_functions; | |
39 | __stdio_init_stream (fp); | |
40 | fp->__seen = 1; | |
41 | } | |
42 | } | |
43 | ||
44 | ||
45 | /* Minimum size of a buffer we will allocate by default. | |
46 | If this much memory is not available, | |
47 | the stream in question will be made unbuffered instead. */ | |
48 | #define MIN_BUFSIZE 128 | |
49 | ||
50 | /* Figure out what kind of buffering (none, line, or full) | |
51 | and what buffer size to give FP. */ | |
52 | static void | |
ebe3b3eb | 53 | init_stream (register FILE *fp) |
28f540f4 RM |
54 | { |
55 | __stdio_check_funcs (fp); | |
56 | ||
57 | if (fp->__buffer == NULL && !fp->__userbuf) | |
58 | { | |
59 | int save; | |
60 | ||
61 | if (fp->__bufsize == 0) | |
62 | fp->__bufsize = BUFSIZ; | |
63 | ||
64 | /* Try to get however many bytes of buffering __stdio_pickbuf | |
65 | specified, but if that much memory isn't available, | |
66 | try half as much each time until it succeeds or the buffer | |
67 | size becomes too small to be useful. */ | |
68 | save = errno; | |
69 | while (fp->__bufsize >= MIN_BUFSIZE) | |
70 | { | |
c4029823 | 71 | fp->__buffer = (char *) malloc (fp->__bufsize); |
28f540f4 RM |
72 | if (fp->__buffer == NULL) |
73 | fp->__bufsize /= 2; | |
74 | else | |
75 | break; | |
76 | } | |
c4029823 | 77 | __set_errno (save); |
28f540f4 RM |
78 | |
79 | if (fp->__buffer == NULL) | |
80 | { | |
81 | /* We can't get space for the buffer, so make it unbuffered. */ | |
82 | fp->__userbuf = 1; | |
83 | fp->__bufsize = 0; | |
84 | } | |
85 | } | |
86 | ||
87 | if (fp->__bufp == NULL) | |
88 | { | |
89 | /* Set the buffer pointer to the beginning of the buffer. */ | |
90 | fp->__bufp = fp->__buffer; | |
91 | fp->__put_limit = fp->__get_limit = fp->__buffer; | |
92 | } | |
93 | } | |
94 | ||
95 | ||
96 | /* Determine the current file position of STREAM if it is unknown. */ | |
97 | int | |
c4029823 UD |
98 | __stdio_check_offset (stream) |
99 | FILE *stream; | |
28f540f4 RM |
100 | { |
101 | init_stream (stream); | |
102 | ||
103 | if (stream->__offset == (fpos_t) -1) | |
104 | { | |
105 | /* This stream's offset is unknown or unknowable. */ | |
106 | if (stream->__io_funcs.__seek == NULL) | |
107 | { | |
108 | /* Unknowable. */ | |
c4029823 | 109 | __set_errno (ESPIPE); |
28f540f4 RM |
110 | return EOF; |
111 | } | |
112 | else | |
113 | { | |
114 | /* Unknown. Find it out. */ | |
115 | fpos_t pos = (fpos_t) 0; | |
c4029823 UD |
116 | if ((*stream->__io_funcs.__seek) (stream->__cookie, |
117 | &pos, SEEK_CUR) < 0) | |
28f540f4 RM |
118 | { |
119 | if (errno == ESPIPE) | |
120 | /* Object is incapable of seeking. */ | |
121 | stream->__io_funcs.__seek = NULL; | |
122 | return EOF; | |
123 | } | |
124 | stream->__offset = pos; | |
125 | } | |
126 | } | |
127 | ||
128 | if (stream->__target == (fpos_t) -1) | |
129 | /* This stream was opened on an existing object with | |
130 | an unknown file position. The position is now known. | |
131 | Make this the target position. */ | |
132 | stream->__target = stream->__offset; | |
133 | ||
134 | return 0; | |
135 | } | |
136 | ||
137 | ||
138 | /* Move FP's file position to its target file position, | |
139 | seeking as necessary and updating its `offset' field. | |
140 | Sets ferror(FP) (and possibly errno) for errors. */ | |
141 | static void | |
ebe3b3eb | 142 | seek_to_target (FILE *fp) |
28f540f4 RM |
143 | { |
144 | int save = errno; | |
145 | if (__stdio_check_offset (fp) == EOF) | |
146 | { | |
147 | if (errno == ESPIPE) | |
c4029823 | 148 | __set_errno (save); |
28f540f4 RM |
149 | else |
150 | fp->__error = 1; | |
151 | } | |
152 | else if (fp->__target != fp->__offset) | |
153 | { | |
154 | /* We are not at the target file position. | |
155 | Seek to that position. */ | |
156 | if (fp->__io_funcs.__seek == NULL) | |
157 | { | |
158 | /* We can't seek! */ | |
c4029823 | 159 | __set_errno (ESPIPE); |
28f540f4 RM |
160 | fp->__error = 1; |
161 | } | |
162 | else | |
163 | { | |
164 | fpos_t pos = fp->__target; | |
c4029823 | 165 | if ((*fp->__io_funcs.__seek) (fp->__cookie, &pos, SEEK_SET) < 0) |
28f540f4 RM |
166 | /* Seek failed! */ |
167 | fp->__error = 1; | |
168 | else | |
169 | { | |
170 | fp->__offset = pos; | |
171 | if (pos != fp->__target) | |
7f77e07b RM |
172 | { |
173 | /* Seek didn't go to the right place! | |
174 | This should never happen. */ | |
175 | #ifdef EGRATUITOUS | |
176 | /* It happens in the Hurd when the io server doesn't | |
177 | obey the protocol for io_seek. */ | |
c4029823 | 178 | __set_errno (EGRATUITOUS); |
7f77e07b RM |
179 | #else |
180 | /* I don't think this can happen in Unix. */ | |
c4029823 | 181 | __set_errno (ESPIPE); /* ??? */ |
7f77e07b RM |
182 | #endif |
183 | fp->__error = 1; | |
184 | } | |
28f540f4 RM |
185 | } |
186 | } | |
187 | } | |
188 | } | |
189 | ||
190 | /* Flush the buffer for FP. | |
191 | If C is not EOF, it is also to be written. | |
192 | If the stream is line buffered and C is a newline, it is written | |
193 | to the output, otherwise it is put in the buffer after it has been | |
194 | flushed to avoid a system call for a single character. | |
195 | This is the default `output room' function. */ | |
196 | static void | |
ebe3b3eb | 197 | flushbuf (register FILE *fp, int c) |
28f540f4 RM |
198 | { |
199 | int flush_only = c == EOF; | |
200 | size_t buffer_written; | |
201 | size_t to_write; | |
202 | ||
203 | /* Set if target and get_limit have already been twiddled appropriately. */ | |
204 | int twiddled = 0; | |
205 | ||
206 | if (fp->__put_limit == fp->__buffer) | |
207 | { | |
208 | /* The stream needs to be primed for writing. */ | |
209 | ||
210 | size_t buffer_offset = 0; | |
211 | ||
8ef76445 RM |
212 | if (fp->__target == -1) |
213 | /* For an unseekable object, data recently read bears no relation | |
214 | to data we will write later. Discard the buffer. */ | |
215 | fp->__get_limit = fp->__buffer; | |
216 | else | |
217 | /* If the user has read some of the buffer, the target position | |
218 | is incremented for each character he has read. */ | |
219 | fp->__target += fp->__bufp - fp->__buffer; | |
28f540f4 RM |
220 | |
221 | if (fp->__mode.__read && fp->__room_funcs.__input != NULL && | |
222 | !fp->__mode.__append) | |
223 | { | |
224 | int save = errno; | |
c4029823 UD |
225 | const int aligned = (fp->__buffer == NULL || |
226 | __stdio_check_offset (fp) == EOF || | |
28f540f4 | 227 | fp->__target % fp->__bufsize == 0); |
c4029823 | 228 | __set_errno (save); |
28f540f4 RM |
229 | |
230 | if (!aligned) | |
231 | { | |
232 | /* Move to a block (buffer size) boundary and read in a block. | |
233 | Then the output will be written as a whole block, too. */ | |
c4029823 | 234 | const size_t o = fp->__target % fp->__bufsize; |
28f540f4 | 235 | fp->__target -= o; |
c4029823 | 236 | if ((*fp->__room_funcs.__input) (fp) == EOF && ferror (fp)) |
28f540f4 RM |
237 | return; |
238 | else | |
c4029823 | 239 | __clearerr (fp); |
28f540f4 RM |
240 | |
241 | if (fp->__get_limit - fp->__buffer < o) | |
242 | /* Oops. We didn't read enough (probably because we got EOF). | |
243 | Forget we even mentioned it. */ | |
244 | fp->__target += o; | |
245 | else | |
246 | /* Start bufp as far into the buffer as we were into | |
247 | this block before we read it. */ | |
248 | buffer_offset = o; | |
28f540f4 | 249 | |
8ef76445 RM |
250 | /* The target position is now set to where the beginning of the |
251 | buffer maps to; and the get_limit was set by the input-room | |
252 | function. */ | |
253 | twiddled = 1; | |
254 | } | |
28f540f4 RM |
255 | } |
256 | ||
257 | if (fp->__buffer != NULL) | |
258 | { | |
259 | /* Set up to write output into the buffer. */ | |
260 | fp->__put_limit = fp->__buffer + fp->__bufsize; | |
261 | fp->__bufp = fp->__buffer + buffer_offset; | |
262 | ||
263 | if (!flush_only) | |
264 | { | |
265 | /* Put C in the buffer to be written out. | |
266 | We only need to actually write it out now if | |
267 | it is a newline on a line-buffered stream. */ | |
268 | *fp->__bufp++ = (unsigned char) c; | |
269 | if (!fp->__linebuf || (unsigned char) c != '\n') | |
270 | { | |
271 | /* There is no need to flush C from the buffer right now. | |
272 | Record that nothing was written from the buffer, | |
273 | and go do clean-up at end. */ | |
274 | buffer_written = 0; | |
275 | goto end; | |
276 | } | |
277 | else | |
278 | /* We put C in the buffer, so don't write it again later. */ | |
279 | flush_only = 1; | |
280 | } | |
281 | } | |
282 | ||
f0bf9cb9 | 283 | if (fp->__bufp - fp->__buffer <= buffer_offset && flush_only) |
28f540f4 RM |
284 | { |
285 | /* There is nothing new in the buffer, only data that | |
286 | was read back aligned from the file. */ | |
287 | buffer_written = 0; | |
288 | goto end; | |
289 | } | |
290 | } | |
291 | ||
292 | /* If there is read data in the buffer past what was written, | |
293 | write all of that as well. Otherwise, just write what has been | |
294 | written into the buffer. */ | |
295 | buffer_written = fp->__bufp - fp->__buffer; | |
296 | to_write = (buffer_written == 0 ? 0 : | |
297 | fp->__get_limit > fp->__bufp ? | |
298 | fp->__get_limit - fp->__buffer : | |
299 | buffer_written); | |
300 | ||
301 | if (fp->__io_funcs.__write == NULL || (to_write == 0 && flush_only)) | |
302 | { | |
303 | /* There is no writing function or we're coming from an fflush | |
304 | call with nothing in the buffer, so just say the buffer's | |
305 | been flushed, increment the file offset, and return. */ | |
306 | fp->__bufp = fp->__buffer; | |
8ef76445 RM |
307 | if (fp->__offset != -1) |
308 | fp->__offset += to_write; | |
28f540f4 RM |
309 | goto end; |
310 | } | |
311 | ||
312 | if (to_write > 0) | |
313 | { | |
314 | int wrote; | |
315 | ||
316 | /* Go to the target file position. Don't bother if appending; | |
317 | the write will just ignore the file position anyway. */ | |
318 | if (!fp->__mode.__append) | |
319 | seek_to_target (fp); | |
320 | ||
321 | if (!ferror(fp)) | |
322 | { | |
323 | /* Write out the buffered data. */ | |
c4029823 UD |
324 | wrote = (*fp->__io_funcs.__write) (fp->__cookie, fp->__buffer, |
325 | to_write); | |
28f540f4 RM |
326 | if (wrote > 0) |
327 | { | |
328 | if (fp->__mode.__append) | |
329 | /* The write has written the data to the end of the file | |
330 | and updated the file position to after the data. Don't | |
331 | bother to find the current position; we can get it | |
332 | later if we need it. */ | |
333 | fp->__offset = fp->__target = -1; | |
8ef76445 | 334 | else if (fp->__offset != -1) |
28f540f4 RM |
335 | /* Record that we've moved forward in the file. */ |
336 | fp->__offset += wrote; | |
337 | } | |
338 | if (wrote < (int) to_write) | |
339 | /* The writing function should always write | |
340 | the whole buffer unless there is an error. */ | |
341 | fp->__error = 1; | |
342 | } | |
343 | } | |
344 | ||
345 | /* Reset the buffer pointer to the beginning of the buffer. */ | |
346 | fp->__bufp = fp->__buffer; | |
347 | ||
348 | /* If we're not just flushing, write the last character, C. */ | |
c4029823 | 349 | if (!flush_only && !ferror (fp)) |
28f540f4 RM |
350 | { |
351 | if (fp->__buffer == NULL || (fp->__linebuf && (unsigned char) c == '\n')) | |
352 | { | |
353 | /* Either we're unbuffered, or we're line-buffered and | |
354 | C is a newline, so really write it out immediately. */ | |
355 | char cc = (unsigned char) c; | |
356 | if ((*fp->__io_funcs.__write)(fp->__cookie, &cc, 1) < 1) | |
357 | fp->__error = 1; | |
8ef76445 | 358 | else if (fp->__offset != -1) |
28f540f4 RM |
359 | { |
360 | /* Record that we've moved forward in the file. */ | |
361 | ++fp->__offset; | |
362 | ++fp->__target; | |
363 | } | |
364 | } | |
365 | else | |
366 | /* Just put C in the buffer. */ | |
367 | *fp->__bufp++ = (unsigned char) c; | |
368 | } | |
369 | ||
370 | end: | |
371 | ||
372 | if (!twiddled) | |
373 | { | |
8ef76445 RM |
374 | if (fp->__target != -1) |
375 | /* The new target position moves up as | |
376 | much as the user wrote into the buffer. */ | |
377 | fp->__target += buffer_written; | |
28f540f4 RM |
378 | |
379 | /* Set the reading limit to the beginning of the buffer, | |
380 | so the next `getc' will call __fillbf. */ | |
381 | fp->__get_limit = fp->__buffer; | |
382 | } | |
383 | ||
c4029823 | 384 | if (feof (fp) || ferror (fp)) |
28f540f4 RM |
385 | fp->__bufp = fp->__put_limit; |
386 | } | |
387 | ||
388 | ||
389 | /* Fill the buffer for FP and return the first character read (or EOF). | |
390 | This is the default `input_room' function. */ | |
391 | static int | |
ebe3b3eb | 392 | fillbuf (register FILE *fp) |
28f540f4 RM |
393 | { |
394 | /* How far into the buffer we read we want to start bufp. */ | |
395 | size_t buffer_offset = 0; | |
396 | register char *buffer; | |
397 | register size_t to_read, nread = 0; | |
398 | /* This must be unsigned to avoid sign extension in return. */ | |
399 | unsigned char c; | |
400 | ||
401 | if (fp->__io_funcs.__read == NULL) | |
402 | { | |
403 | /* There is no read function, so always return EOF. */ | |
404 | fp->__eof = 1; | |
405 | goto end; | |
406 | } | |
407 | ||
408 | if (fp->__buffer == NULL) | |
409 | { | |
410 | /* We're unbuffered, so we want to read only one character. */ | |
411 | buffer = (char *) &c; | |
412 | to_read = 1; | |
413 | } | |
414 | else | |
415 | { | |
416 | /* We're buffered, so try to fill the buffer. */ | |
417 | buffer = fp->__buffer; | |
418 | to_read = fp->__bufsize; | |
419 | } | |
420 | ||
421 | /* We're reading, so we're not at the end-of-file. */ | |
422 | fp->__eof = 0; | |
423 | ||
424 | /* Go to the target file position. */ | |
425 | { | |
426 | int save = errno; | |
427 | if (__stdio_check_offset (fp) == 0 && fp->__target != fp->__offset) | |
428 | { | |
429 | /* Move to a block (buffer size) boundary. */ | |
430 | if (fp->__bufsize != 0) | |
431 | { | |
432 | buffer_offset = fp->__target % fp->__bufsize; | |
433 | fp->__target -= buffer_offset; | |
434 | } | |
435 | seek_to_target (fp); | |
436 | } | |
c4029823 | 437 | __set_errno (save); |
28f540f4 RM |
438 | } |
439 | ||
c4029823 | 440 | while (!ferror (fp) && !feof (fp) && nread <= buffer_offset) |
28f540f4 RM |
441 | { |
442 | /* Try to fill the buffer. */ | |
c4029823 | 443 | int count = (*fp->__io_funcs.__read) (fp->__cookie, buffer, to_read); |
28f540f4 RM |
444 | if (count == 0) |
445 | fp->__eof = 1; | |
446 | else if (count < 0) | |
447 | fp->__error = 1; | |
448 | else | |
449 | { | |
450 | buffer += count; | |
451 | nread += count; | |
452 | to_read -= count; | |
8ef76445 RM |
453 | if (fp->__offset != -1) |
454 | /* Record that we've moved forward in the file. */ | |
455 | fp->__offset += count; | |
28f540f4 RM |
456 | } |
457 | } | |
458 | ||
459 | if (fp->__buffer == NULL) | |
460 | /* There is no buffer, so return the character we read | |
461 | without all the buffer pointer diddling. */ | |
c4029823 | 462 | return (feof (fp) || ferror (fp)) ? EOF : c; |
28f540f4 RM |
463 | |
464 | /* Reset the buffer pointer to the beginning of the buffer | |
465 | (plus whatever offset we may have set above). */ | |
466 | fp->__bufp = fp->__buffer + buffer_offset; | |
467 | ||
468 | end:; | |
469 | ||
c4029823 | 470 | if (feof (fp) || ferror (fp)) |
28f540f4 RM |
471 | { |
472 | /* Set both end pointers to the beginning of the buffer so | |
473 | the next i/o call will force a call to __fillbf/__flshfp. */ | |
474 | fp->__put_limit = fp->__get_limit = fp->__buffer; | |
475 | return EOF; | |
476 | } | |
477 | ||
478 | /* Set the end pointer to one past the last character we read. */ | |
479 | fp->__get_limit = fp->__buffer + nread; | |
480 | ||
481 | /* Make it so the next `putc' will call __flshfp. */ | |
482 | fp->__put_limit = fp->__buffer; | |
483 | ||
484 | /* Return the first character in the buffer. */ | |
485 | return *((unsigned char *) (fp->__bufp++)); | |
486 | } | |
487 | ||
488 | ||
489 | /* Default I/O and room functions. */ | |
490 | ||
491 | extern __io_read_fn __stdio_read; | |
492 | extern __io_write_fn __stdio_write; | |
493 | extern __io_seek_fn __stdio_seek; | |
494 | extern __io_close_fn __stdio_close; | |
495 | extern __io_fileno_fn __stdio_fileno; | |
c4029823 | 496 | const __io_functions __default_io_functions = |
28f540f4 RM |
497 | { |
498 | __stdio_read, __stdio_write, __stdio_seek, __stdio_close, __stdio_fileno | |
499 | }; | |
500 | ||
c4029823 | 501 | const __room_functions __default_room_functions = |
28f540f4 RM |
502 | { |
503 | fillbuf, flushbuf | |
504 | }; | |
505 | ||
506 | ||
507 | /* Flush the buffer for FP and also write C if FLUSH_ONLY is nonzero. | |
508 | This is the function used by putc and fflush. */ | |
509 | int | |
c4029823 UD |
510 | __flshfp (fp, c) |
511 | register FILE *fp; | |
512 | int c; | |
28f540f4 RM |
513 | { |
514 | int flush_only = c == EOF; | |
515 | ||
c4029823 | 516 | if (!__validfp (fp) || !fp->__mode.__write) |
28f540f4 | 517 | { |
c4029823 | 518 | __set_errno (EINVAL); |
28f540f4 RM |
519 | return EOF; |
520 | } | |
521 | ||
c4029823 | 522 | if (ferror (fp)) |
28f540f4 RM |
523 | return EOF; |
524 | ||
525 | if (fp->__pushed_back) | |
526 | { | |
527 | /* Discard the char pushed back by ungetc. */ | |
528 | fp->__bufp = fp->__pushback_bufp; | |
529 | fp->__pushed_back = 0; | |
530 | } | |
531 | ||
532 | /* Make sure the stream is initialized (has functions and buffering). */ | |
c4029823 | 533 | init_stream (fp); |
28f540f4 RM |
534 | |
535 | /* Do this early, so a `putc' on such a stream will never return success. */ | |
536 | if (fp->__room_funcs.__output == NULL) | |
537 | { | |
538 | /* A NULL `output room' function means | |
539 | to always return an output error. */ | |
540 | fp->__error = 1; | |
541 | return EOF; | |
542 | } | |
543 | ||
544 | if (!flush_only && | |
545 | /* Will C fit into the buffer? | |
546 | See below about linebuf_active. */ | |
547 | fp->__bufp < (fp->__linebuf_active ? fp->__buffer + fp->__bufsize : | |
548 | fp->__put_limit)) | |
549 | { | |
550 | /* The character will fit in the buffer, so put it there. */ | |
551 | *fp->__bufp++ = (unsigned char) c; | |
552 | if (fp->__linebuf && (unsigned char) c == '\n') | |
553 | flush_only = 1; | |
554 | else | |
555 | return (unsigned char) c; | |
556 | } | |
557 | ||
558 | if (fp->__linebuf_active) | |
559 | /* This is an active line-buffered stream, so its put-limit is set | |
560 | to the beginning of the buffer in order to force a __flshfp call | |
561 | on each putc (see below). We undo this hack here (by setting | |
562 | the limit to the end of the buffer) to simplify the interface | |
563 | with the output-room function. */ | |
564 | fp->__put_limit = fp->__buffer + fp->__bufsize; | |
565 | ||
566 | /* Make room in the buffer. */ | |
567 | (*fp->__room_funcs.__output) (fp, flush_only ? EOF : (unsigned char) c); | |
568 | ||
569 | if (fp->__linebuf) | |
570 | { | |
571 | /* This is a line-buffered stream, and it is now ready to do | |
572 | some output. We call this an "active line-buffered stream". | |
573 | We set the put_limit to the beginning of the buffer, | |
574 | so the next `putc' call will force a call to this function. | |
575 | Setting the linebuf_active flag tells the code above | |
576 | (on the next call) to undo this hackery. */ | |
577 | fp->__put_limit = fp->__buffer; | |
578 | fp->__linebuf_active = 1; | |
579 | } | |
580 | ||
581 | if (ferror (fp)) | |
582 | return EOF; | |
583 | if (flush_only) | |
584 | return 0; | |
585 | return (unsigned char) c; | |
586 | } | |
587 | ||
588 | ||
589 | /* Fill the buffer for FP and return the first character read. | |
590 | This is the function used by getc. */ | |
591 | int | |
c4029823 UD |
592 | __fillbf (fp) |
593 | register FILE *fp; | |
28f540f4 RM |
594 | { |
595 | register int c; | |
596 | fpos_t new_target; | |
597 | ||
c4029823 | 598 | if (!__validfp (fp) || !fp->__mode.__read) |
28f540f4 | 599 | { |
c4029823 | 600 | __set_errno (EINVAL); |
28f540f4 RM |
601 | return EOF; |
602 | } | |
603 | ||
604 | if (fp->__pushed_back) | |
605 | { | |
606 | /* Return the char pushed back by ungetc. */ | |
607 | fp->__bufp = fp->__pushback_bufp; | |
608 | fp->__pushed_back = 0; | |
609 | return fp->__pushback; | |
610 | } | |
611 | ||
612 | /* Make sure the stream is initialized (has functions and buffering). */ | |
c4029823 | 613 | init_stream (fp); |
28f540f4 RM |
614 | |
615 | /* If we're trying to read the first character of a new | |
616 | line of input from an unbuffered or line buffered stream, | |
617 | we must flush all line-buffered output streams. */ | |
618 | if (fp->__buffer == NULL || fp->__linebuf) | |
619 | { | |
620 | register FILE *f; | |
621 | for (f = __stdio_head; f != NULL; f = f->__next) | |
622 | if (__validfp (f) && f->__linebuf && f->__mode.__write) | |
623 | (void) __flshfp (f, EOF); | |
624 | } | |
625 | ||
626 | /* Note we must do this after flushing all line-buffered | |
627 | streams, or else __flshfp would undo it! */ | |
628 | if (fp->__linebuf_active) | |
629 | { | |
630 | /* This is an active line-buffered stream, meaning it is in the midst | |
631 | of writing, but has a bogus put_limit. Restore it to normality. */ | |
632 | fp->__put_limit = fp->__buffer + fp->__bufsize; | |
633 | fp->__linebuf_active = 0; | |
634 | } | |
635 | ||
636 | /* We want the beginning of the buffer to now | |
637 | map to just past the last data we read. */ | |
638 | new_target = fp->__target + (fp->__get_limit - fp->__buffer); | |
639 | ||
640 | if (fp->__put_limit > fp->__buffer) | |
641 | { | |
642 | /* There is written data in the buffer. | |
643 | Flush it out. */ | |
644 | if (fp->__room_funcs.__output == NULL) | |
645 | fp->__error = 1; | |
646 | else | |
647 | (*fp->__room_funcs.__output) (fp, EOF); | |
648 | } | |
649 | ||
650 | fp->__target = new_target; | |
651 | ||
c4029823 | 652 | if (ferror (fp)) |
28f540f4 RM |
653 | c = EOF; |
654 | else if (fp->__room_funcs.__input != NULL) | |
655 | { | |
c4029823 | 656 | c = (*fp->__room_funcs.__input) (fp); |
28f540f4 RM |
657 | if (fp->__buffer == NULL) |
658 | /* This is an unbuffered stream, so the target sync above | |
659 | won't do anything the next time around. Instead, note that | |
660 | we have read one character. The (nonexistent) buffer now | |
661 | maps to the position just past that character. */ | |
662 | ++fp->__target; | |
663 | } | |
664 | else | |
665 | { | |
666 | /* A NULL `input_room' function means always return EOF. */ | |
667 | fp->__eof = 1; | |
668 | c = EOF; | |
669 | } | |
670 | ||
671 | return c; | |
672 | } | |
673 | ||
674 | ||
675 | /* Nuke a stream, but don't kill its link in the chain. */ | |
676 | void | |
c4029823 UD |
677 | __invalidate (stream) |
678 | register FILE *stream; | |
28f540f4 RM |
679 | { |
680 | /* Save its link. */ | |
681 | register FILE *next = stream->__next; | |
682 | ||
6d52618b | 683 | /* Pulverize the deceased. */ |
c4029823 | 684 | memset((void *) stream, 0, sizeof(FILE)); |
28f540f4 RM |
685 | |
686 | /* Restore the deceased's link. */ | |
687 | stream->__next = next; | |
688 | } |