xref: /haiku/src/system/libroot/posix/glibc/libio/genops.c (revision 24159a0c7d6d6dcba9f2a0c1a7c08d2c8167f21b)
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 
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 #if 0
47 static void
48 flush_cleanup (void *not_used)
49 {
50   if (run_fp != NULL)
51     _IO_funlockfile (run_fp);
52 #ifdef _IO_MTSAFE_IO
53   _IO_lock_unlock (list_all_lock);
54 #endif
55 }
56 #endif
57 
58 
59 void
60 _IO_un_link(struct _IO_FILE_plus *fp)
61 {
62   if (fp->file._flags & _IO_LINKED)
63     {
64       struct _IO_FILE_plus **f;
65 #ifdef _IO_MTSAFE_IO
66       _IO_cleanup_region_start_noarg (flush_cleanup);
67       _IO_lock_lock (list_all_lock);
68       run_fp = (_IO_FILE *) fp;
69       _IO_flockfile ((_IO_FILE *) fp);
70 #endif
71       for (f = &INTUSE(_IO_list_all); *f;
72 	   f = (struct _IO_FILE_plus **) &(*f)->file._chain)
73 	{
74 	  if (*f == fp)
75 	    {
76 	      *f = (struct _IO_FILE_plus *) fp->file._chain;
77 	      ++_IO_list_all_stamp;
78 	      break;
79 	    }
80 	}
81       fp->file._flags &= ~_IO_LINKED;
82 #ifdef _IO_MTSAFE_IO
83       _IO_funlockfile ((_IO_FILE *) fp);
84       run_fp = NULL;
85       _IO_lock_unlock (list_all_lock);
86       _IO_cleanup_region_end (0);
87 #endif
88     }
89 }
90 INTDEF(_IO_un_link)
91 
92 void
93 _IO_link_in (fp)
94      struct _IO_FILE_plus *fp;
95 {
96   if ((fp->file._flags & _IO_LINKED) == 0)
97     {
98       fp->file._flags |= _IO_LINKED;
99 #ifdef _IO_MTSAFE_IO
100       _IO_cleanup_region_start_noarg (flush_cleanup);
101       _IO_lock_lock (list_all_lock);
102       run_fp = (_IO_FILE *) fp;
103       _IO_flockfile ((_IO_FILE *) fp);
104 #endif
105       fp->file._chain = (_IO_FILE *) INTUSE(_IO_list_all);
106       INTUSE(_IO_list_all) = fp;
107       ++_IO_list_all_stamp;
108 #ifdef _IO_MTSAFE_IO
109       _IO_funlockfile ((_IO_FILE *) fp);
110       run_fp = NULL;
111       _IO_lock_unlock (list_all_lock);
112       _IO_cleanup_region_end (0);
113 #endif
114     }
115 }
116 INTDEF(_IO_link_in)
117 
118 /* Return minimum _pos markers
119    Assumes the current get area is the main get area. */
120 _IO_ssize_t _IO_least_marker __P ((_IO_FILE *fp, char *end_p));
121 
122 _IO_ssize_t
123 _IO_least_marker (fp, end_p)
124      _IO_FILE *fp;
125      char *end_p;
126 {
127   _IO_ssize_t least_so_far = end_p - fp->_IO_read_base;
128   struct _IO_marker *mark;
129   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
130     if (mark->_pos < least_so_far)
131       least_so_far = mark->_pos;
132   return least_so_far;
133 }
134 
135 /* Switch current get area from backup buffer to (start of) main get area. */
136 
137 void
138 _IO_switch_to_main_get_area (fp)
139      _IO_FILE *fp;
140 {
141   char *tmp;
142   fp->_flags &= ~_IO_IN_BACKUP;
143   /* Swap _IO_read_end and _IO_save_end. */
144   tmp = fp->_IO_read_end;
145   fp->_IO_read_end = fp->_IO_save_end;
146   fp->_IO_save_end= tmp;
147   /* Swap _IO_read_base and _IO_save_base. */
148   tmp = fp->_IO_read_base;
149   fp->_IO_read_base = fp->_IO_save_base;
150   fp->_IO_save_base = tmp;
151   /* Set _IO_read_ptr. */
152   fp->_IO_read_ptr = fp->_IO_read_base;
153 }
154 
155 /* Switch current get area from main get area to (end of) backup area. */
156 
157 void
158 _IO_switch_to_backup_area (fp)
159      _IO_FILE *fp;
160 {
161   char *tmp;
162   fp->_flags |= _IO_IN_BACKUP;
163   /* Swap _IO_read_end and _IO_save_end. */
164   tmp = fp->_IO_read_end;
165   fp->_IO_read_end = fp->_IO_save_end;
166   fp->_IO_save_end = tmp;
167   /* Swap _IO_read_base and _IO_save_base. */
168   tmp = fp->_IO_read_base;
169   fp->_IO_read_base = fp->_IO_save_base;
170   fp->_IO_save_base = tmp;
171   /* Set _IO_read_ptr.  */
172   fp->_IO_read_ptr = fp->_IO_read_end;
173 }
174 
175 int
176 _IO_switch_to_get_mode (fp)
177      _IO_FILE *fp;
178 {
179   if (fp->_IO_write_ptr > fp->_IO_write_base)
180     if (_IO_OVERFLOW (fp, EOF) == EOF)
181       return EOF;
182   if (_IO_in_backup (fp))
183     fp->_IO_read_base = fp->_IO_backup_base;
184   else
185     {
186       fp->_IO_read_base = fp->_IO_buf_base;
187       if (fp->_IO_write_ptr > fp->_IO_read_end)
188 	fp->_IO_read_end = fp->_IO_write_ptr;
189     }
190   fp->_IO_read_ptr = fp->_IO_write_ptr;
191 
192   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = fp->_IO_read_ptr;
193 
194   fp->_flags &= ~_IO_CURRENTLY_PUTTING;
195   return 0;
196 }
197 INTDEF(_IO_switch_to_get_mode)
198 
199 void
200 _IO_free_backup_area (fp)
201      _IO_FILE *fp;
202 {
203   if (_IO_in_backup (fp))
204     _IO_switch_to_main_get_area (fp);  /* Just in case. */
205   free (fp->_IO_save_base);
206   fp->_IO_save_base = NULL;
207   fp->_IO_save_end = NULL;
208   fp->_IO_backup_base = NULL;
209 }
210 INTDEF(_IO_free_backup_area)
211 
212 #if 0
213 int
214 _IO_switch_to_put_mode (fp)
215      _IO_FILE *fp;
216 {
217   fp->_IO_write_base = fp->_IO_read_ptr;
218   fp->_IO_write_ptr = fp->_IO_read_ptr;
219   /* Following is wrong if line- or un-buffered? */
220   fp->_IO_write_end = (fp->_flags & _IO_IN_BACKUP
221 		       ? fp->_IO_read_end : fp->_IO_buf_end);
222 
223   fp->_IO_read_ptr = fp->_IO_read_end;
224   fp->_IO_read_base = fp->_IO_read_end;
225 
226   fp->_flags |= _IO_CURRENTLY_PUTTING;
227   return 0;
228 }
229 #endif
230 
231 
232 int
233 __overflow(_IO_FILE *file, int character)
234 {
235 	/* This is a single-byte stream.  */
236 	if (file->_mode == 0)
237 		_IO_fwide(file, -1);
238 
239 	return _IO_OVERFLOW(file, character);
240 }
241 libc_hidden_def(__overflow)
242 
243 
244 static int save_for_backup __P ((_IO_FILE *fp, char *end_p))
245 #ifdef _LIBC
246      internal_function
247 #endif
248      ;
249 
250 static int
251 #ifdef _LIBC
252 internal_function
253 #endif
254 save_for_backup (fp, end_p)
255      _IO_FILE *fp;
256      char *end_p;
257 {
258   /* Append [_IO_read_base..end_p] to backup area. */
259   _IO_ssize_t least_mark = _IO_least_marker (fp, end_p);
260   /* needed_size is how much space we need in the backup area. */
261   _IO_size_t needed_size = (end_p - fp->_IO_read_base) - least_mark;
262   /* FIXME: Dubious arithmetic if pointers are NULL */
263   _IO_size_t current_Bsize = fp->_IO_save_end - fp->_IO_save_base;
264   _IO_size_t avail; /* Extra space available for future expansion. */
265   _IO_ssize_t delta;
266   struct _IO_marker *mark;
267   if (needed_size > current_Bsize)
268     {
269       char *new_buffer;
270       avail = 100;
271       new_buffer = (char *) malloc (avail + needed_size);
272       if (new_buffer == NULL)
273 	return EOF;		/* FIXME */
274       if (least_mark < 0)
275 	{
276 #ifdef _LIBC
277 	  __mempcpy (__mempcpy (new_buffer + avail,
278 				fp->_IO_save_end + least_mark,
279 				-least_mark),
280 		     fp->_IO_read_base,
281 		     end_p - fp->_IO_read_base);
282 #else
283 	  memcpy (new_buffer + avail,
284 		  fp->_IO_save_end + least_mark,
285 		  -least_mark);
286 	  memcpy (new_buffer + avail - least_mark,
287 		  fp->_IO_read_base,
288 		  end_p - fp->_IO_read_base);
289 #endif
290 	}
291       else
292 	memcpy (new_buffer + avail,
293 		fp->_IO_read_base + least_mark,
294 		needed_size);
295       if (fp->_IO_save_base)
296 	free (fp->_IO_save_base);
297       fp->_IO_save_base = new_buffer;
298       fp->_IO_save_end = new_buffer + avail + needed_size;
299     }
300   else
301     {
302       avail = current_Bsize - needed_size;
303       if (least_mark < 0)
304 	{
305 	  memmove (fp->_IO_save_base + avail,
306 		   fp->_IO_save_end + least_mark,
307 		   -least_mark);
308 	  memcpy (fp->_IO_save_base + avail - least_mark,
309 		  fp->_IO_read_base,
310 		  end_p - fp->_IO_read_base);
311 	}
312       else if (needed_size > 0)
313 	memcpy (fp->_IO_save_base + avail,
314 		fp->_IO_read_base + least_mark,
315 		needed_size);
316     }
317   fp->_IO_backup_base = fp->_IO_save_base + avail;
318   /* Adjust all the streammarkers. */
319   delta = end_p - fp->_IO_read_base;
320   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
321     mark->_pos -= delta;
322   return 0;
323 }
324 
325 
326 int
327 __underflow(_IO_FILE *file)
328 {
329 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
330 	if (file->_vtable_offset == 0 && _IO_fwide(file, -1) != -1)
331 		return EOF;
332 #endif
333 
334 	if (file->_mode == 0)
335 		_IO_fwide(file, -1);
336 
337 	if (_IO_in_put_mode(file) && INTUSE(_IO_switch_to_get_mode)(file) == EOF)
338 		return EOF;
339 
340 	if (file->_IO_read_ptr < file->_IO_read_end)
341 		return *(unsigned char *)file->_IO_read_ptr;
342 
343 	if (_IO_in_backup(file)) {
344 		_IO_switch_to_main_get_area(file);
345 
346 		if (file->_IO_read_ptr < file->_IO_read_end)
347 			return *(unsigned char *)file->_IO_read_ptr;
348     }
349 	if (_IO_have_markers(file)) {
350 		if (save_for_backup(file, file->_IO_read_end))
351 			return EOF;
352     } else if (_IO_have_backup(file))
353 		INTUSE(_IO_free_backup_area)(file);
354 
355 	return _IO_UNDERFLOW(file);
356 }
357 libc_hidden_def(__underflow)
358 
359 
360 int
361 __uflow(_IO_FILE *file)
362 {
363 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
364 	if (file->_vtable_offset == 0 && _IO_fwide(file, -1) != -1)
365 		return EOF;
366 #endif
367 
368 	if (file->_mode == 0)
369 		_IO_fwide(file, -11);
370 
371 	if (_IO_in_put_mode(file) && INTUSE(_IO_switch_to_get_mode)(file) == EOF)
372 		return EOF;
373 
374 	if (file->_IO_read_ptr < file->_IO_read_end)
375 		return *(unsigned char *)file->_IO_read_ptr++;
376 
377 	if (_IO_in_backup(file)) {
378 		_IO_switch_to_main_get_area(file);
379 
380 		if (file->_IO_read_ptr < file->_IO_read_end)
381 			return *(unsigned char *)file->_IO_read_ptr++;
382 	}
383 
384 	if (_IO_have_markers(file)) {
385 		if (save_for_backup(file, file->_IO_read_end))
386 			return EOF;
387 	} else if (_IO_have_backup(file))
388 		INTUSE(_IO_free_backup_area)(file);
389 
390 	return _IO_UFLOW(file);
391 }
392 libc_hidden_def(__uflow)
393 
394 
395 void
396 _IO_setb (f, b, eb, a)
397      _IO_FILE *f;
398      char *b;
399      char *eb;
400      int a;
401 {
402   if (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF))
403     FREE_BUF (f->_IO_buf_base, _IO_blen (f));
404   f->_IO_buf_base = b;
405   f->_IO_buf_end = eb;
406   if (a)
407     f->_flags &= ~_IO_USER_BUF;
408   else
409     f->_flags |= _IO_USER_BUF;
410 }
411 INTDEF(_IO_setb)
412 
413 void
414 _IO_doallocbuf (fp)
415      _IO_FILE *fp;
416 {
417   if (fp->_IO_buf_base)
418     return;
419   if (!(fp->_flags & _IO_UNBUFFERED) || fp->_mode > 0)
420     if (_IO_DOALLOCATE (fp) != EOF)
421       return;
422   INTUSE(_IO_setb) (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
423 }
424 INTDEF(_IO_doallocbuf)
425 
426 int
427 _IO_default_underflow (fp)
428      _IO_FILE *fp;
429 {
430   return EOF;
431 }
432 
433 int
434 _IO_default_uflow (fp)
435      _IO_FILE *fp;
436 {
437   int ch = _IO_UNDERFLOW (fp);
438   if (ch == EOF)
439     return EOF;
440   return *(unsigned char *) fp->_IO_read_ptr++;
441 }
442 INTDEF(_IO_default_uflow)
443 
444 _IO_size_t
445 _IO_default_xsputn (f, data, n)
446      _IO_FILE *f;
447      const void *data;
448      _IO_size_t n;
449 {
450   const char *s = (char *) data;
451   _IO_size_t more = n;
452   if (more <= 0)
453     return 0;
454   for (;;)
455     {
456       /* Space available. */
457       _IO_ssize_t count = f->_IO_write_end - f->_IO_write_ptr;
458       if (count > 0)
459 	{
460 	  if ((_IO_size_t) count > more)
461 	    count = more;
462 	  if (count > 20)
463 	    {
464 #ifdef _LIBC
465 	      f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
466 #else
467 	      memcpy (f->_IO_write_ptr, s, count);
468 	      f->_IO_write_ptr += count;
469 #endif
470 	      s += count;
471             }
472 	  else if (count <= 0)
473 	    count = 0;
474 	  else
475 	    {
476 	      char *p = f->_IO_write_ptr;
477 	      _IO_ssize_t i;
478 	      for (i = count; --i >= 0; )
479 		*p++ = *s++;
480 	      f->_IO_write_ptr = p;
481             }
482 	  more -= count;
483         }
484       if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)
485 	break;
486       more--;
487     }
488   return n - more;
489 }
490 INTDEF(_IO_default_xsputn)
491 
492 _IO_size_t
493 _IO_sgetn (fp, data, n)
494      _IO_FILE *fp;
495      void *data;
496      _IO_size_t n;
497 {
498   /* FIXME handle putback buffer here! */
499   return _IO_XSGETN (fp, data, n);
500 }
501 INTDEF(_IO_sgetn)
502 
503 _IO_size_t
504 _IO_default_xsgetn (fp, data, n)
505      _IO_FILE *fp;
506      void *data;
507      _IO_size_t n;
508 {
509   _IO_size_t more = n;
510   char *s = (char*) data;
511   for (;;)
512     {
513       /* Data available. */
514       _IO_ssize_t count = fp->_IO_read_end - fp->_IO_read_ptr;
515       if (count > 0)
516 	{
517 	  if ((_IO_size_t) count > more)
518 	    count = more;
519 	  if (count > 20)
520 	    {
521 #ifdef _LIBC
522 	      s = __mempcpy (s, fp->_IO_read_ptr, count);
523 #else
524 	      memcpy (s, fp->_IO_read_ptr, count);
525 	      s += count;
526 #endif
527 	      fp->_IO_read_ptr += count;
528 	    }
529 	  else if (count <= 0)
530 	    count = 0;
531 	  else
532 	    {
533 	      char *p = fp->_IO_read_ptr;
534 	      int i = (int) count;
535 	      while (--i >= 0)
536 		*s++ = *p++;
537 	      fp->_IO_read_ptr = p;
538             }
539             more -= count;
540         }
541       if (more == 0 || __underflow (fp) == EOF)
542 	break;
543     }
544   return n - more;
545 }
546 INTDEF(_IO_default_xsgetn)
547 
548 #if 0
549 /* Seems not to be needed. --drepper */
550 int
551 _IO_sync (fp)
552      _IO_FILE *fp;
553 {
554   return 0;
555 }
556 #endif
557 
558 _IO_FILE *
559 _IO_default_setbuf (fp, p, len)
560      _IO_FILE *fp;
561      char *p;
562      _IO_ssize_t len;
563 {
564     if (_IO_SYNC (fp) == EOF)
565 	return NULL;
566     if (p == NULL || len == 0)
567       {
568 	fp->_flags |= _IO_UNBUFFERED;
569 	INTUSE(_IO_setb) (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
570       }
571     else
572       {
573 	fp->_flags &= ~_IO_UNBUFFERED;
574 	INTUSE(_IO_setb) (fp, p, p+len, 0);
575       }
576     fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = 0;
577     fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end = 0;
578     return fp;
579 }
580 
581 _IO_off64_t
582 _IO_default_seekpos (fp, pos, mode)
583      _IO_FILE *fp;
584      _IO_off64_t pos;
585      int mode;
586 {
587   return _IO_SEEKOFF (fp, pos, 0, mode);
588 }
589 
590 int
591 _IO_default_doallocate (fp)
592      _IO_FILE *fp;
593 {
594   char *buf;
595 
596   ALLOC_BUF (buf, _IO_BUFSIZ, EOF);
597   INTUSE(_IO_setb) (fp, buf, buf+_IO_BUFSIZ, 1);
598   return 1;
599 }
600 INTDEF(_IO_default_doallocate)
601 
602 void
603 _IO_init (fp, flags)
604      _IO_FILE *fp;
605      int flags;
606 {
607   _IO_no_init (fp, flags, -1, NULL, NULL);
608 }
609 INTDEF(_IO_init)
610 
611 void
612 _IO_no_init (fp, flags, orientation, wd, jmp)
613      _IO_FILE *fp;
614      int flags;
615      int orientation;
616      struct _IO_wide_data *wd;
617      struct _IO_jump_t *jmp;
618 {
619   fp->_flags = _IO_MAGIC|flags;
620   fp->_flags2 = 0;
621   fp->_IO_buf_base = NULL;
622   fp->_IO_buf_end = NULL;
623   fp->_IO_read_base = NULL;
624   fp->_IO_read_ptr = NULL;
625   fp->_IO_read_end = NULL;
626   fp->_IO_write_base = NULL;
627   fp->_IO_write_ptr = NULL;
628   fp->_IO_write_end = NULL;
629   fp->_chain = NULL; /* Not necessary. */
630 
631   fp->_IO_save_base = NULL;
632   fp->_IO_backup_base = NULL;
633   fp->_IO_save_end = NULL;
634   fp->_markers = NULL;
635   fp->_cur_column = 0;
636 #if _IO_JUMPS_OFFSET
637   fp->_vtable_offset = 0;
638 #endif
639 #ifdef _IO_MTSAFE_IO
640   if (fp->_lock != NULL)
641     _IO_lock_init (*fp->_lock);
642 #endif
643   fp->_mode = orientation;
644 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
645   if (orientation >= 0)
646     {
647       fp->_wide_data = wd;
648       fp->_wide_data->_IO_buf_base = NULL;
649       fp->_wide_data->_IO_buf_end = NULL;
650       fp->_wide_data->_IO_read_base = NULL;
651       fp->_wide_data->_IO_read_ptr = NULL;
652       fp->_wide_data->_IO_read_end = NULL;
653       fp->_wide_data->_IO_write_base = NULL;
654       fp->_wide_data->_IO_write_ptr = NULL;
655       fp->_wide_data->_IO_write_end = NULL;
656       fp->_wide_data->_IO_save_base = NULL;
657       fp->_wide_data->_IO_backup_base = NULL;
658       fp->_wide_data->_IO_save_end = NULL;
659 
660       fp->_wide_data->_wide_vtable = jmp;
661     }
662 #endif
663 }
664 
665 int
666 _IO_default_sync (fp)
667      _IO_FILE *fp;
668 {
669   return 0;
670 }
671 
672 /* The way the C++ classes are mapped into the C functions in the
673    current implementation, this function can get called twice! */
674 
675 void
676 _IO_default_finish (fp, dummy)
677      _IO_FILE *fp;
678      int dummy;
679 {
680   struct _IO_marker *mark;
681   if (fp->_IO_buf_base && !(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   int result = INTUSE(_IO_flush_all) ();
945 
946   /* We currently don't have a reliable mechanism for making sure that
947      C++ static destructors are executed in the correct order.
948      So it is possible that other static destructors might want to
949      write to cout - and they're supposed to be able to do so.
950 
951      The following will make the standard streambufs be unbuffered,
952      which forces any output from late destructors to be written out. */
953   _IO_unbuffer_write ();
954 
955   return result;
956 }
957 
958 
959 void
960 _IO_init_marker (marker, fp)
961      struct _IO_marker *marker;
962      _IO_FILE *fp;
963 {
964   marker->_sbuf = fp;
965   if (_IO_in_put_mode (fp))
966     INTUSE(_IO_switch_to_get_mode) (fp);
967   if (_IO_in_backup (fp))
968     marker->_pos = fp->_IO_read_ptr - fp->_IO_read_end;
969   else
970     marker->_pos = fp->_IO_read_ptr - fp->_IO_read_base;
971 
972   /* Should perhaps sort the chain? */
973   marker->_next = fp->_markers;
974   fp->_markers = marker;
975 }
976 
977 void
978 _IO_remove_marker (marker)
979      struct _IO_marker *marker;
980 {
981   /* Unlink from sb's chain. */
982   struct _IO_marker **ptr = &marker->_sbuf->_markers;
983   for (; ; ptr = &(*ptr)->_next)
984     {
985       if (*ptr == NULL)
986 	break;
987       else if (*ptr == marker)
988 	{
989 	  *ptr = marker->_next;
990 	  return;
991 	}
992     }
993 #if 0
994     if _sbuf has a backup area that is no longer needed, should we delete
995     it now, or wait until the next underflow?
996 #endif
997 }
998 
999 #define BAD_DELTA EOF
1000 
1001 int
1002 _IO_marker_difference (mark1, mark2)
1003      struct _IO_marker *mark1;
1004      struct _IO_marker *mark2;
1005 {
1006   return mark1->_pos - mark2->_pos;
1007 }
1008 
1009 /* Return difference between MARK and current position of MARK's stream. */
1010 int
1011 _IO_marker_delta (mark)
1012      struct _IO_marker *mark;
1013 {
1014   int cur_pos;
1015   if (mark->_sbuf == NULL)
1016     return BAD_DELTA;
1017   if (_IO_in_backup (mark->_sbuf))
1018     cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_end;
1019   else
1020     cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_base;
1021   return mark->_pos - cur_pos;
1022 }
1023 
1024 int
1025 _IO_seekmark (fp, mark, delta)
1026      _IO_FILE *fp;
1027      struct _IO_marker *mark;
1028      int delta;
1029 {
1030   if (mark->_sbuf != fp)
1031     return EOF;
1032  if (mark->_pos >= 0)
1033     {
1034       if (_IO_in_backup (fp))
1035 	_IO_switch_to_main_get_area (fp);
1036       fp->_IO_read_ptr = fp->_IO_read_base + mark->_pos;
1037     }
1038   else
1039     {
1040       if (!_IO_in_backup (fp))
1041 	_IO_switch_to_backup_area (fp);
1042       fp->_IO_read_ptr = fp->_IO_read_end + mark->_pos;
1043     }
1044   return 0;
1045 }
1046 
1047 void
1048 _IO_unsave_markers (fp)
1049      _IO_FILE *fp;
1050 {
1051   struct _IO_marker *mark = fp->_markers;
1052   if (mark)
1053     {
1054 #ifdef TODO
1055       streampos offset = seekoff (0, ios::cur, ios::in);
1056       if (offset != EOF)
1057 	{
1058 	  offset += eGptr () - Gbase ();
1059 	  for ( ; mark != NULL; mark = mark->_next)
1060 	    mark->set_streampos (mark->_pos + offset);
1061 	}
1062     else
1063       {
1064 	for ( ; mark != NULL; mark = mark->_next)
1065 	  mark->set_streampos (EOF);
1066       }
1067 #endif
1068       fp->_markers = 0;
1069     }
1070 
1071   if (_IO_have_backup (fp))
1072     INTUSE(_IO_free_backup_area) (fp);
1073 }
1074 INTDEF(_IO_unsave_markers)
1075 
1076 #if 0
1077 /* Seems not to be needed. --drepper */
1078 int
1079 _IO_nobackup_pbackfail (fp, c)
1080      _IO_FILE *fp;
1081      int c;
1082 {
1083   if (fp->_IO_read_ptr > fp->_IO_read_base)
1084 	fp->_IO_read_ptr--;
1085   if (c != EOF && *fp->_IO_read_ptr != c)
1086       *fp->_IO_read_ptr = c;
1087   return (unsigned char) c;
1088 }
1089 #endif
1090 
1091 int
1092 _IO_default_pbackfail (fp, c)
1093      _IO_FILE *fp;
1094      int c;
1095 {
1096   if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp)
1097       && (unsigned char) fp->_IO_read_ptr[-1] == c)
1098     --fp->_IO_read_ptr;
1099   else
1100     {
1101       /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
1102       if (!_IO_in_backup (fp))
1103 	{
1104 	  /* We need to keep the invariant that the main get area
1105 	     logically follows the backup area.  */
1106 	  if (fp->_IO_read_ptr > fp->_IO_read_base && _IO_have_backup (fp))
1107 	    {
1108 	      if (save_for_backup (fp, fp->_IO_read_ptr))
1109 		return EOF;
1110 	    }
1111 	  else if (!_IO_have_backup (fp))
1112 	    {
1113 	      /* No backup buffer: allocate one. */
1114 	      /* Use nshort buffer, if unused? (probably not)  FIXME */
1115 	      int backup_size = 128;
1116 	      char *bbuf = (char *) malloc (backup_size);
1117 	      if (bbuf == NULL)
1118 		return EOF;
1119 	      fp->_IO_save_base = bbuf;
1120 	      fp->_IO_save_end = fp->_IO_save_base + backup_size;
1121 	      fp->_IO_backup_base = fp->_IO_save_end;
1122 	    }
1123 	  fp->_IO_read_base = fp->_IO_read_ptr;
1124 	  _IO_switch_to_backup_area (fp);
1125 	}
1126       else if (fp->_IO_read_ptr <= fp->_IO_read_base)
1127 	{
1128 	  /* Increase size of existing backup buffer. */
1129 	  _IO_size_t new_size;
1130 	  _IO_size_t old_size = fp->_IO_read_end - fp->_IO_read_base;
1131 	  char *new_buf;
1132 	  new_size = 2 * old_size;
1133 	  new_buf = (char *) malloc (new_size);
1134 	  if (new_buf == NULL)
1135 	    return EOF;
1136 	  memcpy (new_buf + (new_size - old_size), fp->_IO_read_base,
1137 		  old_size);
1138 	  free (fp->_IO_read_base);
1139 	  _IO_setg (fp, new_buf, new_buf + (new_size - old_size),
1140 		    new_buf + new_size);
1141 	  fp->_IO_backup_base = fp->_IO_read_ptr;
1142 	}
1143 
1144       *--fp->_IO_read_ptr = c;
1145     }
1146   return (unsigned char) c;
1147 }
1148 INTDEF(_IO_default_pbackfail)
1149 
1150 _IO_off64_t
1151 _IO_default_seek (fp, offset, dir)
1152      _IO_FILE *fp;
1153      _IO_off64_t offset;
1154      int dir;
1155 {
1156   return _IO_pos_BAD;
1157 }
1158 
1159 int
1160 _IO_default_stat (fp, st)
1161      _IO_FILE *fp;
1162      void* st;
1163 {
1164   return EOF;
1165 }
1166 
1167 _IO_ssize_t
1168 _IO_default_read (fp, data, n)
1169      _IO_FILE* fp;
1170      void *data;
1171      _IO_ssize_t n;
1172 {
1173   return -1;
1174 }
1175 
1176 _IO_ssize_t
1177 _IO_default_write (fp, data, n)
1178      _IO_FILE *fp;
1179      const void *data;
1180      _IO_ssize_t n;
1181 {
1182   return 0;
1183 }
1184 
1185 int
1186 _IO_default_showmanyc (fp)
1187      _IO_FILE *fp;
1188 {
1189   return -1;
1190 }
1191 
1192 void
1193 _IO_default_imbue (fp, locale)
1194      _IO_FILE *fp;
1195      void *locale;
1196 {
1197 }
1198 
1199 _IO_ITER
1200 _IO_iter_begin()
1201 {
1202   return (_IO_ITER) INTUSE(_IO_list_all);
1203 }
1204 libc_hidden_def (_IO_iter_begin)
1205 
1206 _IO_ITER
1207 _IO_iter_end()
1208 {
1209   return NULL;
1210 }
1211 libc_hidden_def (_IO_iter_end)
1212 
1213 _IO_ITER
1214 _IO_iter_next(iter)
1215     _IO_ITER iter;
1216 {
1217   return iter->_chain;
1218 }
1219 libc_hidden_def (_IO_iter_next)
1220 
1221 _IO_FILE *
1222 _IO_iter_file(iter)
1223     _IO_ITER iter;
1224 {
1225   return iter;
1226 }
1227 libc_hidden_def (_IO_iter_file)
1228 
1229 void
1230 _IO_list_lock()
1231 {
1232 #ifdef _IO_MTSAFE_IO
1233   _IO_lock_lock (list_all_lock);
1234 #endif
1235 }
1236 libc_hidden_def (_IO_list_lock)
1237 
1238 void
1239 _IO_list_unlock()
1240 {
1241 #ifdef _IO_MTSAFE_IO
1242   _IO_lock_unlock (list_all_lock);
1243 #endif
1244 }
1245 libc_hidden_def (_IO_list_unlock)
1246 
1247 void
1248 _IO_list_resetlock()
1249 {
1250 #ifdef _IO_MTSAFE_IO
1251   _IO_lock_init (list_all_lock);
1252 #endif
1253 }
1254 libc_hidden_def (_IO_list_resetlock)
1255 
1256 
1257 #ifdef TODO
1258 #if defined(linux)
1259 #define IO_CLEANUP ;
1260 #endif
1261 
1262 #ifdef IO_CLEANUP
1263   IO_CLEANUP
1264 #else
1265 struct __io_defs {
1266     __io_defs() { }
1267     ~__io_defs() { _IO_cleanup (); }
1268 };
1269 __io_defs io_defs__;
1270 #endif
1271 
1272 #endif /* TODO */
1273 
1274 #ifdef text_set_element
1275 text_set_element(__libc_atexit, _IO_cleanup);
1276 #endif
1277