1/* Copyright (C) 1993, 1995, 1997-1999, 2000 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
34#ifdef _IO_MTSAFE_IO
35static _IO_lock_t list_all_lock = _IO_lock_initializer;
36#endif
37
38void
39_IO_un_link (fp)
40     struct _IO_FILE_plus *fp;
41{
42  if (fp->file._flags & _IO_LINKED)
43    {
44      struct _IO_FILE_plus **f;
45#ifdef _IO_MTSAFE_IO
46      _IO_lock_lock (list_all_lock);
47#endif
48      for (f = &_IO_list_all; *f; f = (struct _IO_FILE_plus **) &(*f)->file._chain)
49	{
50	  if (*f == fp)
51	    {
52	      *f = (struct _IO_FILE_plus *) fp->file._chain;
53	      break;
54	    }
55	}
56#ifdef _IO_MTSAFE_IO
57      _IO_lock_unlock (list_all_lock);
58#endif
59      fp->file._flags &= ~_IO_LINKED;
60    }
61}
62
63void
64_IO_link_in (fp)
65     struct _IO_FILE_plus *fp;
66{
67    if ((fp->file._flags & _IO_LINKED) == 0)
68      {
69	fp->file._flags |= _IO_LINKED;
70#ifdef _IO_MTSAFE_IO
71	_IO_lock_lock (list_all_lock);
72#endif
73	fp->file._chain = (_IO_FILE *) _IO_list_all;
74	_IO_list_all = fp;
75#ifdef _IO_MTSAFE_IO
76	_IO_lock_unlock (list_all_lock);
77#endif
78      }
79}
80
81/* Return minimum _pos markers
82   Assumes the current get area is the main get area. */
83_IO_ssize_t _IO_least_marker __P ((_IO_FILE *fp, char *end_p));
84
85_IO_ssize_t
86_IO_least_marker (fp, end_p)
87     _IO_FILE *fp;
88     char *end_p;
89{
90  _IO_ssize_t least_so_far = end_p - fp->_IO_read_base;
91  struct _IO_marker *mark;
92  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
93    if (mark->_pos < least_so_far)
94      least_so_far = mark->_pos;
95  return least_so_far;
96}
97
98/* Switch current get area from backup buffer to (start of) main get area. */
99
100void
101_IO_switch_to_main_get_area (fp)
102     _IO_FILE *fp;
103{
104  char *tmp;
105  fp->_flags &= ~_IO_IN_BACKUP;
106  /* Swap _IO_read_end and _IO_save_end. */
107  tmp = fp->_IO_read_end;
108  fp->_IO_read_end = fp->_IO_save_end;
109  fp->_IO_save_end= tmp;
110  /* Swap _IO_read_base and _IO_save_base. */
111  tmp = fp->_IO_read_base;
112  fp->_IO_read_base = fp->_IO_save_base;
113  fp->_IO_save_base = tmp;
114  /* Set _IO_read_ptr. */
115  fp->_IO_read_ptr = fp->_IO_read_base;
116}
117
118/* Switch current get area from main get area to (end of) backup area. */
119
120void
121_IO_switch_to_backup_area (fp)
122     _IO_FILE *fp;
123{
124  char *tmp;
125  fp->_flags |= _IO_IN_BACKUP;
126  /* Swap _IO_read_end and _IO_save_end. */
127  tmp = fp->_IO_read_end;
128  fp->_IO_read_end = fp->_IO_save_end;
129  fp->_IO_save_end = tmp;
130  /* Swap _IO_read_base and _IO_save_base. */
131  tmp = fp->_IO_read_base;
132  fp->_IO_read_base = fp->_IO_save_base;
133  fp->_IO_save_base = tmp;
134  /* Set _IO_read_ptr.  */
135  fp->_IO_read_ptr = fp->_IO_read_end;
136}
137
138int
139_IO_switch_to_get_mode (fp)
140     _IO_FILE *fp;
141{
142  if (fp->_IO_write_ptr > fp->_IO_write_base)
143    if (_IO_OVERFLOW (fp, EOF) == EOF)
144      return EOF;
145  if (_IO_in_backup (fp))
146    fp->_IO_read_base = fp->_IO_backup_base;
147  else
148    {
149      fp->_IO_read_base = fp->_IO_buf_base;
150      if (fp->_IO_write_ptr > fp->_IO_read_end)
151	fp->_IO_read_end = fp->_IO_write_ptr;
152    }
153  fp->_IO_read_ptr = fp->_IO_write_ptr;
154
155  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = fp->_IO_read_ptr;
156
157  fp->_flags &= ~_IO_CURRENTLY_PUTTING;
158  return 0;
159}
160
161void
162_IO_free_backup_area (fp)
163     _IO_FILE *fp;
164{
165  if (_IO_in_backup (fp))
166    _IO_switch_to_main_get_area (fp);  /* Just in case. */
167  free (fp->_IO_save_base);
168  fp->_IO_save_base = NULL;
169  fp->_IO_save_end = NULL;
170  fp->_IO_backup_base = NULL;
171}
172
173#if 0
174int
175_IO_switch_to_put_mode (fp)
176     _IO_FILE *fp;
177{
178  fp->_IO_write_base = fp->_IO_read_ptr;
179  fp->_IO_write_ptr = fp->_IO_read_ptr;
180  /* Following is wrong if line- or un-buffered? */
181  fp->_IO_write_end = (fp->_flags & _IO_IN_BACKUP
182		       ? fp->_IO_read_end : fp->_IO_buf_end);
183
184  fp->_IO_read_ptr = fp->_IO_read_end;
185  fp->_IO_read_base = fp->_IO_read_end;
186
187  fp->_flags |= _IO_CURRENTLY_PUTTING;
188  return 0;
189}
190#endif
191
192int
193__overflow (f, ch)
194     _IO_FILE *f;
195     int ch;
196{
197  /* This is a single-byte stream.  */
198  if (f->_mode == 0)
199    _IO_fwide (f, -1);
200  return _IO_OVERFLOW (f, ch);
201}
202
203static int save_for_backup __P ((_IO_FILE *fp, char *end_p))
204#ifdef _LIBC
205     internal_function
206#endif
207     ;
208
209static int
210#ifdef _LIBC
211internal_function
212#endif
213save_for_backup (fp, end_p)
214     _IO_FILE *fp;
215     char *end_p;
216{
217  /* Append [_IO_read_base..end_p] to backup area. */
218  _IO_ssize_t least_mark = _IO_least_marker (fp, end_p);
219  /* needed_size is how much space we need in the backup area. */
220  _IO_size_t needed_size = (end_p - fp->_IO_read_base) - least_mark;
221  /* FIXME: Dubious arithmetic if pointers are NULL */
222  _IO_size_t current_Bsize = fp->_IO_save_end - fp->_IO_save_base;
223  _IO_size_t avail; /* Extra space available for future expansion. */
224  _IO_ssize_t delta;
225  struct _IO_marker *mark;
226  if (needed_size > current_Bsize)
227    {
228      char *new_buffer;
229      avail = 100;
230      new_buffer = (char *) malloc (avail + needed_size);
231      if (new_buffer == NULL)
232	return EOF;		/* FIXME */
233      if (least_mark < 0)
234	{
235#ifdef _LIBC
236	  __mempcpy (__mempcpy (new_buffer + avail,
237				fp->_IO_save_end + least_mark,
238				-least_mark),
239		     fp->_IO_read_base,
240		     end_p - fp->_IO_read_base);
241#else
242	  memcpy (new_buffer + avail,
243		  fp->_IO_save_end + least_mark,
244		  -least_mark);
245	  memcpy (new_buffer + avail - least_mark,
246		  fp->_IO_read_base,
247		  end_p - fp->_IO_read_base);
248#endif
249	}
250      else
251	memcpy (new_buffer + avail,
252		fp->_IO_read_base + least_mark,
253		needed_size);
254      if (fp->_IO_save_base)
255	free (fp->_IO_save_base);
256      fp->_IO_save_base = new_buffer;
257      fp->_IO_save_end = new_buffer + avail + needed_size;
258    }
259  else
260    {
261      avail = current_Bsize - needed_size;
262      if (least_mark < 0)
263	{
264	  memmove (fp->_IO_save_base + avail,
265		   fp->_IO_save_end + least_mark,
266		   -least_mark);
267	  memcpy (fp->_IO_save_base + avail - least_mark,
268		  fp->_IO_read_base,
269		  end_p - fp->_IO_read_base);
270	}
271      else if (needed_size > 0)
272	memcpy (fp->_IO_save_base + avail,
273		fp->_IO_read_base + least_mark,
274		needed_size);
275    }
276  fp->_IO_backup_base = fp->_IO_save_base + avail;
277  /* Adjust all the streammarkers. */
278  delta = end_p - fp->_IO_read_base;
279  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
280    mark->_pos -= delta;
281  return 0;
282}
283
284int
285__underflow (fp)
286     _IO_FILE *fp;
287{
288#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T || defined(_GLIBCPP_USE_TYPE_WCHAR_T)
289  if (fp->_vtable_offset == 0 && _IO_fwide (fp, -1) != -1)
290    return EOF;
291#endif
292
293  if (fp->_mode == 0)
294    _IO_fwide (fp, -1);
295  if (_IO_in_put_mode (fp))
296    if (_IO_switch_to_get_mode (fp) == EOF)
297      return EOF;
298  if (fp->_IO_read_ptr < fp->_IO_read_end)
299    return *(unsigned char *) fp->_IO_read_ptr;
300  if (_IO_in_backup (fp))
301    {
302      _IO_switch_to_main_get_area (fp);
303      if (fp->_IO_read_ptr < fp->_IO_read_end)
304	return *(unsigned char *) fp->_IO_read_ptr;
305    }
306  if (_IO_have_markers (fp))
307    {
308      if (save_for_backup (fp, fp->_IO_read_end))
309	return EOF;
310    }
311  else if (_IO_have_backup (fp))
312    _IO_free_backup_area (fp);
313  return _IO_UNDERFLOW (fp);
314}
315
316int
317__uflow (fp)
318     _IO_FILE *fp;
319{
320#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T || defined(_GLIBCPP_USE_TYPE_WCHAR_T)
321  if (fp->_vtable_offset == 0 && _IO_fwide (fp, -1) != -1)
322    return EOF;
323#endif
324
325  if (fp->_mode == 0)
326    _IO_fwide (fp, -11);
327  if (_IO_in_put_mode (fp))
328    if (_IO_switch_to_get_mode (fp) == EOF)
329      return EOF;
330  if (fp->_IO_read_ptr < fp->_IO_read_end)
331    return *(unsigned char *) fp->_IO_read_ptr++;
332  if (_IO_in_backup (fp))
333    {
334      _IO_switch_to_main_get_area (fp);
335      if (fp->_IO_read_ptr < fp->_IO_read_end)
336	return *(unsigned char *) fp->_IO_read_ptr++;
337    }
338  if (_IO_have_markers (fp))
339    {
340      if (save_for_backup (fp, fp->_IO_read_end))
341	return EOF;
342    }
343  else if (_IO_have_backup (fp))
344    _IO_free_backup_area (fp);
345  return _IO_UFLOW (fp);
346}
347
348void
349_IO_setb (f, b, eb, a)
350     _IO_FILE *f;
351      char *b;
352     char *eb;
353     int a;
354{
355  if (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF))
356    FREE_BUF (f->_IO_buf_base, _IO_blen (f));
357  f->_IO_buf_base = b;
358  f->_IO_buf_end = eb;
359  if (a)
360    f->_flags &= ~_IO_USER_BUF;
361  else
362    f->_flags |= _IO_USER_BUF;
363}
364
365void
366_IO_doallocbuf (fp)
367     _IO_FILE *fp;
368{
369  if (fp->_IO_buf_base)
370    return;
371  if (!(fp->_flags & _IO_UNBUFFERED))
372    if (_IO_DOALLOCATE (fp) != EOF)
373      return;
374  _IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
375}
376
377int
378_IO_default_underflow (fp)
379     _IO_FILE *fp;
380{
381  return EOF;
382}
383
384int
385_IO_default_uflow (fp)
386     _IO_FILE *fp;
387{
388  int ch = _IO_UNDERFLOW (fp);
389  if (ch == EOF)
390    return EOF;
391  return *(unsigned char *) fp->_IO_read_ptr++;
392}
393
394_IO_size_t
395_IO_default_xsputn (f, data, n)
396     _IO_FILE *f;
397     const void *data;
398     _IO_size_t n;
399{
400  const char *s = (char *) data;
401  _IO_size_t more = n;
402  if (more <= 0)
403    return 0;
404  for (;;)
405    {
406      /* Space available. */
407      _IO_ssize_t count = f->_IO_write_end - f->_IO_write_ptr;
408      if (count > 0)
409	{
410	  if ((_IO_size_t) count > more)
411	    count = more;
412	  if (count > 20)
413	    {
414#ifdef _LIBC
415	      f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
416#else
417	      memcpy (f->_IO_write_ptr, s, count);
418	      f->_IO_write_ptr += count;
419#endif
420	      s += count;
421            }
422	  else if (count <= 0)
423	    count = 0;
424	  else
425	    {
426	      char *p = f->_IO_write_ptr;
427	      _IO_ssize_t i;
428	      for (i = count; --i >= 0; )
429		*p++ = *s++;
430	      f->_IO_write_ptr = p;
431            }
432	  more -= count;
433        }
434      if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)
435	break;
436      more--;
437    }
438  return n - more;
439}
440
441_IO_size_t
442_IO_sgetn (fp, data, n)
443     _IO_FILE *fp;
444     void *data;
445     _IO_size_t n;
446{
447  /* FIXME handle putback buffer here! */
448  return _IO_XSGETN (fp, data, n);
449}
450
451_IO_size_t
452_IO_default_xsgetn (fp, data, n)
453     _IO_FILE *fp;
454     void *data;
455     _IO_size_t n;
456{
457  _IO_size_t more = n;
458  char *s = (char*) data;
459  for (;;)
460    {
461      /* Data available. */
462      _IO_ssize_t count = fp->_IO_read_end - fp->_IO_read_ptr;
463      if (count > 0)
464	{
465	  if ((_IO_size_t) count > more)
466	    count = more;
467	  if (count > 20)
468	    {
469#ifdef _LIBC
470	      s = __mempcpy (s, fp->_IO_read_ptr, count);
471#else
472	      memcpy (s, fp->_IO_read_ptr, count);
473	      s += count;
474#endif
475	      fp->_IO_read_ptr += count;
476	    }
477	  else if (count <= 0)
478	    count = 0;
479	  else
480	    {
481	      char *p = fp->_IO_read_ptr;
482	      int i = (int) count;
483	      while (--i >= 0)
484		*s++ = *p++;
485	      fp->_IO_read_ptr = p;
486            }
487            more -= count;
488        }
489      if (more == 0 || __underflow (fp) == EOF)
490	break;
491    }
492  return n - more;
493}
494
495#if 0
496/* Seems not to be needed. --drepper */
497int
498_IO_sync (fp)
499     _IO_FILE *fp;
500{
501  return 0;
502}
503#endif
504
505_IO_FILE *
506_IO_default_setbuf (fp, p, len)
507     _IO_FILE *fp;
508     char *p;
509     _IO_ssize_t len;
510{
511    if (_IO_SYNC (fp) == EOF)
512	return NULL;
513    if (p == NULL || len == 0)
514      {
515	fp->_flags |= _IO_UNBUFFERED;
516	_IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
517      }
518    else
519      {
520	fp->_flags &= ~_IO_UNBUFFERED;
521	_IO_setb (fp, p, p+len, 0);
522      }
523    fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = 0;
524    fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end = 0;
525    return fp;
526}
527
528_IO_off64_t
529_IO_default_seekpos (fp, pos, mode)
530     _IO_FILE *fp;
531     _IO_off64_t pos;
532     int mode;
533{
534  return _IO_SEEKOFF (fp, pos, 0, mode);
535}
536
537int
538_IO_default_doallocate (fp)
539     _IO_FILE *fp;
540{
541  char *buf;
542
543  ALLOC_BUF (buf, _IO_BUFSIZ, EOF);
544  _IO_setb (fp, buf, buf+_IO_BUFSIZ, 1);
545  return 1;
546}
547
548void
549_IO_init (fp, flags)
550     _IO_FILE *fp;
551     int flags;
552{
553  _IO_no_init (fp, flags, -1, NULL, NULL);
554}
555
556void
557_IO_no_init (fp, flags, orientation, wd, jmp)
558     _IO_FILE *fp;
559     int flags;
560     int orientation;
561     struct _IO_wide_data *wd;
562     struct _IO_jump_t *jmp;
563{
564  fp->_flags = _IO_MAGIC|flags;
565  fp->_IO_buf_base = NULL;
566  fp->_IO_buf_end = NULL;
567  fp->_IO_read_base = NULL;
568  fp->_IO_read_ptr = NULL;
569  fp->_IO_read_end = NULL;
570  fp->_IO_write_base = NULL;
571  fp->_IO_write_ptr = NULL;
572  fp->_IO_write_end = NULL;
573  fp->_chain = NULL; /* Not necessary. */
574
575  fp->_IO_save_base = NULL;
576  fp->_IO_backup_base = NULL;
577  fp->_IO_save_end = NULL;
578  fp->_markers = NULL;
579  fp->_cur_column = 0;
580#if _IO_JUMPS_OFFSET
581  fp->_vtable_offset = 0;
582#endif
583#ifdef _IO_MTSAFE_IO
584  _IO_lock_init (*fp->_lock);
585#endif
586  fp->_mode = orientation;
587#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T || defined(_GLIBCPP_USE_TYPE_WCHAR_T)
588  if (orientation >= 0)
589    {
590      fp->_wide_data = wd;
591      fp->_wide_data->_IO_buf_base = NULL;
592      fp->_wide_data->_IO_buf_end = NULL;
593      fp->_wide_data->_IO_read_base = NULL;
594      fp->_wide_data->_IO_read_ptr = NULL;
595      fp->_wide_data->_IO_read_end = NULL;
596      fp->_wide_data->_IO_write_base = NULL;
597      fp->_wide_data->_IO_write_ptr = NULL;
598      fp->_wide_data->_IO_write_end = NULL;
599      fp->_wide_data->_IO_save_base = NULL;
600      fp->_wide_data->_IO_backup_base = NULL;
601      fp->_wide_data->_IO_save_end = NULL;
602
603      fp->_wide_data->_wide_vtable = jmp;
604    }
605#endif
606}
607
608int
609_IO_default_sync (fp)
610     _IO_FILE *fp;
611{
612  return 0;
613}
614
615/* The way the C++ classes are mapped into the C functions in the
616   current implementation, this function can get called twice! */
617
618void
619_IO_default_finish (fp, dummy)
620     _IO_FILE *fp;
621     int dummy;
622{
623  struct _IO_marker *mark;
624  if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
625    {
626      FREE_BUF (fp->_IO_buf_base, _IO_blen (fp));
627      fp->_IO_buf_base = fp->_IO_buf_end = NULL;
628    }
629
630  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
631    mark->_sbuf = NULL;
632
633  if (fp->_IO_save_base)
634    {
635      free (fp->_IO_save_base);
636      fp->_IO_save_base = NULL;
637    }
638
639#ifdef _IO_MTSAFE_IO
640  _IO_lock_fini (*fp->_lock);
641#endif
642
643  _IO_un_link ((struct _IO_FILE_plus *) fp);
644}
645
646_IO_off64_t
647_IO_default_seekoff (fp, offset, dir, mode)
648     _IO_FILE *fp;
649     _IO_off64_t offset;
650     int dir;
651     int mode;
652{
653    return _IO_pos_BAD;
654}
655
656int
657_IO_sputbackc (fp, c)
658     _IO_FILE *fp;
659     int c;
660{
661  int result;
662
663  if (fp->_IO_read_ptr > fp->_IO_read_base
664      && (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
665    {
666      fp->_IO_read_ptr--;
667      result = (unsigned char) c;
668    }
669  else
670    result = _IO_PBACKFAIL (fp, c);
671
672  if (result != EOF)
673    fp->_flags &= ~_IO_EOF_SEEN;
674
675  return result;
676}
677
678int
679_IO_sungetc (fp)
680     _IO_FILE *fp;
681{
682  int result;
683
684  if (fp->_IO_read_ptr > fp->_IO_read_base)
685    {
686      fp->_IO_read_ptr--;
687      result = (unsigned char) *fp->_IO_read_ptr;
688    }
689  else
690    result = _IO_PBACKFAIL (fp, EOF);
691
692  if (result != EOF)
693    fp->_flags &= ~_IO_EOF_SEEN;
694
695  return result;
696}
697
698#if 0 /* Work in progress */
699/* Seems not to be needed.  */
700#if 0
701void
702_IO_set_column (fp, c)
703     _IO_FILE *fp;
704     int c;
705{
706  if (c == -1)
707    fp->_column = -1;
708  else
709    fp->_column = c - (fp->_IO_write_ptr - fp->_IO_write_base);
710}
711#else
712int
713_IO_set_column (fp, i)
714     _IO_FILE *fp;
715     int i;
716{
717  fp->_cur_column = i + 1;
718  return 0;
719}
720#endif
721#endif
722
723
724unsigned
725_IO_adjust_column (start, line, count)
726     unsigned start;
727     const char *line;
728     int count;
729{
730  const char *ptr = line + count;
731  while (ptr > line)
732    if (*--ptr == '\n')
733      return line + count - ptr - 1;
734  return start + count;
735}
736
737#if 0
738/* Seems not to be needed. --drepper */
739int
740_IO_get_column (fp)
741     _IO_FILE *fp;
742{
743  if (fp->_cur_column)
744    return _IO_adjust_column (fp->_cur_column - 1,
745			      fp->_IO_write_base,
746			      fp->_IO_write_ptr - fp->_IO_write_base);
747  return -1;
748}
749#endif
750
751int
752_IO_flush_all ()
753{
754  int result = 0;
755  struct _IO_FILE *fp;
756  for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
757    if (((fp->_mode < 0 && fp->_IO_write_ptr > fp->_IO_write_base)
758#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T || defined(_GLIBCPP_USE_TYPE_WCHAR_T)
759	 || (fp->_vtable_offset == 0
760	     && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
761				  > fp->_wide_data->_IO_write_base))
762#endif
763	 )
764	&& _IO_OVERFLOW (fp, EOF) == EOF)
765      result = EOF;
766  return result;
767}
768
769void
770_IO_flush_all_linebuffered ()
771{
772  struct _IO_FILE *fp;
773  for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
774    if ((fp->_flags & _IO_NO_WRITES) == 0 && fp->_flags & _IO_LINE_BUF)
775      _IO_OVERFLOW (fp, EOF);
776}
777
778static void _IO_unbuffer_write __P ((void));
779
780static void
781_IO_unbuffer_write ()
782{
783  struct _IO_FILE *fp;
784  for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
785    if (! (fp->_flags & _IO_UNBUFFERED)
786	&& (! (fp->_flags & _IO_NO_WRITES)
787	    || (fp->_flags & _IO_IS_APPENDING))
788	/* Iff stream is un-orientated, it wasn't used. */
789	&& fp->_mode != 0)
790      _IO_SETBUF (fp, NULL, 0);
791}
792
793int
794_IO_cleanup ()
795{
796  int result = _IO_flush_all ();
797
798  /* We currently don't have a reliable mechanism for making sure that
799     C++ static destructors are executed in the correct order.
800     So it is possible that other static destructors might want to
801     write to cout - and they're supposed to be able to do so.
802
803     The following will make the standard streambufs be unbuffered,
804     which forces any output from late destructors to be written out. */
805  _IO_unbuffer_write ();
806
807  return result;
808}
809
810
811void
812_IO_init_marker (marker, fp)
813     struct _IO_marker *marker;
814     _IO_FILE *fp;
815{
816  marker->_sbuf = fp;
817  if (_IO_in_put_mode (fp))
818    _IO_switch_to_get_mode (fp);
819  if (_IO_in_backup (fp))
820    marker->_pos = fp->_IO_read_ptr - fp->_IO_read_end;
821  else
822    marker->_pos = fp->_IO_read_ptr - fp->_IO_read_base;
823
824  /* Should perhaps sort the chain? */
825  marker->_next = fp->_markers;
826  fp->_markers = marker;
827}
828
829void
830_IO_remove_marker (marker)
831     struct _IO_marker *marker;
832{
833  /* Unlink from sb's chain. */
834  struct _IO_marker **ptr = &marker->_sbuf->_markers;
835  for (; ; ptr = &(*ptr)->_next)
836    {
837      if (*ptr == NULL)
838	break;
839      else if (*ptr == marker)
840	{
841	  *ptr = marker->_next;
842	  return;
843	}
844    }
845#if 0
846    if _sbuf has a backup area that is no longer needed, should we delete
847    it now, or wait until the next underflow?
848#endif
849}
850
851#define BAD_DELTA EOF
852
853int
854_IO_marker_difference (mark1, mark2)
855     struct _IO_marker *mark1;
856     struct _IO_marker *mark2;
857{
858  return mark1->_pos - mark2->_pos;
859}
860
861/* Return difference between MARK and current position of MARK's stream. */
862int
863_IO_marker_delta (mark)
864     struct _IO_marker *mark;
865{
866  int cur_pos;
867  if (mark->_sbuf == NULL)
868    return BAD_DELTA;
869  if (_IO_in_backup (mark->_sbuf))
870    cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_end;
871  else
872    cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_base;
873  return mark->_pos - cur_pos;
874}
875
876int
877_IO_seekmark (fp, mark, delta)
878     _IO_FILE *fp;
879     struct _IO_marker *mark;
880     int delta;
881{
882  if (mark->_sbuf != fp)
883    return EOF;
884 if (mark->_pos >= 0)
885    {
886      if (_IO_in_backup (fp))
887	_IO_switch_to_main_get_area (fp);
888      fp->_IO_read_ptr = fp->_IO_read_base + mark->_pos;
889    }
890  else
891    {
892      if (!_IO_in_backup (fp))
893	_IO_switch_to_backup_area (fp);
894      fp->_IO_read_ptr = fp->_IO_read_end + mark->_pos;
895    }
896  return 0;
897}
898
899void
900_IO_unsave_markers (fp)
901     _IO_FILE *fp;
902{
903  struct _IO_marker *mark = fp->_markers;
904  if (mark)
905    {
906#ifdef TODO
907      streampos offset = seekoff (0, ios::cur, ios::in);
908      if (offset != EOF)
909	{
910	  offset += eGptr () - Gbase ();
911	  for ( ; mark != NULL; mark = mark->_next)
912	    mark->set_streampos (mark->_pos + offset);
913	}
914    else
915      {
916	for ( ; mark != NULL; mark = mark->_next)
917	  mark->set_streampos (EOF);
918      }
919#endif
920      fp->_markers = 0;
921    }
922
923  if (_IO_have_backup (fp))
924    _IO_free_backup_area (fp);
925}
926
927#if 0
928/* Seems not to be needed. --drepper */
929int
930_IO_nobackup_pbackfail (fp, c)
931     _IO_FILE *fp;
932     int c;
933{
934  if (fp->_IO_read_ptr > fp->_IO_read_base)
935	fp->_IO_read_ptr--;
936  if (c != EOF && *fp->_IO_read_ptr != c)
937      *fp->_IO_read_ptr = c;
938  return (unsigned char) c;
939}
940#endif
941
942int
943_IO_default_pbackfail (fp, c)
944     _IO_FILE *fp;
945     int c;
946{
947  if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp)
948      && (unsigned char) fp->_IO_read_ptr[-1] == c)
949    --fp->_IO_read_ptr;
950  else
951    {
952      /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
953      if (!_IO_in_backup (fp))
954	{
955	  /* We need to keep the invariant that the main get area
956	     logically follows the backup area.  */
957	  if (fp->_IO_read_ptr > fp->_IO_read_base && _IO_have_backup (fp))
958	    {
959	      if (save_for_backup (fp, fp->_IO_read_ptr))
960		return EOF;
961	    }
962	  else if (!_IO_have_backup (fp))
963	    {
964	      /* No backup buffer: allocate one. */
965	      /* Use nshort buffer, if unused? (probably not)  FIXME */
966	      int backup_size = 128;
967	      char *bbuf = (char *) malloc (backup_size);
968	      if (bbuf == NULL)
969		return EOF;
970	      fp->_IO_save_base = bbuf;
971	      fp->_IO_save_end = fp->_IO_save_base + backup_size;
972	      fp->_IO_backup_base = fp->_IO_save_end;
973	    }
974	  fp->_IO_read_base = fp->_IO_read_ptr;
975	  _IO_switch_to_backup_area (fp);
976	}
977      else if (fp->_IO_read_ptr <= fp->_IO_read_base)
978	{
979	  /* Increase size of existing backup buffer. */
980	  _IO_size_t new_size;
981	  _IO_size_t old_size = fp->_IO_read_end - fp->_IO_read_base;
982	  char *new_buf;
983	  new_size = 2 * old_size;
984	  new_buf = (char *) malloc (new_size);
985	  if (new_buf == NULL)
986	    return EOF;
987	  memcpy (new_buf + (new_size - old_size), fp->_IO_read_base,
988		  old_size);
989	  free (fp->_IO_read_base);
990	  _IO_setg (fp, new_buf, new_buf + (new_size - old_size),
991		    new_buf + new_size);
992	  fp->_IO_backup_base = fp->_IO_read_ptr;
993	}
994
995      *--fp->_IO_read_ptr = c;
996    }
997  return (unsigned char) c;
998}
999
1000_IO_off64_t
1001_IO_default_seek (fp, offset, dir)
1002     _IO_FILE *fp;
1003     _IO_off64_t offset;
1004     int dir;
1005{
1006  return _IO_pos_BAD;
1007}
1008
1009int
1010_IO_default_stat (fp, st)
1011     _IO_FILE *fp;
1012     void* st;
1013{
1014  return EOF;
1015}
1016
1017_IO_ssize_t
1018_IO_default_read (fp, data, n)
1019     _IO_FILE* fp;
1020     void *data;
1021     _IO_ssize_t n;
1022{
1023  return -1;
1024}
1025
1026_IO_ssize_t
1027_IO_default_write (fp, data, n)
1028     _IO_FILE *fp;
1029     const void *data;
1030     _IO_ssize_t n;
1031{
1032  return 0;
1033}
1034
1035int
1036_IO_default_showmanyc (fp)
1037     _IO_FILE *fp;
1038{
1039  return -1;
1040}
1041
1042void
1043_IO_default_imbue (fp, locale)
1044     _IO_FILE *fp;
1045     void *locale;
1046{
1047}
1048
1049_IO_ITER
1050_IO_iter_begin()
1051{
1052  return (_IO_ITER) _IO_list_all;
1053}
1054
1055_IO_ITER
1056_IO_iter_end()
1057{
1058  return NULL;
1059}
1060
1061_IO_ITER
1062_IO_iter_next(iter)
1063    _IO_ITER iter;
1064{
1065  return iter->_chain;
1066}
1067
1068_IO_FILE *
1069_IO_iter_file(iter)
1070    _IO_ITER iter;
1071{
1072  return iter;
1073}
1074
1075void
1076_IO_list_lock()
1077{
1078#ifdef _IO_MTSAFE_IO
1079  _IO_lock_lock (list_all_lock);
1080#endif
1081}
1082
1083void
1084_IO_list_unlock()
1085{
1086#ifdef _IO_MTSAFE_IO
1087  _IO_lock_unlock (list_all_lock);
1088#endif
1089}
1090
1091void
1092_IO_list_resetlock()
1093{
1094#ifdef _IO_MTSAFE_IO
1095  _IO_lock_init (list_all_lock);
1096#endif
1097}
1098
1099
1100#ifdef TODO
1101#if defined(linux)
1102#define IO_CLEANUP ;
1103#endif
1104
1105#ifdef IO_CLEANUP
1106  IO_CLEANUP
1107#else
1108struct __io_defs {
1109    __io_defs() { }
1110    ~__io_defs() { _IO_cleanup (); }
1111};
1112__io_defs io_defs__;
1113#endif
1114
1115#endif /* TODO */
1116
1117#ifdef weak_alias
1118weak_alias (_IO_cleanup, _cleanup)
1119#endif
1120
1121#ifdef text_set_element
1122text_set_element(__libc_atexit, _cleanup);
1123#endif
1124