Use INTUSE to reference functions and variables inside libc itself.
[kopensolaris-gnu/glibc.git] / libio / fileops.c
1 /* Copyright (C) 1993, 1995, 1997-2001, 2002 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Written by Per Bothner <bothner@cygnus.com>.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C 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 GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.
19
20    As a special exception, if you link the code in this file with
21    files compiled with a GNU compiler to produce an executable,
22    that does not cause the resulting executable to be covered by
23    the GNU Lesser General Public License.  This exception does not
24    however invalidate any other reasons why the executable file
25    might be covered by the GNU Lesser General Public License.
26    This exception applies to code released by its copyright holders
27    in files containing the exception.  */
28
29
30 #ifndef _POSIX_SOURCE
31 # define _POSIX_SOURCE
32 #endif
33 #include "libioP.h"
34 #include <assert.h>
35 #include <fcntl.h>
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #ifdef __STDC__
43 #include <stdlib.h>
44 #endif
45 #if _LIBC
46 # include "../wcsmbs/wcsmbsload.h"
47 # include "../iconv/gconv_charset.h"
48 # include "../iconv/gconv_int.h"
49 # include <shlib-compat.h>
50 #endif
51 #ifndef errno
52 extern int errno;
53 #endif
54 #ifndef __set_errno
55 # define __set_errno(Val) errno = (Val)
56 #endif
57
58
59 #ifdef _LIBC
60 # define open(Name, Flags, Prot) __open (Name, Flags, Prot)
61 # define close(FD) __close (FD)
62 # define lseek(FD, Offset, Whence) __lseek (FD, Offset, Whence)
63 # define read(FD, Buf, NBytes) __read (FD, Buf, NBytes)
64 # define write(FD, Buf, NBytes) __write (FD, Buf, NBytes)
65 #else
66 # define _IO_new_do_write _IO_do_write
67 # define _IO_new_file_attach _IO_file_attach
68 # define _IO_new_file_close_it _IO_file_close_it
69 # define _IO_new_file_finish _IO_file_finish
70 # define _IO_new_file_fopen _IO_file_fopen
71 # define _IO_new_file_init _IO_file_init
72 # define _IO_new_file_setbuf _IO_file_setbuf
73 # define _IO_new_file_sync _IO_file_sync
74 # define _IO_new_file_overflow _IO_file_overflow
75 # define _IO_new_file_seekoff _IO_file_seekoff
76 # define _IO_new_file_underflow _IO_file_underflow
77 # define _IO_new_file_write _IO_file_write
78 # define _IO_new_file_xsputn _IO_file_xsputn
79 #endif
80
81
82 #ifdef _LIBC
83 extern struct __gconv_trans_data __libio_translit;
84 #endif
85
86
87 /* An fstream can be in at most one of put mode, get mode, or putback mode.
88    Putback mode is a variant of get mode.
89
90    In a filebuf, there is only one current position, instead of two
91    separate get and put pointers.  In get mode, the current position
92    is that of gptr(); in put mode that of pptr().
93
94    The position in the buffer that corresponds to the position
95    in external file system is normally _IO_read_end, except in putback
96    mode, when it is _IO_save_end.
97    If the field _fb._offset is >= 0, it gives the offset in
98    the file as a whole corresponding to eGptr(). (?)
99
100    PUT MODE:
101    If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
102    and _IO_read_base are equal to each other.  These are usually equal
103    to _IO_buf_base, though not necessarily if we have switched from
104    get mode to put mode.  (The reason is to maintain the invariant
105    that _IO_read_end corresponds to the external file position.)
106    _IO_write_base is non-NULL and usually equal to _IO_base_base.
107    We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
108    The un-flushed character are those between _IO_write_base and _IO_write_ptr.
109
110    GET MODE:
111    If a filebuf is in get or putback mode, eback() != egptr().
112    In get mode, the unread characters are between gptr() and egptr().
113    The OS file position corresponds to that of egptr().
114
115    PUTBACK MODE:
116    Putback mode is used to remember "excess" characters that have
117    been sputbackc'd in a separate putback buffer.
118    In putback mode, the get buffer points to the special putback buffer.
119    The unread characters are the characters between gptr() and egptr()
120    in the putback buffer, as well as the area between save_gptr()
121    and save_egptr(), which point into the original reserve buffer.
122    (The pointers save_gptr() and save_egptr() are the values
123    of gptr() and egptr() at the time putback mode was entered.)
124    The OS position corresponds to that of save_egptr().
125
126    LINE BUFFERED OUTPUT:
127    During line buffered output, _IO_write_base==base() && epptr()==base().
128    However, ptr() may be anywhere between base() and ebuf().
129    This forces a call to filebuf::overflow(int C) on every put.
130    If there is more space in the buffer, and C is not a '\n',
131    then C is inserted, and pptr() incremented.
132
133    UNBUFFERED STREAMS:
134    If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
135 */
136
137 #define CLOSED_FILEBUF_FLAGS \
138   (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
139
140
141 void
142 _IO_new_file_init (fp)
143      struct _IO_FILE_plus *fp;
144 {
145   /* POSIX.1 allows another file handle to be used to change the position
146      of our file descriptor.  Hence we actually don't know the actual
147      position before we do the first fseek (and until a following fflush). */
148   fp->file._offset = _IO_pos_BAD;
149   fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS;
150
151   INTUSE(_IO_link_in) (fp);
152   fp->file._fileno = -1;
153 }
154 INTDEF2(_IO_new_file_init, _IO_file_init)
155
156 int
157 _IO_new_file_close_it (fp)
158      _IO_FILE *fp;
159 {
160   int write_status, close_status;
161   if (!_IO_file_is_open (fp))
162     return EOF;
163
164   write_status = _IO_do_flush (fp);
165
166   INTUSE(_IO_unsave_markers) (fp);
167
168   close_status = _IO_SYSCLOSE (fp);
169
170   /* Free buffer. */
171   if (fp->_mode <= 0)
172     {
173       INTUSE(_IO_setb) (fp, NULL, NULL, 0);
174       _IO_setg (fp, NULL, NULL, NULL);
175       _IO_setp (fp, NULL, NULL);
176     }
177 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
178   else
179     {
180       INTUSE(_IO_wsetb) (fp, NULL, NULL, 0);
181       _IO_wsetg (fp, NULL, NULL, NULL);
182       _IO_wsetp (fp, NULL, NULL);
183     }
184 #endif
185
186   INTUSE(_IO_un_link) ((struct _IO_FILE_plus *) fp);
187   fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
188   fp->_fileno = -1;
189   fp->_offset = _IO_pos_BAD;
190
191   return close_status ? close_status : write_status;
192 }
193 INTDEF2(_IO_new_file_close_it, _IO_file_close_it)
194
195 void
196 _IO_new_file_finish (fp, dummy)
197      _IO_FILE *fp;
198      int dummy;
199 {
200   if (_IO_file_is_open (fp))
201     {
202       _IO_do_flush (fp);
203       if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
204         _IO_SYSCLOSE (fp);
205     }
206   INTUSE(_IO_default_finish) (fp, 0);
207 }
208 INTDEF2(_IO_new_file_finish, _IO_file_finish)
209
210 #if defined __GNUC__ && __GNUC__ >= 2
211 __inline__
212 #endif
213 _IO_FILE *
214 _IO_file_open (fp, filename, posix_mode, prot, read_write, is32not64)
215      _IO_FILE *fp;
216      const char *filename;
217      int posix_mode;
218      int prot;
219      int read_write;
220      int is32not64;
221 {
222   int fdesc;
223 #ifdef _G_OPEN64
224   fdesc = (is32not64
225            ? open (filename, posix_mode, prot)
226            : _G_OPEN64 (filename, posix_mode, prot));
227 #else
228   fdesc = open (filename, posix_mode, prot);
229 #endif
230   if (fdesc < 0)
231     return NULL;
232   fp->_fileno = fdesc;
233   _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
234   if (read_write & _IO_IS_APPENDING)
235     if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
236         == _IO_pos_BAD && errno != ESPIPE)
237       return NULL;
238   INTUSE(_IO_link_in) ((struct _IO_FILE_plus *) fp);
239   return fp;
240 }
241
242 _IO_FILE *
243 _IO_new_file_fopen (fp, filename, mode, is32not64)
244      _IO_FILE *fp;
245      const char *filename;
246      const char *mode;
247      int is32not64;
248 {
249   int oflags = 0, omode;
250   int read_write;
251   int oprot = 0666;
252   int i;
253   _IO_FILE *result;
254 #ifdef _LIBC
255   const char *cs;
256   const char *last_recognized;
257 #endif
258
259   if (_IO_file_is_open (fp))
260     return 0;
261   switch (*mode)
262     {
263     case 'r':
264       omode = O_RDONLY;
265       read_write = _IO_NO_WRITES;
266       break;
267     case 'w':
268       omode = O_WRONLY;
269       oflags = O_CREAT|O_TRUNC;
270       read_write = _IO_NO_READS;
271       break;
272     case 'a':
273       omode = O_WRONLY;
274       oflags = O_CREAT|O_APPEND;
275       read_write = _IO_NO_READS|_IO_IS_APPENDING;
276       break;
277     default:
278       __set_errno (EINVAL);
279       return NULL;
280     }
281 #ifdef _LIBC
282   last_recognized = mode;
283 #endif
284   for (i = 1; i < 4; ++i)
285     {
286       switch (*++mode)
287         {
288         case '\0':
289           break;
290         case '+':
291           omode = O_RDWR;
292           read_write &= _IO_IS_APPENDING;
293 #ifdef _LIBC
294           last_recognized = mode;
295 #endif
296           continue;
297         case 'x':
298           oflags |= O_EXCL;
299 #ifdef _LIBC
300           last_recognized = mode;
301 #endif
302           continue;
303         case 'b':
304 #ifdef _LIBC
305           last_recognized = mode;
306 #endif
307         default:
308           /* Ignore.  */
309           continue;
310         }
311       break;
312     }
313
314   result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write,
315                           is32not64);
316
317
318 #ifdef _LIBC
319   if (result != NULL)
320     {
321       /* Test whether the mode string specifies the conversion.  */
322       cs = strstr (last_recognized + 1, ",ccs=");
323       if (cs != NULL)
324         {
325           /* Yep.  Load the appropriate conversions and set the orientation
326              to wide.  */
327           struct gconv_fcts fcts;
328           struct _IO_codecvt *cc;
329           char *endp = __strchrnul (cs + 5, ',');
330           char ccs[endp - (cs + 5) + 3];
331
332           *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
333           strip (ccs, ccs);
334
335           if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
336                                    ? upstr (ccs, cs + 5) : ccs) != 0)
337             {
338               /* Something went wrong, we cannot load the conversion modules.
339                  This means we cannot proceed since the user explicitly asked
340                  for these.  */
341               __set_errno (EINVAL);
342               return NULL;
343             }
344
345           assert (fcts.towc_nsteps == 1);
346           assert (fcts.tomb_nsteps == 1);
347
348           fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
349           fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
350
351           /* Clear the state.  We start all over again.  */
352           memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
353           memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
354
355           cc = fp->_codecvt = &fp->_wide_data->_codecvt;
356
357           /* The functions are always the same.  */
358           *cc = __libio_codecvt;
359
360           cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
361           cc->__cd_in.__cd.__steps = fcts.towc;
362
363           cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
364           cc->__cd_in.__cd.__data[0].__internal_use = 1;
365           cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
366           cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
367
368           /* XXX For now no transliteration.  */
369           cc->__cd_in.__cd.__data[0].__trans = NULL;
370
371           cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
372           cc->__cd_out.__cd.__steps = fcts.tomb;
373
374           cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
375           cc->__cd_out.__cd.__data[0].__internal_use = 1;
376           cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
377           cc->__cd_out.__cd.__data[0].__statep =
378             &result->_wide_data->_IO_state;
379
380           /* And now the transliteration.  */
381           cc->__cd_out.__cd.__data[0].__trans = &__libio_translit;
382
383           /* Set the mode now.  */
384           result->_mode = 1;
385
386           /* We don't need the step data structure anymore.  */
387           __gconv_release_cache (fcts.towc, fcts.towc_nsteps);
388           __gconv_release_cache (fcts.tomb, fcts.tomb_nsteps);
389         }
390     }
391 #endif  /* GNU libc */
392
393   return result;
394 }
395 INTDEF2(_IO_new_file_fopen, _IO_file_fopen)
396
397 _IO_FILE *
398 _IO_new_file_attach (fp, fd)
399      _IO_FILE *fp;
400      int fd;
401 {
402   if (_IO_file_is_open (fp))
403     return NULL;
404   fp->_fileno = fd;
405   fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
406   fp->_flags |= _IO_DELETE_DONT_CLOSE;
407   /* Get the current position of the file. */
408   /* We have to do that since that may be junk. */
409   fp->_offset = _IO_pos_BAD;
410   if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT)
411       == _IO_pos_BAD && errno != ESPIPE)
412     return NULL;
413   return fp;
414 }
415 INTDEF2(_IO_new_file_attach, _IO_file_attach)
416
417 _IO_FILE *
418 _IO_new_file_setbuf (fp, p, len)
419      _IO_FILE *fp;
420      char *p;
421      _IO_ssize_t len;
422 {
423   if (_IO_default_setbuf (fp, p, len) == NULL)
424     return NULL;
425
426   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
427     = fp->_IO_buf_base;
428   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
429
430   return fp;
431 }
432 INTDEF2(_IO_new_file_setbuf, _IO_file_setbuf)
433
434 static int new_do_write __P ((_IO_FILE *, const char *, _IO_size_t));
435
436 /* Write TO_DO bytes from DATA to FP.
437    Then mark FP as having empty buffers. */
438
439 int
440 _IO_new_do_write (fp, data, to_do)
441      _IO_FILE *fp;
442      const char *data;
443      _IO_size_t to_do;
444 {
445   return (to_do == 0 || new_do_write (fp, data, to_do) == to_do) ? 0 : EOF;
446 }
447 INTDEF2(_IO_new_do_write, _IO_do_write)
448
449 static
450 int
451 new_do_write (fp, data, to_do)
452      _IO_FILE *fp;
453      const char *data;
454      _IO_size_t to_do;
455 {
456   _IO_size_t count;
457   if (fp->_flags & _IO_IS_APPENDING)
458     /* On a system without a proper O_APPEND implementation,
459        you would need to sys_seek(0, SEEK_END) here, but is
460        is not needed nor desirable for Unix- or Posix-like systems.
461        Instead, just indicate that offset (before and after) is
462        unpredictable. */
463     fp->_offset = _IO_pos_BAD;
464   else if (fp->_IO_read_end != fp->_IO_write_base)
465     {
466       _IO_off64_t new_pos
467         = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
468       if (new_pos == _IO_pos_BAD)
469         return 0;
470       fp->_offset = new_pos;
471     }
472   count = _IO_SYSWRITE (fp, data, to_do);
473   if (fp->_cur_column && count)
474     fp->_cur_column = INTUSE(_IO_adjust_column) (fp->_cur_column - 1, data,
475                                                  count) + 1;
476   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
477   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
478   fp->_IO_write_end = (fp->_mode <= 0
479                        && (fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
480                        ? fp->_IO_buf_base : fp->_IO_buf_end);
481   return count;
482 }
483
484 int
485 _IO_new_file_underflow (fp)
486      _IO_FILE *fp;
487 {
488   _IO_ssize_t count;
489 #if 0
490   /* SysV does not make this test; take it out for compatibility */
491   if (fp->_flags & _IO_EOF_SEEN)
492     return (EOF);
493 #endif
494
495   if (fp->_flags & _IO_NO_READS)
496     {
497       fp->_flags |= _IO_ERR_SEEN;
498       __set_errno (EBADF);
499       return EOF;
500     }
501   if (fp->_IO_read_ptr < fp->_IO_read_end)
502     return *(unsigned char *) fp->_IO_read_ptr;
503
504   if (fp->_IO_buf_base == NULL)
505     {
506       /* Maybe we already have a push back pointer.  */
507       if (fp->_IO_save_base != NULL)
508         {
509           free (fp->_IO_save_base);
510           fp->_flags &= ~_IO_IN_BACKUP;
511         }
512       INTUSE(_IO_doallocbuf) (fp);
513     }
514
515   /* Flush all line buffered files before reading. */
516   /* FIXME This can/should be moved to genops ?? */
517   if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
518     {
519 #if 0
520       INTUSE(_IO_flush_all_linebuffered) ();
521 #else
522       /* We used to flush all line-buffered stream.  This really isn't
523          required by any standard.  My recollection is that
524          traditional Unix systems did this for stdout.  stderr better
525          not be line buffered.  So we do just that here
526          explicitly.  --drepper */
527       _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile,
528                                 _IO_stdout);
529       _IO_flockfile (_IO_stdout);
530
531       if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
532           == (_IO_LINKED | _IO_LINE_BUF))
533         _IO_OVERFLOW (_IO_stdout, EOF);
534
535       _IO_funlockfile (_IO_stdout);
536       _IO_cleanup_region_end (0);
537 #endif
538     }
539
540   INTUSE(_IO_switch_to_get_mode) (fp);
541
542   /* This is very tricky. We have to adjust those
543      pointers before we call _IO_SYSREAD () since
544      we may longjump () out while waiting for
545      input. Those pointers may be screwed up. H.J. */
546   fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
547   fp->_IO_read_end = fp->_IO_buf_base;
548   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
549     = fp->_IO_buf_base;
550
551   count = _IO_SYSREAD (fp, fp->_IO_buf_base,
552                        fp->_IO_buf_end - fp->_IO_buf_base);
553   if (count <= 0)
554     {
555       if (count == 0)
556         fp->_flags |= _IO_EOF_SEEN;
557       else
558         fp->_flags |= _IO_ERR_SEEN, count = 0;
559   }
560   fp->_IO_read_end += count;
561   if (count == 0)
562     return EOF;
563   if (fp->_offset != _IO_pos_BAD)
564     _IO_pos_adjust (fp->_offset, count);
565   return *(unsigned char *) fp->_IO_read_ptr;
566 }
567 INTDEF2(_IO_new_file_underflow, _IO_file_underflow)
568
569 /* Special callback replacing the underflow callbacks if we mmap the
570    file.  */
571 int
572 _IO_file_underflow_mmap (_IO_FILE *fp)
573 {
574   if (fp->_IO_read_end < fp->_IO_buf_end)
575     {
576       if (
577 # ifdef _G_LSEEK64
578           _G_LSEEK64 (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base,
579                       SEEK_SET)
580 # else
581           __lseek (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base, SEEK_SET)
582 # endif
583           != fp->_IO_buf_end - fp->_IO_buf_base)
584         {
585           fp->_flags |= _IO_ERR_SEEN;
586           return EOF;
587         }
588
589       fp->_offset = fp->_IO_buf_end - fp->_IO_buf_base;
590       fp->_IO_read_end = fp->_IO_buf_end;
591       return *(unsigned char *) fp->_IO_read_ptr;
592     }
593
594   fp->_flags |= _IO_EOF_SEEN;
595   return EOF;
596 }
597
598 int
599 _IO_new_file_overflow (f, ch)
600       _IO_FILE *f;
601       int ch;
602 {
603   if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
604     {
605       f->_flags |= _IO_ERR_SEEN;
606       __set_errno (EBADF);
607       return EOF;
608     }
609   /* If currently reading or no buffer allocated. */
610   if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == 0)
611     {
612       /* Allocate a buffer if needed. */
613       if (f->_IO_write_base == 0)
614         {
615           INTUSE(_IO_doallocbuf) (f);
616           _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
617         }
618       /* Otherwise must be currently reading.
619          If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
620          logically slide the buffer forwards one block (by setting the
621          read pointers to all point at the beginning of the block).  This
622          makes room for subsequent output.
623          Otherwise, set the read pointers to _IO_read_end (leaving that
624          alone, so it can continue to correspond to the external position). */
625       if (f->_IO_read_ptr == f->_IO_buf_end)
626         f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
627       f->_IO_write_ptr = f->_IO_read_ptr;
628       f->_IO_write_base = f->_IO_write_ptr;
629       f->_IO_write_end = f->_IO_buf_end;
630       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
631
632       f->_flags |= _IO_CURRENTLY_PUTTING;
633       if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
634         f->_IO_write_end = f->_IO_write_ptr;
635     }
636   if (ch == EOF)
637     return _IO_new_do_write(f, f->_IO_write_base,
638                             f->_IO_write_ptr - f->_IO_write_base);
639   if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
640     if (_IO_do_flush (f) == EOF)
641       return EOF;
642   *f->_IO_write_ptr++ = ch;
643   if ((f->_flags & _IO_UNBUFFERED)
644       || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
645     if (_IO_new_do_write(f, f->_IO_write_base,
646                          f->_IO_write_ptr - f->_IO_write_base) == EOF)
647       return EOF;
648   return (unsigned char) ch;
649 }
650 INTDEF2(_IO_new_file_overflow, _IO_file_overflow)
651
652 int
653 _IO_new_file_sync (fp)
654      _IO_FILE *fp;
655 {
656   _IO_ssize_t delta;
657   int retval = 0;
658
659   /*    char* ptr = cur_ptr(); */
660   if (fp->_IO_write_ptr > fp->_IO_write_base)
661     if (_IO_do_flush(fp)) return EOF;
662   delta = fp->_IO_read_ptr - fp->_IO_read_end;
663   if (delta != 0)
664     {
665 #ifdef TODO
666       if (_IO_in_backup (fp))
667         delta -= eGptr () - Gbase ();
668 #endif
669       _IO_off64_t new_pos = _IO_SYSSEEK (fp, delta, 1);
670       if (new_pos != (_IO_off64_t) EOF)
671         fp->_IO_read_end = fp->_IO_read_ptr;
672 #ifdef ESPIPE
673       else if (errno == ESPIPE)
674         ; /* Ignore error from unseekable devices. */
675 #endif
676       else
677         retval = EOF;
678     }
679   if (retval != EOF)
680     fp->_offset = _IO_pos_BAD;
681   /* FIXME: Cleanup - can this be shared? */
682   /*    setg(base(), ptr, ptr); */
683   return retval;
684 }
685 INTDEF2(_IO_new_file_sync, _IO_file_sync)
686
687 _IO_off64_t
688 _IO_new_file_seekoff (fp, offset, dir, mode)
689      _IO_FILE *fp;
690      _IO_off64_t offset;
691      int dir;
692      int mode;
693 {
694   _IO_off64_t result;
695   _IO_off64_t delta, new_offset;
696   long count;
697   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
698      offset of the underlying file must be exact.  */
699   int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
700                        && fp->_IO_write_base == fp->_IO_write_ptr);
701
702   if (mode == 0)
703     dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
704
705   /* Flush unwritten characters.
706      (This may do an unneeded write if we seek within the buffer.
707      But to be able to switch to reading, we would need to set
708      egptr to ptr.  That can't be done in the current design,
709      which assumes file_ptr() is eGptr.  Anyway, since we probably
710      end up flushing when we close(), it doesn't make much difference.)
711      FIXME: simulate mem-papped files. */
712
713   if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp))
714     if (INTUSE(_IO_switch_to_get_mode) (fp))
715       return EOF;
716
717   if (fp->_IO_buf_base == NULL)
718     {
719       /* It could be that we already have a pushback buffer.  */
720       if (fp->_IO_read_base != NULL)
721         {
722           free (fp->_IO_read_base);
723           fp->_flags &= ~_IO_IN_BACKUP;
724         }
725       INTUSE(_IO_doallocbuf) (fp);
726       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
727       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
728     }
729
730   switch (dir)
731     {
732     case _IO_seek_cur:
733       /* Adjust for read-ahead (bytes is buffer). */
734       offset -= fp->_IO_read_end - fp->_IO_read_ptr;
735       if (fp->_offset == _IO_pos_BAD)
736         goto dumb;
737       /* Make offset absolute, assuming current pointer is file_ptr(). */
738       offset += fp->_offset;
739
740       dir = _IO_seek_set;
741       break;
742     case _IO_seek_set:
743       break;
744     case _IO_seek_end:
745       {
746         struct _G_stat64 st;
747         if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
748           {
749             offset += st.st_size;
750             dir = _IO_seek_set;
751           }
752         else
753           goto dumb;
754       }
755     }
756   /* At this point, dir==_IO_seek_set. */
757
758   /* If we are only interested in the current position we've found it now.  */
759   if (mode == 0)
760     return offset;
761
762   /* If destination is within current buffer, optimize: */
763   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
764       && !_IO_in_backup (fp))
765     {
766       /* Offset relative to start of main get area. */
767       _IO_off64_t rel_offset = (offset - fp->_offset
768                                 + (fp->_IO_read_end - fp->_IO_read_base));
769       if (rel_offset >= 0)
770         {
771 #if 0
772           if (_IO_in_backup (fp))
773             _IO_switch_to_main_get_area (fp);
774 #endif
775           if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
776             {
777               _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
778                         fp->_IO_read_end);
779               _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
780               {
781                 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
782                 goto resync;
783               }
784             }
785 #ifdef TODO
786             /* If we have streammarkers, seek forward by reading ahead. */
787             if (_IO_have_markers (fp))
788               {
789                 int to_skip = rel_offset
790                   - (fp->_IO_read_ptr - fp->_IO_read_base);
791                 if (ignore (to_skip) != to_skip)
792                   goto dumb;
793                 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
794                 goto resync;
795               }
796 #endif
797         }
798 #ifdef TODO
799       if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
800         {
801           if (!_IO_in_backup (fp))
802             _IO_switch_to_backup_area (fp);
803           gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
804           _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
805           goto resync;
806         }
807 #endif
808     }
809
810 #ifdef TODO
811   INTUSE(_IO_unsave_markers) (fp);
812 #endif
813
814   if (fp->_flags & _IO_NO_READS)
815     goto dumb;
816
817   /* Try to seek to a block boundary, to improve kernel page management. */
818   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
819   delta = offset - new_offset;
820   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
821     {
822       new_offset = offset;
823       delta = 0;
824     }
825   result = _IO_SYSSEEK (fp, new_offset, 0);
826   if (result < 0)
827     return EOF;
828   if (delta == 0)
829     count = 0;
830   else
831     {
832       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
833                            (must_be_exact
834                             ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
835       if (count < delta)
836         {
837           /* We weren't allowed to read, but try to seek the remainder. */
838           offset = count == EOF ? delta : delta-count;
839           dir = _IO_seek_cur;
840           goto dumb;
841         }
842     }
843   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
844             fp->_IO_buf_base + count);
845   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
846   fp->_offset = result + count;
847   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
848   return offset;
849  dumb:
850
851   INTUSE(_IO_unsave_markers) (fp);
852   result = _IO_SYSSEEK (fp, offset, dir);
853   if (result != EOF)
854     {
855       _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
856       fp->_offset = result;
857       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
858       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
859     }
860   return result;
861
862 resync:
863   /* We need to do it since it is possible that the file offset in
864      the kernel may be changed behind our back. It may happen when
865      we fopen a file and then do a fork. One process may access the
866      the file and the kernel file offset will be changed. */
867   if (fp->_offset >= 0)
868     _IO_SYSSEEK (fp, fp->_offset, 0);
869
870   return offset;
871 }
872 INTDEF2(_IO_new_file_seekoff, _IO_file_seekoff)
873
874 _IO_off64_t
875 _IO_file_seekoff_mmap (fp, offset, dir, mode)
876      _IO_FILE *fp;
877      _IO_off64_t offset;
878      int dir;
879      int mode;
880 {
881   _IO_off64_t result;
882
883   if (mode == 0)
884     dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
885
886   switch (dir)
887     {
888     case _IO_seek_cur:
889       /* Adjust for read-ahead (bytes is buffer). */
890       offset += fp->_IO_read_ptr - fp->_IO_read_base;
891       break;
892     case _IO_seek_set:
893       break;
894     case _IO_seek_end:
895       offset += fp->_IO_buf_end - fp->_IO_buf_base;
896       break;
897     }
898   /* At this point, dir==_IO_seek_set. */
899
900   if (offset < 0)
901     /* No negative offsets are valid.  */
902     return EOF;
903
904   /* If we are only interested in the current position we've found it now.  */
905   if (mode == 0)
906     return offset;
907
908   result = _IO_SYSSEEK (fp, offset, 0);
909   if (result < 0)
910     return EOF;
911
912   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + offset,
913             fp->_IO_buf_base + offset);
914
915   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
916
917   return offset;
918 }
919
920 _IO_ssize_t
921 _IO_file_read (fp, buf, size)
922      _IO_FILE *fp;
923      void *buf;
924      _IO_ssize_t size;
925 {
926   return read (fp->_fileno, buf, size);
927 }
928 INTDEF(_IO_file_read)
929
930 _IO_off64_t
931 _IO_file_seek (fp, offset, dir)
932      _IO_FILE *fp;
933      _IO_off64_t offset;
934      int dir;
935 {
936 #ifdef _G_LSEEK64
937   return _G_LSEEK64 (fp->_fileno, offset, dir);
938 #else
939   return lseek (fp->_fileno, offset, dir);
940 #endif
941 }
942 INTDEF(_IO_file_seek)
943
944 int
945 _IO_file_stat (fp, st)
946      _IO_FILE *fp;
947      void *st;
948 {
949 #ifdef _G_FSTAT64
950   return _G_FSTAT64 (fp->_fileno, (struct _G_stat64 *) st);
951 #else
952   return fstat (fp->_fileno, (struct stat *) st);
953 #endif
954 }
955 INTDEF(_IO_file_stat)
956
957 int
958 _IO_file_close_mmap (fp)
959      _IO_FILE *fp;
960 {
961   /* In addition to closing the file descriptor we have to unmap the
962      file.  */
963   (void) munmap (fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base);
964   fp->_IO_buf_base = fp->_IO_buf_end = NULL;
965   return close (fp->_fileno);
966 }
967
968 int
969 _IO_file_close (fp)
970      _IO_FILE *fp;
971 {
972   return close (fp->_fileno);
973 }
974 INTDEF(_IO_file_close)
975
976 _IO_ssize_t
977 _IO_new_file_write (f, data, n)
978      _IO_FILE *f;
979      const void *data;
980      _IO_ssize_t n;
981 {
982   _IO_ssize_t to_do = n;
983   while (to_do > 0)
984     {
985       _IO_ssize_t count = write (f->_fileno, data, to_do);
986       if (count < 0)
987         {
988           f->_flags |= _IO_ERR_SEEN;
989           break;
990         }
991       to_do -= count;
992       data = (void *) ((char *) data + count);
993     }
994   n -= to_do;
995   if (f->_offset >= 0)
996     f->_offset += n;
997   return n;
998 }
999
1000 _IO_size_t
1001 _IO_new_file_xsputn (f, data, n)
1002      _IO_FILE *f;
1003      const void *data;
1004      _IO_size_t n;
1005 {
1006   register const char *s = (const char *) data;
1007   _IO_size_t to_do = n;
1008   int must_flush = 0;
1009   _IO_size_t count;
1010
1011   if (n <= 0)
1012     return 0;
1013   /* This is an optimized implementation.
1014      If the amount to be written straddles a block boundary
1015      (or the filebuf is unbuffered), use sys_write directly. */
1016
1017   /* First figure out how much space is available in the buffer. */
1018   count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
1019   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
1020     {
1021       count = f->_IO_buf_end - f->_IO_write_ptr;
1022       if (count >= n)
1023         {
1024           register const char *p;
1025           for (p = s + n; p > s; )
1026             {
1027               if (*--p == '\n')
1028                 {
1029                   count = p - s + 1;
1030                   must_flush = 1;
1031                   break;
1032                 }
1033             }
1034         }
1035     }
1036   /* Then fill the buffer. */
1037   if (count > 0)
1038     {
1039       if (count > to_do)
1040         count = to_do;
1041       if (count > 20)
1042         {
1043 #ifdef _LIBC
1044           f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
1045 #else
1046           memcpy (f->_IO_write_ptr, s, count);
1047           f->_IO_write_ptr += count;
1048 #endif
1049           s += count;
1050         }
1051       else
1052         {
1053           register char *p = f->_IO_write_ptr;
1054           register int i = (int) count;
1055           while (--i >= 0)
1056             *p++ = *s++;
1057           f->_IO_write_ptr = p;
1058         }
1059       to_do -= count;
1060     }
1061   if (to_do + must_flush > 0)
1062     {
1063       _IO_size_t block_size, do_write;
1064       /* Next flush the (full) buffer. */
1065       if (_IO_OVERFLOW (f, EOF) == EOF)
1066         return n - to_do;
1067
1068       /* Try to maintain alignment: write a whole number of blocks.
1069          dont_write is what gets left over. */
1070       block_size = f->_IO_buf_end - f->_IO_buf_base;
1071       do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
1072
1073       if (do_write)
1074         {
1075           count = new_do_write (f, s, do_write);
1076           to_do -= count;
1077           if (count < do_write)
1078             return n - to_do;
1079         }
1080
1081       /* Now write out the remainder.  Normally, this will fit in the
1082          buffer, but it's somewhat messier for line-buffered files,
1083          so we let _IO_default_xsputn handle the general case. */
1084       if (to_do)
1085         to_do -= INTUSE(_IO_default_xsputn) (f, s+do_write, to_do);
1086     }
1087   return n - to_do;
1088 }
1089 INTDEF2(_IO_new_file_xsputn, _IO_file_xsputn)
1090
1091 _IO_size_t
1092 _IO_file_xsgetn (fp, data, n)
1093      _IO_FILE *fp;
1094      void *data;
1095      _IO_size_t n;
1096 {
1097   register _IO_size_t want, have;
1098   register _IO_ssize_t count;
1099   register char *s = data;
1100
1101   want = n;
1102
1103   if (fp->_IO_buf_base == NULL)
1104     {
1105       /* Maybe we already have a push back pointer.  */
1106       if (fp->_IO_save_base != NULL)
1107         {
1108           free (fp->_IO_save_base);
1109           fp->_flags &= ~_IO_IN_BACKUP;
1110         }
1111       INTUSE(_IO_doallocbuf) (fp);
1112     }
1113
1114   while (want > 0)
1115     {
1116       have = fp->_IO_read_end - fp->_IO_read_ptr;
1117       if (want <= have)
1118         {
1119           memcpy (s, fp->_IO_read_ptr, want);
1120           fp->_IO_read_ptr += want;
1121           want = 0;
1122         }
1123       else
1124         {
1125           if (have > 0)
1126             {
1127 #ifdef _LIBC
1128               s = __mempcpy (s, fp->_IO_read_ptr, have);
1129 #else
1130               memcpy (s, fp->_IO_read_ptr, have);
1131               s += have;
1132 #endif
1133               want -= have;
1134               fp->_IO_read_ptr += have;
1135             }
1136
1137           /* Check for backup and repeat */
1138           if (_IO_in_backup (fp))
1139             {
1140               _IO_switch_to_main_get_area (fp);
1141               continue;
1142             }
1143
1144           /* If we now want less than a buffer, underflow and repeat
1145              the copy.  Otherwise, _IO_SYSREAD directly to
1146              the user buffer. */
1147           if (fp->_IO_buf_base && want < fp->_IO_buf_end - fp->_IO_buf_base)
1148             {
1149               if (__underflow (fp) == EOF)
1150                 break;
1151
1152               continue;
1153             }
1154
1155           /* These must be set before the sysread as we might longjmp out
1156              waiting for input. */
1157           _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
1158           _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
1159
1160           /* Try to maintain alignment: read a whole number of blocks.  */
1161           count = want;
1162           if (fp->_IO_buf_base)
1163             {
1164               _IO_size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base;
1165               if (block_size >= 128)
1166                 count -= want % block_size;
1167             }
1168
1169           count = _IO_SYSREAD (fp, s, count);
1170           if (count <= 0)
1171             {
1172               if (count == 0)
1173                 fp->_flags |= _IO_EOF_SEEN;
1174               else
1175                 fp->_flags |= _IO_ERR_SEEN;
1176
1177               break;
1178             }
1179
1180           s += count;
1181           want -= count;
1182           if (fp->_offset != _IO_pos_BAD)
1183             _IO_pos_adjust (fp->_offset, count);
1184         }
1185     }
1186
1187   return n - want;
1188 }
1189 INTDEF(_IO_file_xsgetn)
1190
1191 static _IO_size_t _IO_file_xsgetn_mmap __P ((_IO_FILE *, void *, _IO_size_t));
1192 static _IO_size_t
1193 _IO_file_xsgetn_mmap (fp, data, n)
1194      _IO_FILE *fp;
1195      void *data;
1196      _IO_size_t n;
1197 {
1198   register _IO_size_t have;
1199   char *read_ptr = fp->_IO_read_ptr;
1200
1201   have = fp->_IO_read_end - fp->_IO_read_ptr;
1202
1203   if (have < n)
1204     {
1205       /* Maybe the read buffer is not yet fully set up.  */
1206       fp->_IO_read_ptr = fp->_IO_read_end;
1207       if (fp->_IO_read_end < fp->_IO_buf_end
1208           && _IO_file_underflow_mmap (fp) != EOF)
1209         have = fp->_IO_read_end - read_ptr;
1210     }
1211
1212   if (have == 0)
1213     fp->_flags |= _IO_EOF_SEEN;
1214   else
1215     {
1216       have = MIN (have, n);
1217       memcpy (data, read_ptr, have);
1218       fp->_IO_read_ptr = read_ptr + have;
1219     }
1220
1221   return have;
1222 }
1223
1224 struct _IO_jump_t _IO_file_jumps =
1225 {
1226   JUMP_INIT_DUMMY,
1227   JUMP_INIT(finish, INTUSE(_IO_file_finish)),
1228   JUMP_INIT(overflow, INTUSE(_IO_file_overflow)),
1229   JUMP_INIT(underflow, INTUSE(_IO_file_underflow)),
1230   JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
1231   JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
1232   JUMP_INIT(xsputn, INTUSE(_IO_file_xsputn)),
1233   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
1234   JUMP_INIT(seekoff, _IO_new_file_seekoff),
1235   JUMP_INIT(seekpos, _IO_default_seekpos),
1236   JUMP_INIT(setbuf, _IO_new_file_setbuf),
1237   JUMP_INIT(sync, _IO_new_file_sync),
1238   JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
1239   JUMP_INIT(read, INTUSE(_IO_file_read)),
1240   JUMP_INIT(write, _IO_new_file_write),
1241   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
1242   JUMP_INIT(close, INTUSE(_IO_file_close)),
1243   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
1244   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1245   JUMP_INIT(imbue, _IO_default_imbue)
1246 };
1247 INTDEF(_IO_file_jumps)
1248
1249 struct _IO_jump_t _IO_file_jumps_mmap =
1250 {
1251   JUMP_INIT_DUMMY,
1252   JUMP_INIT(finish, INTUSE(_IO_file_finish)),
1253   JUMP_INIT(overflow, INTUSE(_IO_file_overflow)),
1254   JUMP_INIT(underflow, _IO_file_underflow_mmap),
1255   JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
1256   JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
1257   JUMP_INIT(xsputn, _IO_new_file_xsputn),
1258   JUMP_INIT(xsgetn, _IO_file_xsgetn_mmap),
1259   JUMP_INIT(seekoff, _IO_file_seekoff_mmap),
1260   JUMP_INIT(seekpos, _IO_default_seekpos),
1261   JUMP_INIT(setbuf, _IO_new_file_setbuf),
1262   JUMP_INIT(sync, _IO_new_file_sync),
1263   JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
1264   JUMP_INIT(read, INTUSE(_IO_file_read)),
1265   JUMP_INIT(write, _IO_new_file_write),
1266   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
1267   JUMP_INIT(close, _IO_file_close_mmap),
1268   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
1269   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1270   JUMP_INIT(imbue, _IO_default_imbue)
1271 };
1272
1273 #ifdef _LIBC
1274 versioned_symbol (libc, _IO_new_do_write, _IO_do_write, GLIBC_2_1);
1275 versioned_symbol (libc, _IO_new_file_attach, _IO_file_attach, GLIBC_2_1);
1276 versioned_symbol (libc, _IO_new_file_close_it, _IO_file_close_it, GLIBC_2_1);
1277 versioned_symbol (libc, _IO_new_file_finish, _IO_file_finish, GLIBC_2_1);
1278 versioned_symbol (libc, _IO_new_file_fopen, _IO_file_fopen, GLIBC_2_1);
1279 versioned_symbol (libc, _IO_new_file_init, _IO_file_init, GLIBC_2_1);
1280 versioned_symbol (libc, _IO_new_file_setbuf, _IO_file_setbuf, GLIBC_2_1);
1281 versioned_symbol (libc, _IO_new_file_sync, _IO_file_sync, GLIBC_2_1);
1282 versioned_symbol (libc, _IO_new_file_overflow, _IO_file_overflow, GLIBC_2_1);
1283 versioned_symbol (libc, _IO_new_file_seekoff, _IO_file_seekoff, GLIBC_2_1);
1284 versioned_symbol (libc, _IO_new_file_underflow, _IO_file_underflow, GLIBC_2_1);
1285 versioned_symbol (libc, _IO_new_file_write, _IO_file_write, GLIBC_2_1);
1286 versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1);
1287 #endif