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