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