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