ignored by import
[gcc.git] / libio / fileops.c
1 /*
2 Copyright (C) 1993, 1995 Free Software Foundation
3
4 This file is part of the GNU IO Library. This library is free
5 software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this library; see the file COPYING. If not, write to the Free
17 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 As a special exception, if you link this library with files
20 compiled with a GNU compiler to produce an executable, this does not cause
21 the resulting executable to be covered by the GNU General Public License.
22 This exception does not however invalidate any other reasons why
23 the executable file might be covered by the GNU General Public License. */
24
25 /* written by Per Bothner (bothner@cygnus.com) */
26
27 #define _POSIX_SOURCE
28 #include "libioP.h"
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <string.h>
33 #include <errno.h>
34 #ifndef errno
35 extern int errno;
36 #endif
37
38 /* An fstream can be in at most one of put mode, get mode, or putback mode.
39 Putback mode is a variant of get mode.
40
41 In a filebuf, there is only one current position, instead of two
42 separate get and put pointers. In get mode, the current posistion
43 is that of gptr(); in put mode that of pptr().
44
45 The position in the buffer that corresponds to the position
46 in external file system is normally _IO_read_end, except in putback
47 mode, when it is _IO_save_end.
48 If the field _fb._offset is >= 0, it gives the offset in
49 the file as a whole corresponding to eGptr(). (?)
50
51 PUT MODE:
52 If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
53 and _IO_read_base are equal to each other. These are usually equal
54 to _IO_buf_base, though not necessarily if we have switched from
55 get mode to put mode. (The reason is to maintain the invariant
56 that _IO_read_end corresponds to the external file position.)
57 _IO_write_base is non-NULL and usually equal to _IO_base_base.
58 We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
59 The un-flushed character are those between _IO_write_base and _IO_write_ptr.
60
61 GET MODE:
62 If a filebuf is in get or putback mode, eback() != egptr().
63 In get mode, the unread characters are between gptr() and egptr().
64 The OS file position corresponds to that of egptr().
65
66 PUTBACK MODE:
67 Putback mode is used to remember "excess" characters that have
68 been sputbackc'd in a separate putback buffer.
69 In putback mode, the get buffer points to the special putback buffer.
70 The unread characters are the characters between gptr() and egptr()
71 in the putback buffer, as well as the area between save_gptr()
72 and save_egptr(), which point into the original reserve buffer.
73 (The pointers save_gptr() and save_egptr() are the values
74 of gptr() and egptr() at the time putback mode was entered.)
75 The OS position corresponds to that of save_egptr().
76
77 LINE BUFFERED OUTPUT:
78 During line buffered output, _IO_write_base==base() && epptr()==base().
79 However, ptr() may be anywhere between base() and ebuf().
80 This forces a call to filebuf::overflow(int C) on every put.
81 If there is more space in the buffer, and C is not a '\n',
82 then C is inserted, and pptr() incremented.
83
84 UNBUFFERED STREAMS:
85 If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
86 */
87
88 #define CLOSED_FILEBUF_FLAGS \
89 (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
90
91
92 void
93 DEFUN(_IO_file_init, (fp),
94 register _IO_FILE *fp)
95 {
96 /* POSIX.1 allows another file handle to be used to change the position
97 of our file descriptor. Hence we actually don't know the actual
98 position before we do the first fseek (and until a following fflush). */
99 fp->_offset = _IO_pos_BAD;
100 fp->_IO_file_flags |= CLOSED_FILEBUF_FLAGS;
101
102 _IO_link_in(fp);
103 fp->_fileno = -1;
104 }
105
106 int
107 DEFUN(_IO_file_close_it, (fp),
108 register _IO_FILE* fp)
109 {
110 int write_status, close_status;
111 if (!_IO_file_is_open(fp))
112 return EOF;
113
114 write_status = _IO_do_flush (fp);
115
116 _IO_unsave_markers(fp);
117
118 close_status = _IO_SYSCLOSE (fp);
119
120 /* Free buffer. */
121 _IO_setb(fp, NULL, NULL, 0);
122 _IO_setg(fp, NULL, NULL, NULL);
123 _IO_setp(fp, NULL, NULL);
124
125 _IO_un_link(fp);
126 fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
127 fp->_fileno = EOF;
128 fp->_offset = _IO_pos_BAD;
129
130 return close_status ? close_status : write_status;
131 }
132
133 void
134 DEFUN(_IO_file_finish, (fp),
135 register _IO_FILE* fp)
136 {
137 if (_IO_file_is_open(fp))
138 {
139 _IO_do_flush (fp);
140 if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
141 _IO_SYSCLOSE (fp);
142 }
143 _IO_default_finish(fp);
144 }
145
146 _IO_FILE *
147 DEFUN(_IO_file_fopen, (fp, filename, mode),
148 register _IO_FILE *fp AND const char *filename AND const char *mode)
149 {
150 int oflags = 0, omode;
151 int read_write, fdesc;
152 int oprot = 0666;
153 if (_IO_file_is_open (fp))
154 return 0;
155 switch (*mode++) {
156 case 'r':
157 omode = O_RDONLY;
158 read_write = _IO_NO_WRITES;
159 break;
160 case 'w':
161 omode = O_WRONLY;
162 oflags = O_CREAT|O_TRUNC;
163 read_write = _IO_NO_READS;
164 break;
165 case 'a':
166 omode = O_WRONLY;
167 oflags = O_CREAT|O_APPEND;
168 read_write = _IO_NO_READS|_IO_IS_APPENDING;
169 break;
170 default:
171 errno = EINVAL;
172 return NULL;
173 }
174 if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+')) {
175 omode = O_RDWR;
176 read_write &= _IO_IS_APPENDING;
177 }
178 fdesc = open(filename, omode|oflags, oprot);
179 if (fdesc < 0)
180 return NULL;
181 fp->_fileno = fdesc;
182 _IO_mask_flags(fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
183 if (read_write & _IO_IS_APPENDING)
184 if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
185 == _IO_pos_BAD)
186 return NULL;
187 _IO_link_in(fp);
188 return fp;
189 }
190
191 _IO_FILE*
192 DEFUN(_IO_file_attach, (fp, fd),
193 _IO_FILE *fp AND int fd)
194 {
195 if (_IO_file_is_open(fp))
196 return NULL;
197 fp->_fileno = fd;
198 fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
199 fp->_flags |= _IO_DELETE_DONT_CLOSE;
200 fp->_offset = _IO_pos_BAD;
201 return fp;
202 }
203
204 _IO_FILE*
205 DEFUN(_IO_file_setbuf, (fp, p, len),
206 register _IO_FILE *fp AND char* p AND _IO_ssize_t len)
207 {
208 if (_IO_default_setbuf(fp, p, len) == NULL)
209 return NULL;
210
211 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
212 = fp->_IO_buf_base;
213 _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
214
215 return fp;
216 }
217
218 /* Write TO_DO bytes from DATA to FP.
219 Then mark FP as having empty buffers. */
220
221 int
222 DEFUN(_IO_do_write, (fp, data, to_do),
223 register _IO_FILE *fp AND const char* data AND _IO_size_t to_do)
224 {
225 _IO_size_t count;
226 if (to_do == 0)
227 return 0;
228 else
229 {
230 if (fp->_flags & _IO_IS_APPENDING)
231 /* On a system without a proper O_APPEND implementation,
232 you would need to sys_seek(0, SEEK_END) here, but is
233 is not needed nor desirable for Unix- or Posix-like systems.
234 Instead, just indicate that offset (before and after) is
235 unpredictable. */
236 fp->_offset = _IO_pos_BAD;
237 else if (fp->_IO_read_end != fp->_IO_write_base)
238 {
239 _IO_pos_t new_pos
240 = _IO_SYSSEEK(fp, fp->_IO_write_base - fp->_IO_read_end, 1);
241 if (new_pos == _IO_pos_BAD)
242 return EOF;
243 fp->_offset = new_pos;
244 }
245 count = _IO_SYSWRITE (fp, data, to_do);
246 if (fp->_cur_column)
247 fp->_cur_column
248 = _IO_adjust_column (fp->_cur_column - 1, data, to_do) + 1;
249 }
250 _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
251 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
252 fp->_IO_write_end = (fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) ? fp->_IO_buf_base
253 : fp->_IO_buf_end;
254 return count != to_do ? EOF : 0;
255 }
256
257 int
258 DEFUN(_IO_file_underflow, (fp),
259 register _IO_FILE *fp)
260 {
261 _IO_ssize_t count;
262 #if 0
263 /* SysV does not make this test; take it out for compatibility */
264 if (fp->_flags & _IO_EOF_SEEN)
265 return (EOF);
266 #endif
267
268 if (fp->_flags & _IO_NO_READS)
269 return EOF;
270 if (fp->_IO_read_ptr < fp->_IO_read_end)
271 return *(unsigned char*)fp->_IO_read_ptr;
272
273 if (fp->_IO_buf_base == NULL)
274 _IO_doallocbuf(fp);
275
276 /* Flush all line buffered files before reading. */
277 /* FIXME This can/should be moved to genops ?? */
278 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
279 _IO_flush_all_linebuffered();
280
281 _IO_switch_to_get_mode(fp);
282
283 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
284 fp->_IO_buf_end - fp->_IO_buf_base);
285 if (count <= 0)
286 {
287 if (count == 0)
288 fp->_flags |= _IO_EOF_SEEN;
289 else
290 fp->_flags |= _IO_ERR_SEEN, count = 0;
291 }
292 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
293 fp->_IO_read_end = fp->_IO_buf_base + count;
294 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
295 = fp->_IO_buf_base;
296 if (count == 0)
297 return EOF;
298 if (fp->_offset != _IO_pos_BAD)
299 _IO_pos_adjust(fp->_offset, count);
300 return *(unsigned char*)fp->_IO_read_ptr;
301 }
302
303 int
304 DEFUN(_IO_file_overflow, (f, ch),
305 register _IO_FILE* f AND int ch)
306 {
307 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
308 return EOF;
309 /* If currently reading or no buffer allocated. */
310 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
311 {
312 /* Allocate a buffer if needed. */
313 if (f->_IO_write_base == 0)
314 {
315 _IO_doallocbuf(f);
316 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
317 }
318 /* Otherwise must be currently reading.
319 If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
320 logically slide the buffer forwards one block (by setting the
321 read pointers to all point at the beginning of the block). This
322 makes room for subsequent output.
323 Otherwise, set the read pointers to _IO_read_end (leaving that
324 alone, so it can continue to correspond to the external position). */
325 if (f->_IO_read_ptr == f->_IO_buf_end)
326 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
327 f->_IO_write_ptr = f->_IO_read_ptr;
328 f->_IO_write_base = f->_IO_write_ptr;
329 f->_IO_write_end = f->_IO_buf_end;
330 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
331
332 if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
333 f->_IO_write_end = f->_IO_write_ptr;
334 f->_flags |= _IO_CURRENTLY_PUTTING;
335 }
336 if (ch == EOF)
337 return _IO_do_flush(f);
338 if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
339 if (_IO_do_flush(f) == EOF)
340 return EOF;
341 *f->_IO_write_ptr++ = ch;
342 if ((f->_flags & _IO_UNBUFFERED)
343 || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
344 if (_IO_do_flush(f) == EOF)
345 return EOF;
346 return (unsigned char)ch;
347 }
348
349 int
350 DEFUN(_IO_file_sync, (fp),
351 register _IO_FILE* fp)
352 {
353 _IO_size_t delta;
354 /* char* ptr = cur_ptr(); */
355 if (fp->_IO_write_ptr > fp->_IO_write_base)
356 if (_IO_do_flush(fp)) return EOF;
357 delta = fp->_IO_read_ptr - fp->_IO_read_end;
358 if (delta != 0)
359 {
360 #ifdef TODO
361 if (_IO_in_backup(fp))
362 delta -= eGptr() - Gbase();
363 #endif
364 _IO_off_t new_pos = _IO_SYSSEEK (fp, delta, 1);
365 if (new_pos != (_IO_off_t)EOF)
366 fp->_IO_read_end = fp->_IO_read_ptr;
367 #ifdef ESPIPE
368 else if (errno == ESPIPE)
369 ; /* Ignore error from unseekable devices. */
370 #endif
371 else
372 return EOF;
373 }
374 fp->_offset = _IO_pos_BAD;
375 /* FIXME: Cleanup - can this be shared? */
376 /* setg(base(), ptr, ptr); */
377 return 0;
378 }
379
380 _IO_pos_t
381 DEFUN(_IO_file_seekoff, (fp, offset, dir, mode),
382 register _IO_FILE *fp AND _IO_off_t offset AND int dir AND int mode)
383 {
384 _IO_pos_t result;
385 _IO_off_t delta, new_offset;
386 long count;
387
388 if (mode == 0)
389 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
390
391 /* Flush unwritten characters.
392 (This may do an unneeded write if we seek within the buffer.
393 But to be able to switch to reading, we would need to set
394 egptr to ptr. That can't be done in the current design,
395 which assumes file_ptr() is eGptr. Anyway, since we probably
396 end up flushing when we close(), it doesn't make much difference.)
397 FIXME: simulate mem-papped files. */
398
399 if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode(fp))
400 if (_IO_switch_to_get_mode(fp)) return EOF;
401
402 if (fp->_IO_buf_base == NULL)
403 {
404 _IO_doallocbuf(fp);
405 _IO_setp(fp, fp->_IO_buf_base, fp->_IO_buf_base);
406 _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
407 }
408
409 switch (dir)
410 {
411 case _IO_seek_cur:
412 /* Adjust for read-ahead (bytes is buffer). */
413 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
414 if (fp->_offset == _IO_pos_BAD)
415 goto dumb;
416 /* Make offset absolute, assuming current pointer is file_ptr(). */
417 offset += _IO_pos_as_off(fp->_offset);
418
419 dir = _IO_seek_set;
420 break;
421 case _IO_seek_set:
422 break;
423 case _IO_seek_end:
424 {
425 struct stat st;
426 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG(st.st_mode))
427 {
428 offset += st.st_size;
429 dir = _IO_seek_set;
430 }
431 else
432 goto dumb;
433 }
434 }
435 /* At this point, dir==_IO_seek_set. */
436
437 /* If destination is within current buffer, optimize: */
438 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
439 && !_IO_in_backup (fp))
440 {
441 /* Offset relative to start of main get area. */
442 _IO_pos_t rel_offset = offset - fp->_offset
443 + (fp->_IO_read_end - fp->_IO_read_base);
444 if (rel_offset >= 0)
445 {
446 #if 0
447 if (_IO_in_backup(fp))
448 _IO_switch_to_main_get_area(fp);
449 #endif
450 if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
451 {
452 _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
453 fp->_IO_read_end);
454 _IO_setp(fp, fp->_IO_buf_base, fp->_IO_buf_base);
455 return offset;
456 }
457 #ifdef TODO
458 /* If we have streammarkers, seek forward by reading ahead. */
459 if (_IO_have_markers(fp))
460 {
461 int to_skip = rel_offset
462 - (fp->_IO_read_ptr - fp->_IO_read_base);
463 if (ignore(to_skip) != to_skip)
464 goto dumb;
465 return offset;
466 }
467 #endif
468 }
469 #ifdef TODO
470 if (rel_offset < 0 && rel_offset >= Bbase() - Bptr())
471 {
472 if (!_IO_in_backup(fp))
473 _IO_switch_to_backup_area(fp);
474 gbump(fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
475 return offset;
476 }
477 #endif
478 }
479
480 #ifdef TODO
481 _IO_unsave_markers(fp);
482 #endif
483
484 if (fp->_flags & _IO_NO_READS)
485 goto dumb;
486
487 /* Try to seek to a block boundary, to improve kernel page management. */
488 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
489 delta = offset - new_offset;
490 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
491 {
492 new_offset = offset;
493 delta = 0;
494 }
495 result = _IO_SYSSEEK (fp, new_offset, 0);
496 if (result < 0)
497 return EOF;
498 if (delta == 0)
499 count = 0;
500 else
501 {
502 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
503 fp->_IO_buf_end - fp->_IO_buf_base);
504 if (count < delta)
505 {
506 /* We weren't allowed to read, but try to seek the remainder. */
507 offset = count == EOF ? delta : delta-count;
508 dir = _IO_seek_cur;
509 goto dumb;
510 }
511 }
512 _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base+delta, fp->_IO_buf_base+count);
513 _IO_setp(fp, fp->_IO_buf_base, fp->_IO_buf_base);
514 fp->_offset = result + count;
515 _IO_mask_flags(fp, 0, _IO_EOF_SEEN);
516 return offset;
517 dumb:
518
519 _IO_unsave_markers(fp);
520 result = _IO_SYSSEEK (fp, offset, dir);
521 if (result != EOF)
522 _IO_mask_flags(fp, 0, _IO_EOF_SEEN);
523 fp->_offset = result;
524 _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
525 _IO_setp(fp, fp->_IO_buf_base, fp->_IO_buf_base);
526 return result;
527 }
528
529 _IO_ssize_t
530 DEFUN(_IO_file_read, (fp, buf, size),
531 register _IO_FILE* fp AND void* buf AND _IO_ssize_t size)
532 {
533 for (;;)
534 {
535 _IO_ssize_t count = _IO_read(fp->_fileno, buf, size);
536 #ifdef EINTR
537 if (count == -1 && errno == EINTR)
538 continue;
539 #endif
540 return count;
541 }
542 }
543
544 _IO_pos_t
545 DEFUN(_IO_file_seek, (fp, offset, dir),
546 _IO_FILE *fp AND _IO_off_t offset AND int dir)
547 {
548 return _IO_lseek(fp->_fileno, offset, dir);
549 }
550
551 int
552 DEFUN(_IO_file_stat, (fp, st),
553 _IO_FILE *fp AND void* st)
554 {
555 return _IO_fstat(fp->_fileno, (struct stat*)st);
556 }
557
558 int
559 DEFUN(_IO_file_close, (fp),
560 _IO_FILE* fp)
561 {
562 return _IO_close(fp->_fileno);
563 }
564
565 _IO_ssize_t
566 DEFUN(_IO_file_write, (f, data, n),
567 register _IO_FILE* f AND const void* data AND _IO_ssize_t n)
568 {
569 _IO_ssize_t to_do = n;
570 while (to_do > 0)
571 {
572 _IO_ssize_t count = _IO_write(f->_fileno, data, to_do);
573 if (count == EOF)
574 {
575 #ifdef EINTR
576 if (errno == EINTR)
577 continue;
578 else
579 #endif
580 {
581 f->_flags |= _IO_ERR_SEEN;
582 break;
583 }
584 }
585 to_do -= count;
586 data = (void*)((char*)data + count);
587 }
588 n -= to_do;
589 if (f->_offset >= 0)
590 f->_offset += n;
591 return n;
592 }
593
594 _IO_size_t
595 DEFUN(_IO_file_xsputn, (f, data, n),
596 _IO_FILE *f AND const void *data AND _IO_size_t n)
597 {
598 register const char *s = (char*) data;
599 _IO_size_t to_do = n;
600 int must_flush = 0;
601 _IO_size_t count;
602
603 if (n <= 0)
604 return 0;
605 /* This is an optimized implementation.
606 If the amount to be written straddles a block boundary
607 (or the filebuf is unbuffered), use sys_write directly. */
608
609 /* First figure out how much space is available in the buffer. */
610 count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
611 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
612 {
613 count = f->_IO_buf_end - f->_IO_write_ptr;
614 if (count >= n)
615 { register const char *p;
616 for (p = s + n; p > s; )
617 {
618 if (*--p == '\n') {
619 count = p - s + 1;
620 must_flush = 1;
621 break;
622 }
623 }
624 }
625 }
626 /* Then fill the buffer. */
627 if (count > 0)
628 {
629 if (count > to_do)
630 count = to_do;
631 if (count > 20) {
632 memcpy(f->_IO_write_ptr, s, count);
633 s += count;
634 }
635 else
636 {
637 register char *p = f->_IO_write_ptr;
638 register int i = (int)count;
639 while (--i >= 0) *p++ = *s++;
640 }
641 f->_IO_write_ptr += count;
642 to_do -= count;
643 }
644 if (to_do + must_flush > 0)
645 { _IO_size_t block_size, dont_write;
646 /* Next flush the (full) buffer. */
647 if (__overflow(f, EOF) == EOF)
648 return n - to_do;
649
650 /* Try to maintain alignment: write a whole number of blocks.
651 dont_write is what gets left over. */
652 block_size = f->_IO_buf_end - f->_IO_buf_base;
653 dont_write = block_size >= 128 ? to_do % block_size : 0;
654
655 count = to_do - dont_write;
656 if (_IO_do_write(f, s, count) == EOF)
657 return n - to_do;
658 to_do = dont_write;
659
660 /* Now write out the remainder. Normally, this will fit in the
661 buffer, but it's somewhat messier for line-buffered files,
662 so we let _IO_default_xsputn handle the general case. */
663 if (dont_write)
664 to_do -= _IO_default_xsputn(f, s+count, dont_write);
665 }
666 return n - to_do;
667 }
668
669 #if 0
670 /* Work in progress */
671 _IO_size_t
672 DEFUN(_IO_file_xsgetn, (fp, data, n),
673 _IO_FILE *fp AND void *data AND _IO_size_t n)
674 {
675 register _IO_size_t more = n;
676 register char *s = data;
677 for (;;)
678 {
679 _IO_ssize_t count = fp->_IO_read_end - fp->_IO_read_ptr; /* Data available. */
680 if (count > 0)
681 {
682 if (count > more)
683 count = more;
684 if (count > 20)
685 {
686 memcpy(s, fp->_IO_read_ptr, count);
687 s += count;
688 fp->_IO_read_ptr += count;
689 }
690 else if (count <= 0)
691 count = 0;
692 else
693 {
694 register char *p = fp->_IO_read_ptr;
695 register int i = (int)count;
696 while (--i >= 0) *s++ = *p++;
697 fp->_IO_read_ptr = p;
698 }
699 more -= count;
700 }
701 #if 0
702 if (! _IO_in put_mode (fp)
703 && ! _IO_have_markers (fp) && ! IO_have_backup (fp))
704 {
705 /* This is an optimization of _IO_file_underflow */
706 if (fp->_flags & _IO_NO_READS)
707 break;
708 /* If we're reading a lot of data, don't bother allocating
709 a buffer. But if we're only reading a bit, perhaps we should ??*/
710 if (count <= 512 && fp->_IO_buf_base == NULL)
711 _IO_doallocbuf(fp);
712 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
713 _IO_flush_all_linebuffered();
714
715 _IO_switch_to_get_mode(fp); ???;
716 count = _IO_SYSREAD (fp, s, more);
717 if (count <= 0)
718 {
719 if (count == 0)
720 fp->_flags |= _IO_EOF_SEEN;
721 else
722 fp->_flags |= _IO_ERR_SEEN, count = 0;
723 }
724
725 s += count;
726 more -= count;
727 }
728 #endif
729 if (more == 0 || __underflow(fp) == EOF)
730 break;
731 }
732 return n - more;
733 }
734 #endif
735
736 struct _IO_jump_t _IO_file_jumps = {
737 JUMP_INIT_DUMMY,
738 JUMP_INIT(finish, _IO_file_finish),
739 JUMP_INIT(overflow, _IO_file_overflow),
740 JUMP_INIT(underflow, _IO_file_underflow),
741 JUMP_INIT(uflow, _IO_default_uflow),
742 JUMP_INIT(pbackfail, _IO_default_pbackfail),
743 JUMP_INIT(xsputn, _IO_file_xsputn),
744 JUMP_INIT(xsgetn, _IO_default_xsgetn),
745 JUMP_INIT(seekoff, _IO_file_seekoff),
746 JUMP_INIT(seekpos, _IO_default_seekpos),
747 JUMP_INIT(setbuf, _IO_file_setbuf),
748 JUMP_INIT(sync, _IO_file_sync),
749 JUMP_INIT(doallocate, _IO_file_doallocate),
750 JUMP_INIT(read, _IO_file_read),
751 JUMP_INIT(write, _IO_file_write),
752 JUMP_INIT(seek, _IO_file_seek),
753 JUMP_INIT(close, _IO_file_close),
754 JUMP_INIT(stat, _IO_file_stat)
755 };