1/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
2   This file is part of the GNU IO Library.
3
4   This library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU General Public License as
6   published by the Free Software Foundation; either version 2, or (at
7   your option) any later version.
8
9   This library is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this library; see the file COPYING.  If not, write to
16   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
17   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
21   not cause the resulting executable to be covered by the GNU General
22   Public License.  This exception does not however invalidate any
23   other reasons why the executable file might be covered by the GNU
24   General Public License.  */
25
26/* Generic or default I/O operations. */
27
28#include "libioP.h"
29#ifdef __STDC__
30#include <stdlib.h>
31#endif
32#include <string.h>
33
34void
35_IO_un_link (fp)
36     _IO_FILE *fp;
37{
38  if (fp->_flags & _IO_LINKED)
39    {
40      _IO_FILE **f;
41      for (f = &_IO_list_all; *f != NULL; f = &(*f)->_chain)
42	{
43	  if (*f == fp)
44	    {
45	      *f = fp->_chain;
46	      break;
47	    }
48	}
49      fp->_flags &= ~_IO_LINKED;
50    }
51}
52
53void
54_IO_link_in (fp)
55     _IO_FILE *fp;
56{
57    if ((fp->_flags & _IO_LINKED) == 0)
58      {
59	fp->_flags |= _IO_LINKED;
60	fp->_chain = _IO_list_all;
61	_IO_list_all = fp;
62      }
63}
64
65/* Return minimum _pos markers
66   Assumes the current get area is the main get area. */
67static _IO_size_t _IO_least_marker __P ((_IO_FILE *fp));
68
69static _IO_size_t
70_IO_least_marker (fp)
71     _IO_FILE *fp;
72{
73  _IO_ssize_t least_so_far = fp->_IO_read_end - fp->_IO_read_base;
74  struct _IO_marker *mark;
75  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
76    if (mark->_pos < least_so_far)
77      least_so_far = mark->_pos;
78  return least_so_far;
79}
80
81/* Switch current get area from backup buffer to (start of) main get area. */
82
83void
84_IO_switch_to_main_get_area (fp)
85     _IO_FILE *fp;
86{
87  char *tmp;
88  fp->_flags &= ~_IO_IN_BACKUP;
89  /* Swap _IO_read_end and _IO_save_end. */
90  tmp = fp->_IO_read_end;
91  fp->_IO_read_end = fp->_IO_save_end;
92  fp->_IO_save_end= tmp;
93  /* Swap _IO_read_base and _IO_save_base. */
94  tmp = fp->_IO_read_base;
95  fp->_IO_read_base = fp->_IO_save_base;
96  fp->_IO_save_base = tmp;
97
98  fp->_IO_read_ptr = fp->_IO_read_base;
99}
100
101/* Switch current get area from main get area to (end of) backup area. */
102
103void
104_IO_switch_to_backup_area (fp)
105     _IO_FILE *fp;
106{
107  char *tmp;
108  fp->_flags |= _IO_IN_BACKUP;
109  /* Swap _IO_read_end and _IO_save_end. */
110  tmp = fp->_IO_read_end;
111  fp->_IO_read_end = fp->_IO_save_end;
112  fp->_IO_save_end = tmp;
113  /* Swap _gbase and _IO_save_base. */
114  tmp = fp->_IO_read_base;
115  fp->_IO_read_base = fp->_IO_save_base;
116  fp->_IO_save_base = tmp;
117
118  fp->_IO_read_ptr = fp->_IO_read_end;
119}
120
121int
122_IO_switch_to_get_mode (fp)
123     _IO_FILE *fp;
124{
125  if (fp->_IO_write_ptr > fp->_IO_write_base)
126    if (_IO_OVERFLOW (fp, EOF) == EOF)
127      return EOF;
128  if (_IO_in_backup (fp))
129    fp->_IO_read_base = fp->_IO_backup_base;
130  else
131    {
132      fp->_IO_read_base = fp->_IO_buf_base;
133      if (fp->_IO_write_ptr > fp->_IO_read_end)
134	fp->_IO_read_end = fp->_IO_write_ptr;
135    }
136  fp->_IO_read_ptr = fp->_IO_write_ptr;
137
138  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = fp->_IO_read_ptr;
139
140  fp->_flags &= ~_IO_CURRENTLY_PUTTING;
141  return 0;
142}
143
144void
145_IO_free_backup_area (fp)
146     _IO_FILE *fp;
147{
148  if (_IO_in_backup (fp))
149    _IO_switch_to_main_get_area (fp);  /* Just in case. */
150  free (fp->_IO_save_base);
151  fp->_IO_save_base = NULL;
152  fp->_IO_save_end = NULL;
153  fp->_IO_backup_base = NULL;
154}
155
156#if 0
157int
158_IO_switch_to_put_mode (fp)
159     _IO_FILE *fp;
160{
161  fp->_IO_write_base = fp->_IO_read_ptr;
162  fp->_IO_write_ptr = fp->_IO_read_ptr;
163  /* Following is wrong if line- or un-buffered? */
164  fp->_IO_write_end = (fp->_flags & _IO_IN_BACKUP
165		       ? fp->_IO_read_end : fp->_IO_buf_end);
166
167  fp->_IO_read_ptr = fp->_IO_read_end;
168  fp->_IO_read_base = fp->_IO_read_end;
169
170  fp->_flags |= _IO_CURRENTLY_PUTTING;
171  return 0;
172}
173#endif
174
175int
176__overflow (f, ch)
177     _IO_FILE *f;
178     int ch;
179{
180  return _IO_OVERFLOW (f, ch);
181}
182
183static int save_for_backup __P ((_IO_FILE *fp));
184
185     static int
186save_for_backup (fp)
187     _IO_FILE *fp;
188{
189  /* Append [_IO_read_base.._IO_read_end] to backup area. */
190  int least_mark = _IO_least_marker (fp);
191  /* needed_size is how much space we need in the backup area. */
192  int needed_size = (fp->_IO_read_end - fp->_IO_read_base) - least_mark;
193  int current_Bsize = fp->_IO_save_end - fp->_IO_save_base;
194  int avail; /* Extra space available for future expansion. */
195  int delta;
196  struct _IO_marker *mark;
197  if (needed_size > current_Bsize)
198    {
199      char *new_buffer;
200      avail = 100;
201      new_buffer = (char *) malloc (avail + needed_size);
202      if (new_buffer == NULL)
203	return EOF;		/* FIXME */
204      if (least_mark < 0)
205	{
206	  memcpy (new_buffer + avail,
207		  fp->_IO_save_end + least_mark,
208		  -least_mark);
209	  memcpy (new_buffer + avail - least_mark,
210		  fp->_IO_read_base,
211		  fp->_IO_read_end - fp->_IO_read_base);
212	}
213      else
214	memcpy (new_buffer + avail,
215		fp->_IO_read_base + least_mark,
216		needed_size);
217      if (fp->_IO_save_base)
218	free (fp->_IO_save_base);
219      fp->_IO_save_base = new_buffer;
220      fp->_IO_save_end = new_buffer + avail + needed_size;
221    }
222  else
223    {
224      avail = current_Bsize - needed_size;
225      if (least_mark < 0)
226	{
227	  memmove (fp->_IO_save_base + avail,
228		   fp->_IO_save_end + least_mark,
229		   -least_mark);
230	  memcpy (fp->_IO_save_base + avail - least_mark,
231		  fp->_IO_read_base,
232		  fp->_IO_read_end - fp->_IO_read_base);
233	}
234      else if (needed_size > 0)
235	memcpy (fp->_IO_save_base + avail,
236		fp->_IO_read_base + least_mark,
237		needed_size);
238    }
239  /* FIXME: Dubious arithmetic if pointers are NULL */
240  fp->_IO_backup_base = fp->_IO_save_base + avail;
241  /* Adjust all the streammarkers. */
242  delta = fp->_IO_read_end - fp->_IO_read_base;
243  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
244    mark->_pos -= delta;
245  return 0;
246}
247
248int
249__underflow (fp)
250     _IO_FILE *fp;
251{
252  if (_IO_in_put_mode (fp))
253    if (_IO_switch_to_get_mode (fp) == EOF)
254      return EOF;
255  if (fp->_IO_read_ptr < fp->_IO_read_end)
256    return *(unsigned char *) fp->_IO_read_ptr;
257  if (_IO_in_backup (fp))
258    {
259      _IO_switch_to_main_get_area (fp);
260      if (fp->_IO_read_ptr < fp->_IO_read_end)
261	return *(unsigned char *) fp->_IO_read_ptr;
262    }
263  if (_IO_have_markers (fp))
264    {
265      if (save_for_backup (fp))
266	return EOF;
267    }
268  else if (_IO_have_backup (fp))
269    _IO_free_backup_area (fp);
270  return _IO_UNDERFLOW (fp);
271}
272
273int
274__uflow (fp)
275     _IO_FILE *fp;
276{
277  if (_IO_in_put_mode (fp))
278    if (_IO_switch_to_get_mode (fp) == EOF)
279      return EOF;
280  if (fp->_IO_read_ptr < fp->_IO_read_end)
281    return *(unsigned char *) fp->_IO_read_ptr++;
282  if (_IO_in_backup (fp))
283    {
284      _IO_switch_to_main_get_area (fp);
285      if (fp->_IO_read_ptr < fp->_IO_read_end)
286	return *(unsigned char *) fp->_IO_read_ptr++;
287    }
288  if (_IO_have_markers (fp))
289    {
290      if (save_for_backup (fp))
291	return EOF;
292    }
293  else if (_IO_have_backup (fp))
294    _IO_free_backup_area (fp);
295  return _IO_UFLOW (fp);
296}
297
298void
299_IO_setb (f, b, eb, a)
300     _IO_FILE *f;
301      char *b;
302     char *eb;
303     int a;
304{
305  if (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF))
306    FREE_BUF (f->_IO_buf_base, _IO_blen (f));
307  f->_IO_buf_base = b;
308  f->_IO_buf_end = eb;
309  if (a)
310    f->_flags &= ~_IO_USER_BUF;
311  else
312    f->_flags |= _IO_USER_BUF;
313}
314
315void
316_IO_doallocbuf (fp)
317     _IO_FILE *fp;
318{
319  if (fp->_IO_buf_base)
320    return;
321  if (!(fp->_flags & _IO_UNBUFFERED))
322    if (_IO_DOALLOCATE (fp) != EOF)
323      return;
324  _IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
325}
326
327int
328_IO_default_underflow (fp)
329     _IO_FILE *fp;
330{
331  return EOF;
332}
333
334int
335_IO_default_uflow (fp)
336     _IO_FILE *fp;
337{
338  int ch = _IO_UNDERFLOW (fp);
339  if (ch == EOF)
340    return EOF;
341  return *(unsigned char *) fp->_IO_read_ptr++;
342}
343
344_IO_size_t
345_IO_default_xsputn (f, data, n)
346     _IO_FILE *f;
347     const void *data;
348     _IO_size_t n;
349{
350  const char *s = (char *) data;
351  _IO_size_t more = n;
352  if (more <= 0)
353    return 0;
354  for (;;)
355    {
356      /* Space available. */
357      _IO_ssize_t count = f->_IO_write_end - f->_IO_write_ptr;
358      if (count > 0)
359	{
360	  if ((_IO_size_t) count > more)
361	    count = more;
362	  if (count > 20)
363	    {
364	      memcpy (f->_IO_write_ptr, s, count);
365	      s += count;
366	      f->_IO_write_ptr += count;
367            }
368	  else if (count <= 0)
369	    count = 0;
370	  else
371	    {
372	      char *p = f->_IO_write_ptr;
373	      _IO_ssize_t i;
374	      for (i = count; --i >= 0; )
375		*p++ = *s++;
376	      f->_IO_write_ptr = p;
377            }
378	  more -= count;
379        }
380      if (more == 0 || __overflow (f, (unsigned char) *s++) == EOF)
381	break;
382      more--;
383    }
384  return n - more;
385}
386
387_IO_size_t
388_IO_sgetn (fp, data, n)
389     _IO_FILE *fp;
390     void *data;
391     _IO_size_t n;
392{
393  /* FIXME handle putback buffer here! */
394  return _IO_XSGETN (fp, data, n);
395}
396
397_IO_size_t
398_IO_default_xsgetn (fp, data, n)
399     _IO_FILE *fp;
400     void *data;
401     _IO_size_t n;
402{
403  _IO_size_t more = n;
404  char *s = (char*) data;
405  for (;;)
406    {
407      /* Data available. */
408      _IO_ssize_t count = fp->_IO_read_end - fp->_IO_read_ptr;
409      if (count > 0)
410	{
411	  if ((_IO_size_t) count > more)
412	    count = more;
413	  if (count > 20)
414	    {
415	      memcpy (s, fp->_IO_read_ptr, count);
416	      s += count;
417	      fp->_IO_read_ptr += count;
418	    }
419	  else if (count <= 0)
420	    count = 0;
421	  else
422	    {
423	      char *p = fp->_IO_read_ptr;
424	      int i = (int) count;
425	      while (--i >= 0)
426		*s++ = *p++;
427	      fp->_IO_read_ptr = p;
428            }
429            more -= count;
430        }
431      if (more == 0 || __underflow (fp) == EOF)
432	break;
433    }
434  return n - more;
435}
436
437#if 0
438/* Seems not to be needed. --drepper */
439int
440_IO_sync (fp)
441     _IO_FILE *fp;
442{
443  return 0;
444}
445#endif
446
447_IO_FILE *
448_IO_default_setbuf (fp, p, len)
449     _IO_FILE *fp;
450     char *p;
451     _IO_ssize_t len;
452{
453    if (_IO_SYNC (fp) == EOF)
454	return NULL;
455    if (p == NULL || len == 0)
456      {
457	fp->_flags |= _IO_UNBUFFERED;
458	_IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
459      }
460    else
461      {
462	fp->_flags &= ~_IO_UNBUFFERED;
463	_IO_setb (fp, p, p+len, 0);
464      }
465    fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = 0;
466    fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end = 0;
467    return fp;
468}
469
470_IO_pos_t
471_IO_default_seekpos (fp, pos, mode)
472     _IO_FILE *fp;
473     _IO_pos_t pos;
474     int mode;
475{
476  return _IO_SEEKOFF (fp, _IO_pos_as_off (pos), 0, mode);
477}
478
479int
480_IO_default_doallocate (fp)
481     _IO_FILE *fp;
482{
483  char *buf;
484
485  ALLOC_BUF (buf, _IO_BUFSIZ, EOF);
486  _IO_setb (fp, buf, buf+_IO_BUFSIZ, 1);
487  return 1;
488}
489
490void
491_IO_init (fp, flags)
492     _IO_FILE *fp;
493     int flags;
494{
495  fp->_flags = _IO_MAGIC|flags;
496  fp->_IO_buf_base = NULL;
497  fp->_IO_buf_end = NULL;
498  fp->_IO_read_base = NULL;
499  fp->_IO_read_ptr = NULL;
500  fp->_IO_read_end = NULL;
501  fp->_IO_write_base = NULL;
502  fp->_IO_write_ptr = NULL;
503  fp->_IO_write_end = NULL;
504  fp->_chain = NULL; /* Not necessary. */
505
506  fp->_IO_save_base = NULL;
507  fp->_IO_backup_base = NULL;
508  fp->_IO_save_end = NULL;
509  fp->_markers = NULL;
510  fp->_cur_column = 0;
511#ifdef _IO_MTSAFE_IO
512  _IO_lock_init (*fp->_lock);
513#endif
514}
515
516int
517_IO_default_sync (fp)
518     _IO_FILE *fp;
519{
520  return 0;
521}
522
523/* The way the C++ classes are mapped into the C functions in the
524   current implementation, this function can get called twice! */
525
526void
527_IO_default_finish (fp, dummy)
528     _IO_FILE *fp;
529     int dummy;
530{
531  struct _IO_marker *mark;
532  if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
533    {
534      FREE_BUF (fp->_IO_buf_base, _IO_blen (fp));
535      fp->_IO_buf_base = fp->_IO_buf_end = NULL;
536    }
537
538  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
539    mark->_sbuf = NULL;
540
541  if (fp->_IO_save_base)
542    {
543      free (fp->_IO_save_base);
544      fp->_IO_save_base = NULL;
545    }
546
547#ifdef _IO_MTSAFE_IO
548  _IO_lock_fini (*fp->_lock);
549#endif
550
551  _IO_un_link (fp);
552}
553
554_IO_pos_t
555_IO_default_seekoff (fp, offset, dir, mode)
556     _IO_FILE *fp;
557     _IO_off_t offset;
558     int dir;
559     int mode;
560{
561    return _IO_pos_BAD;
562}
563
564int
565_IO_sputbackc (fp, c)
566     _IO_FILE *fp;
567     int c;
568{
569  int result;
570
571  if (fp->_IO_read_ptr > fp->_IO_read_base
572      && (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
573    {
574      fp->_IO_read_ptr--;
575      result = (unsigned char) c;
576    }
577  else
578    result = _IO_PBACKFAIL (fp, c);
579
580  if (result != EOF)
581    fp->_flags &= ~_IO_EOF_SEEN;
582
583  return result;
584}
585
586int
587_IO_sungetc (fp)
588     _IO_FILE *fp;
589{
590  int result;
591
592  if (fp->_IO_read_ptr > fp->_IO_read_base)
593    {
594      fp->_IO_read_ptr--;
595      result = (unsigned char) *fp->_IO_read_ptr;
596    }
597  else
598    result = _IO_PBACKFAIL (fp, EOF);
599
600  if (result != EOF)
601    fp->_flags &= ~_IO_EOF_SEEN;
602
603  return result;
604}
605
606#if 0 /* Work in progress */
607/* Seems not to be needed.  */
608#if 0
609void
610_IO_set_column (fp, c)
611     _IO_FILE *fp;
612     int c;
613{
614  if (c == -1)
615    fp->_column = -1;
616  else
617    fp->_column = c - (fp->_IO_write_ptr - fp->_IO_write_base);
618}
619#else
620int
621_IO_set_column (fp, i)
622     _IO_FILE *fp;
623     int i;
624{
625  fp->_cur_column = i + 1;
626  return 0;
627}
628#endif
629#endif
630
631
632unsigned
633_IO_adjust_column (start, line, count)
634     unsigned start;
635     const char *line;
636     int count;
637{
638  const char *ptr = line + count;
639  while (ptr > line)
640    if (*--ptr == '\n')
641      return line + count - ptr - 1;
642  return start + count;
643}
644
645#if 0
646/* Seems not to be needed. --drepper */
647int
648_IO_get_column (fp)
649     _IO_FILE *fp;
650{
651  if (fp->_cur_column)
652    return _IO_adjust_column (fp->_cur_column - 1,
653			      fp->_IO_write_base,
654			      fp->_IO_write_ptr - fp->_IO_write_base);
655  return -1;
656}
657#endif
658
659int
660_IO_flush_all ()
661{
662  int result = 0;
663  _IO_FILE *fp;
664  for (fp = _IO_list_all; fp != NULL; fp = fp->_chain)
665    if (fp->_IO_write_ptr > fp->_IO_write_base
666	&& _IO_OVERFLOW (fp, EOF) == EOF)
667      result = EOF;
668  return result;
669}
670
671void
672_IO_flush_all_linebuffered ()
673{
674  _IO_FILE *fp;
675  for (fp = _IO_list_all; fp != NULL; fp = fp->_chain)
676    if ((fp->_flags & _IO_NO_WRITES) == 0 && fp->_flags & _IO_LINE_BUF)
677      _IO_OVERFLOW (fp, EOF);
678}
679
680static void _IO_unbuffer_all __P ((void));
681
682static void
683_IO_unbuffer_all ()
684{
685  _IO_FILE *fp;
686  for (fp = _IO_list_all; fp != NULL; fp = fp->_chain)
687    if (! (fp->_flags & _IO_UNBUFFERED))
688      _IO_SETBUF (fp, NULL, 0);
689}
690
691void
692_IO_cleanup ()
693{
694  _IO_flush_all ();
695
696  /* We currently don't have a reliable mechanism for making sure that
697     C++ static destructors are executed in the correct order.
698     So it is possible that other static destructors might want to
699     write to cout - and they're supposed to be able to do so.
700
701     The following will make the standard streambufs be unbuffered,
702     which forces any output from late destructors to be written out. */
703  _IO_unbuffer_all ();
704}
705
706void
707_IO_init_marker (marker, fp)
708     struct _IO_marker *marker;
709     _IO_FILE *fp;
710{
711  marker->_sbuf = fp;
712  if (_IO_in_put_mode (fp))
713    _IO_switch_to_get_mode (fp);
714  if (_IO_in_backup (fp))
715    marker->_pos = fp->_IO_read_ptr - fp->_IO_read_end;
716  else
717    marker->_pos = fp->_IO_read_ptr - fp->_IO_read_base;
718
719  /* Should perhaps sort the chain? */
720  marker->_next = fp->_markers;
721  fp->_markers = marker;
722}
723
724void
725_IO_remove_marker (marker)
726     struct _IO_marker *marker;
727{
728  /* Unlink from sb's chain. */
729  struct _IO_marker **ptr = &marker->_sbuf->_markers;
730  for (; ; ptr = &(*ptr)->_next)
731    {
732      if (*ptr == NULL)
733	break;
734      else if (*ptr == marker)
735	{
736	  *ptr = marker->_next;
737	  return;
738	}
739    }
740#if 0
741    if _sbuf has a backup area that is no longer needed, should we delete
742    it now, or wait until the next underflow?
743#endif
744}
745
746#define BAD_DELTA EOF
747
748int
749_IO_marker_difference (mark1, mark2)
750     struct _IO_marker *mark1;
751     struct _IO_marker *mark2;
752{
753  return mark1->_pos - mark2->_pos;
754}
755
756/* Return difference between MARK and current position of MARK's stream. */
757int
758_IO_marker_delta (mark)
759     struct _IO_marker *mark;
760{
761  int cur_pos;
762  if (mark->_sbuf == NULL)
763    return BAD_DELTA;
764  if (_IO_in_backup (mark->_sbuf))
765    cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_end;
766  else
767    cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_base;
768  return mark->_pos - cur_pos;
769}
770
771int
772_IO_seekmark (fp, mark, delta)
773     _IO_FILE *fp;
774     struct _IO_marker *mark;
775     int delta;
776{
777  if (mark->_sbuf != fp)
778    return EOF;
779 if (mark->_pos >= 0)
780    {
781      if (_IO_in_backup (fp))
782	_IO_switch_to_main_get_area (fp);
783      fp->_IO_read_ptr = fp->_IO_read_base + mark->_pos;
784    }
785  else
786    {
787      if (!_IO_in_backup (fp))
788	_IO_switch_to_backup_area (fp);
789      fp->_IO_read_ptr = fp->_IO_read_end + mark->_pos;
790    }
791  return 0;
792}
793
794void
795_IO_unsave_markers (fp)
796     _IO_FILE *fp;
797{
798  struct _IO_marker *mark = fp->_markers;
799  if (mark)
800    {
801#ifdef TODO
802      streampos offset = seekoff (0, ios::cur, ios::in);
803      if (offset != EOF)
804	{
805	  offset += eGptr () - Gbase ();
806	  for ( ; mark != NULL; mark = mark->_next)
807	    mark->set_streampos (mark->_pos + offset);
808	}
809    else
810      {
811	for ( ; mark != NULL; mark = mark->_next)
812	  mark->set_streampos (EOF);
813      }
814#endif
815      fp->_markers = 0;
816    }
817
818  if (_IO_have_backup (fp))
819    _IO_free_backup_area (fp);
820}
821
822#if 0
823/* Seems not to be needed. --drepper */
824int
825_IO_nobackup_pbackfail (fp, c)
826     _IO_FILE *fp;
827     int c;
828{
829  if (fp->_IO_read_ptr > fp->_IO_read_base)
830	fp->_IO_read_ptr--;
831  if (c != EOF && *fp->_IO_read_ptr != c)
832      *fp->_IO_read_ptr = c;
833  return (unsigned char) c;
834}
835#endif
836
837int
838_IO_default_pbackfail (fp, c)
839     _IO_FILE *fp;
840     int c;
841{
842  if (fp->_IO_read_ptr <= fp->_IO_read_base)
843    {
844      /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
845      if (_IO_have_backup (fp) && !_IO_in_backup (fp))
846	_IO_switch_to_backup_area (fp);
847
848      if (!_IO_have_backup (fp))
849	{
850	  /* No backup buffer: allocate one. */
851	  /* Use nshort buffer, if unused? (probably not)  FIXME */
852	  int backup_size = 128;
853	  char *bbuf = (char *) malloc (backup_size);
854	  if (bbuf == NULL)
855	    return EOF;
856	  fp->_IO_save_base = bbuf;
857	  fp->_IO_save_end = fp->_IO_save_base + backup_size;
858	  fp->_IO_backup_base = fp->_IO_save_end;
859	  _IO_switch_to_backup_area (fp);
860	}
861      else if (fp->_IO_read_ptr <= fp->_IO_read_base)
862	{
863	  /* Increase size of existing backup buffer. */
864	  _IO_size_t new_size;
865	  _IO_size_t old_size = fp->_IO_read_end - fp->_IO_read_base;
866	  char *new_buf;
867	  new_size = 2 * old_size;
868	  new_buf = (char *) malloc (new_size);
869	  if (new_buf == NULL)
870	    return EOF;
871	  memcpy (new_buf + (new_size - old_size), fp->_IO_read_base,
872		  old_size);
873	  free (fp->_IO_read_base);
874	  _IO_setg (fp, new_buf, new_buf + (new_size - old_size),
875		    new_buf + new_size);
876	  fp->_IO_backup_base = fp->_IO_read_ptr;
877	}
878    }
879  --fp->_IO_read_ptr;
880  if (c != EOF && *fp->_IO_read_ptr != c)
881    *fp->_IO_read_ptr = c;
882  return (unsigned char) *fp->_IO_read_ptr;
883}
884
885_IO_pos_t
886_IO_default_seek (fp, offset, dir)
887     _IO_FILE *fp;
888     _IO_off_t offset;
889     int dir;
890{
891  return _IO_pos_BAD;
892}
893
894int
895_IO_default_stat (fp, st)
896     _IO_FILE *fp;
897     void* st;
898{
899  return EOF;
900}
901
902_IO_ssize_t
903_IO_default_read (fp, data, n)
904     _IO_FILE* fp;
905     void *data;
906     _IO_ssize_t n;
907{
908  return -1;
909}
910
911_IO_ssize_t
912_IO_default_write (fp, data, n)
913     _IO_FILE *fp;
914     const void *data;
915     _IO_ssize_t n;
916{
917  return 0;
918}
919
920
921#ifdef TODO
922#if defined(linux)
923#define IO_CLEANUP ;
924#endif
925
926#ifdef IO_CLEANUP
927  IO_CLEANUP
928#else
929struct __io_defs {
930    __io_defs() { }
931    ~__io_defs() { _IO_cleanup (); }
932};
933__io_defs io_defs__;
934#endif
935
936#endif /* TODO */
937
938#ifdef weak_alias
939weak_alias (_IO_cleanup, _cleanup)
940#elif defined(_G_STDIO_USES_LIBIO) && defined(_G_HAVE_WEAK_SYMBOL)
941void _cleanup () __attribute__ ((weak, alias ("_IO_cleanup")));
942#endif
943
944#ifdef text_set_element
945text_set_element(__libc_atexit, _cleanup);
946#endif
947