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