(_IO_least_marker): Make global.
[kopensolaris-gnu/glibc.git] / libio / genops.c
1 /* Copyright (C) 1993, 1995, 1997, 1998, 1999 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 (_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 (_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 || __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->_mode > 0 && (fp->_wide_data->_IO_write_ptr
746                                > fp->_wide_data->_IO_write_base)))
747         && _IO_OVERFLOW (fp, EOF) == EOF)
748       result = EOF;
749   return result;
750 }
751
752 void
753 _IO_flush_all_linebuffered ()
754 {
755   _IO_FILE *fp;
756   for (fp = _IO_list_all; fp != NULL; fp = fp->_chain)
757     if ((fp->_flags & _IO_NO_WRITES) == 0 && fp->_flags & _IO_LINE_BUF)
758       _IO_OVERFLOW (fp, EOF);
759 }
760
761 static void _IO_unbuffer_write __P ((void));
762
763 static void
764 _IO_unbuffer_write ()
765 {
766   _IO_FILE *fp;
767   for (fp = _IO_list_all; fp != NULL; fp = fp->_chain)
768     if (! (fp->_flags & _IO_UNBUFFERED)
769         && (! (fp->_flags & _IO_NO_WRITES)
770             || (fp->_flags & _IO_IS_APPENDING)))
771       _IO_SETBUF (fp, NULL, 0);
772 }
773
774 int
775 _IO_cleanup ()
776 {
777   int result = _IO_flush_all ();
778
779   /* We currently don't have a reliable mechanism for making sure that
780      C++ static destructors are executed in the correct order.
781      So it is possible that other static destructors might want to
782      write to cout - and they're supposed to be able to do so.
783
784      The following will make the standard streambufs be unbuffered,
785      which forces any output from late destructors to be written out. */
786   _IO_unbuffer_write ();
787
788   return result;
789 }
790
791
792 void
793 _IO_init_marker (marker, fp)
794      struct _IO_marker *marker;
795      _IO_FILE *fp;
796 {
797   marker->_sbuf = fp;
798   if (_IO_in_put_mode (fp))
799     _IO_switch_to_get_mode (fp);
800   if (_IO_in_backup (fp))
801     marker->_pos = fp->_IO_read_ptr - fp->_IO_read_end;
802   else
803     marker->_pos = fp->_IO_read_ptr - fp->_IO_read_base;
804
805   /* Should perhaps sort the chain? */
806   marker->_next = fp->_markers;
807   fp->_markers = marker;
808 }
809
810 void
811 _IO_remove_marker (marker)
812      struct _IO_marker *marker;
813 {
814   /* Unlink from sb's chain. */
815   struct _IO_marker **ptr = &marker->_sbuf->_markers;
816   for (; ; ptr = &(*ptr)->_next)
817     {
818       if (*ptr == NULL)
819         break;
820       else if (*ptr == marker)
821         {
822           *ptr = marker->_next;
823           return;
824         }
825     }
826 #if 0
827     if _sbuf has a backup area that is no longer needed, should we delete
828     it now, or wait until the next underflow?
829 #endif
830 }
831
832 #define BAD_DELTA EOF
833
834 int
835 _IO_marker_difference (mark1, mark2)
836      struct _IO_marker *mark1;
837      struct _IO_marker *mark2;
838 {
839   return mark1->_pos - mark2->_pos;
840 }
841
842 /* Return difference between MARK and current position of MARK's stream. */
843 int
844 _IO_marker_delta (mark)
845      struct _IO_marker *mark;
846 {
847   int cur_pos;
848   if (mark->_sbuf == NULL)
849     return BAD_DELTA;
850   if (_IO_in_backup (mark->_sbuf))
851     cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_end;
852   else
853     cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_base;
854   return mark->_pos - cur_pos;
855 }
856
857 int
858 _IO_seekmark (fp, mark, delta)
859      _IO_FILE *fp;
860      struct _IO_marker *mark;
861      int delta;
862 {
863   if (mark->_sbuf != fp)
864     return EOF;
865  if (mark->_pos >= 0)
866     {
867       if (_IO_in_backup (fp))
868         _IO_switch_to_main_get_area (fp);
869       fp->_IO_read_ptr = fp->_IO_read_base + mark->_pos;
870     }
871   else
872     {
873       if (!_IO_in_backup (fp))
874         _IO_switch_to_backup_area (fp);
875       fp->_IO_read_ptr = fp->_IO_read_end + mark->_pos;
876     }
877   return 0;
878 }
879
880 void
881 _IO_unsave_markers (fp)
882      _IO_FILE *fp;
883 {
884   struct _IO_marker *mark = fp->_markers;
885   if (mark)
886     {
887 #ifdef TODO
888       streampos offset = seekoff (0, ios::cur, ios::in);
889       if (offset != EOF)
890         {
891           offset += eGptr () - Gbase ();
892           for ( ; mark != NULL; mark = mark->_next)
893             mark->set_streampos (mark->_pos + offset);
894         }
895     else
896       {
897         for ( ; mark != NULL; mark = mark->_next)
898           mark->set_streampos (EOF);
899       }
900 #endif
901       fp->_markers = 0;
902     }
903
904   if (_IO_have_backup (fp))
905     _IO_free_backup_area (fp);
906 }
907
908 #if 0
909 /* Seems not to be needed. --drepper */
910 int
911 _IO_nobackup_pbackfail (fp, c)
912      _IO_FILE *fp;
913      int c;
914 {
915   if (fp->_IO_read_ptr > fp->_IO_read_base)
916         fp->_IO_read_ptr--;
917   if (c != EOF && *fp->_IO_read_ptr != c)
918       *fp->_IO_read_ptr = c;
919   return (unsigned char) c;
920 }
921 #endif
922
923 int
924 _IO_default_pbackfail (fp, c)
925      _IO_FILE *fp;
926      int c;
927 {
928   if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp)
929       && (unsigned char) fp->_IO_read_ptr[-1] == c)
930     --fp->_IO_read_ptr;
931   else
932     {
933       /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
934       if (!_IO_in_backup (fp))
935         {
936           /* We need to keep the invariant that the main get area
937              logically follows the backup area.  */
938           if (fp->_IO_read_ptr > fp->_IO_read_base && _IO_have_backup (fp))
939             {
940               if (save_for_backup (fp, fp->_IO_read_ptr))
941                 return EOF;
942             }
943           else if (!_IO_have_backup (fp))
944             {
945               /* No backup buffer: allocate one. */
946               /* Use nshort buffer, if unused? (probably not)  FIXME */
947               int backup_size = 128;
948               char *bbuf = (char *) malloc (backup_size);
949               if (bbuf == NULL)
950                 return EOF;
951               fp->_IO_save_base = bbuf;
952               fp->_IO_save_end = fp->_IO_save_base + backup_size;
953               fp->_IO_backup_base = fp->_IO_save_end;
954             }
955           fp->_IO_read_base = fp->_IO_read_ptr;
956           _IO_switch_to_backup_area (fp);
957         }
958       else if (fp->_IO_read_ptr <= fp->_IO_read_base)
959         {
960           /* Increase size of existing backup buffer. */
961           _IO_size_t new_size;
962           _IO_size_t old_size = fp->_IO_read_end - fp->_IO_read_base;
963           char *new_buf;
964           new_size = 2 * old_size;
965           new_buf = (char *) malloc (new_size);
966           if (new_buf == NULL)
967             return EOF;
968           memcpy (new_buf + (new_size - old_size), fp->_IO_read_base,
969                   old_size);
970           free (fp->_IO_read_base);
971           _IO_setg (fp, new_buf, new_buf + (new_size - old_size),
972                     new_buf + new_size);
973           fp->_IO_backup_base = fp->_IO_read_ptr;
974         }
975
976       *--fp->_IO_read_ptr = c;
977     }
978   return (unsigned char) c;
979 }
980
981 _IO_off64_t
982 _IO_default_seek (fp, offset, dir)
983      _IO_FILE *fp;
984      _IO_off64_t offset;
985      int dir;
986 {
987   return _IO_pos_BAD;
988 }
989
990 int
991 _IO_default_stat (fp, st)
992      _IO_FILE *fp;
993      void* st;
994 {
995   return EOF;
996 }
997
998 _IO_ssize_t
999 _IO_default_read (fp, data, n)
1000      _IO_FILE* fp;
1001      void *data;
1002      _IO_ssize_t n;
1003 {
1004   return -1;
1005 }
1006
1007 _IO_ssize_t
1008 _IO_default_write (fp, data, n)
1009      _IO_FILE *fp;
1010      const void *data;
1011      _IO_ssize_t n;
1012 {
1013   return 0;
1014 }
1015
1016 int
1017 _IO_default_showmanyc (fp)
1018      _IO_FILE *fp;
1019 {
1020   return -1;
1021 }
1022
1023 void
1024 _IO_default_imbue (fp, locale)
1025      _IO_FILE *fp;
1026      void *locale;
1027 {
1028 }
1029
1030
1031 #ifdef TODO
1032 #if defined(linux)
1033 #define IO_CLEANUP ;
1034 #endif
1035
1036 #ifdef IO_CLEANUP
1037   IO_CLEANUP
1038 #else
1039 struct __io_defs {
1040     __io_defs() { }
1041     ~__io_defs() { _IO_cleanup (); }
1042 };
1043 __io_defs io_defs__;
1044 #endif
1045
1046 #endif /* TODO */
1047
1048 #ifdef weak_alias
1049 weak_alias (_IO_cleanup, _cleanup)
1050 #endif
1051
1052 #ifdef text_set_element
1053 text_set_element(__libc_atexit, _cleanup);
1054 #endif