Optimize a bit by using mempcpy.
[kopensolaris-gnu/glibc.git] / libio / genops.c
1 /* Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU IO Library.
3
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2, or (at
7    your option) any later version.
8
9    This library is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this library; see the file COPYING.  If not, write to
16    the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
17    MA 02111-1307, USA.
18
19    As a special exception, if you link this library with files
20    compiled with a GNU compiler to produce an executable, this does
21    not cause the resulting executable to be covered by the GNU General
22    Public License.  This exception does not however invalidate any
23    other reasons why the executable file might be covered by the GNU
24    General Public License.  */
25
26 /* Generic or default I/O operations. */
27
28 #include "libioP.h"
29 #ifdef __STDC__
30 #include <stdlib.h>
31 #endif
32 #include <string.h>
33
34 void
35 _IO_un_link (fp)
36      _IO_FILE *fp;
37 {
38   if (fp->_flags & _IO_LINKED)
39     {
40       _IO_FILE **f;
41       for (f = &_IO_list_all; *f != NULL; f = &(*f)->_chain)
42         {
43           if (*f == fp)
44             {
45               *f = fp->_chain;
46               break;
47             }
48         }
49       fp->_flags &= ~_IO_LINKED;
50     }
51 }
52
53 void
54 _IO_link_in (fp)
55      _IO_FILE *fp;
56 {
57     if ((fp->_flags & _IO_LINKED) == 0)
58       {
59         fp->_flags |= _IO_LINKED;
60         fp->_chain = _IO_list_all;
61         _IO_list_all = fp;
62       }
63 }
64
65 /* Return minimum _pos markers
66    Assumes the current get area is the main get area. */
67 static _IO_size_t _IO_least_marker __P ((_IO_FILE *fp));
68
69 static _IO_size_t
70 _IO_least_marker (fp)
71      _IO_FILE *fp;
72 {
73   _IO_ssize_t least_so_far = fp->_IO_read_end - fp->_IO_read_base;
74   struct _IO_marker *mark;
75   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
76     if (mark->_pos < least_so_far)
77       least_so_far = mark->_pos;
78   return least_so_far;
79 }
80
81 /* Switch current get area from backup buffer to (start of) main get area. */
82
83 void
84 _IO_switch_to_main_get_area (fp)
85      _IO_FILE *fp;
86 {
87   char *tmp;
88   fp->_flags &= ~_IO_IN_BACKUP;
89   /* Swap _IO_read_end and _IO_save_end. */
90   tmp = fp->_IO_read_end;
91   fp->_IO_read_end = fp->_IO_save_end;
92   fp->_IO_save_end= tmp;
93   /* Swap _IO_read_base and _IO_save_base. */
94   tmp = fp->_IO_read_base;
95   fp->_IO_read_base = fp->_IO_save_base;
96   fp->_IO_save_base = tmp;
97
98   fp->_IO_read_ptr = fp->_IO_read_base;
99 }
100
101 /* Switch current get area from main get area to (end of) backup area. */
102
103 void
104 _IO_switch_to_backup_area (fp)
105      _IO_FILE *fp;
106 {
107   char *tmp;
108   fp->_flags |= _IO_IN_BACKUP;
109   /* Swap _IO_read_end and _IO_save_end. */
110   tmp = fp->_IO_read_end;
111   fp->_IO_read_end = fp->_IO_save_end;
112   fp->_IO_save_end = tmp;
113   /* Swap _gbase and _IO_save_base. */
114   tmp = fp->_IO_read_base;
115   fp->_IO_read_base = fp->_IO_save_base;
116   fp->_IO_save_base = tmp;
117
118   fp->_IO_read_ptr = fp->_IO_read_end;
119 }
120
121 int
122 _IO_switch_to_get_mode (fp)
123      _IO_FILE *fp;
124 {
125   if (fp->_IO_write_ptr > fp->_IO_write_base)
126     if (_IO_OVERFLOW (fp, EOF) == EOF)
127       return EOF;
128   if (_IO_in_backup (fp))
129     fp->_IO_read_base = fp->_IO_backup_base;
130   else
131     {
132       fp->_IO_read_base = fp->_IO_buf_base;
133       if (fp->_IO_write_ptr > fp->_IO_read_end)
134         fp->_IO_read_end = fp->_IO_write_ptr;
135     }
136   fp->_IO_read_ptr = fp->_IO_write_ptr;
137
138   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = fp->_IO_read_ptr;
139
140   fp->_flags &= ~_IO_CURRENTLY_PUTTING;
141   return 0;
142 }
143
144 void
145 _IO_free_backup_area (fp)
146      _IO_FILE *fp;
147 {
148   if (_IO_in_backup (fp))
149     _IO_switch_to_main_get_area (fp);  /* Just in case. */
150   free (fp->_IO_save_base);
151   fp->_IO_save_base = NULL;
152   fp->_IO_save_end = NULL;
153   fp->_IO_backup_base = NULL;
154 }
155
156 #if 0
157 int
158 _IO_switch_to_put_mode (fp)
159      _IO_FILE *fp;
160 {
161   fp->_IO_write_base = fp->_IO_read_ptr;
162   fp->_IO_write_ptr = fp->_IO_read_ptr;
163   /* Following is wrong if line- or un-buffered? */
164   fp->_IO_write_end = (fp->_flags & _IO_IN_BACKUP
165                        ? fp->_IO_read_end : fp->_IO_buf_end);
166
167   fp->_IO_read_ptr = fp->_IO_read_end;
168   fp->_IO_read_base = fp->_IO_read_end;
169
170   fp->_flags |= _IO_CURRENTLY_PUTTING;
171   return 0;
172 }
173 #endif
174
175 int
176 __overflow (f, ch)
177      _IO_FILE *f;
178      int ch;
179 {
180   return _IO_OVERFLOW (f, ch);
181 }
182
183 static int save_for_backup __P ((_IO_FILE *fp))
184 #ifdef _LIBC
185      internal_function
186 #endif
187      ;
188
189      static int
190 #ifdef _LIBC
191      internal_function
192 #endif
193 save_for_backup (fp)
194      _IO_FILE *fp;
195 {
196   /* Append [_IO_read_base.._IO_read_end] to backup area. */
197   int least_mark = _IO_least_marker (fp);
198   /* needed_size is how much space we need in the backup area. */
199   int needed_size = (fp->_IO_read_end - fp->_IO_read_base) - least_mark;
200   int current_Bsize = fp->_IO_save_end - fp->_IO_save_base;
201   int avail; /* Extra space available for future expansion. */
202   int delta;
203   struct _IO_marker *mark;
204   if (needed_size > current_Bsize)
205     {
206       char *new_buffer;
207       avail = 100;
208       new_buffer = (char *) malloc (avail + needed_size);
209       if (new_buffer == NULL)
210         return EOF;             /* FIXME */
211       if (least_mark < 0)
212         {
213 #ifdef _LIBC
214           __mempcpy (__mempcpy (new_buffer + avail,
215                                 fp->_IO_save_end + least_mark,
216                                 -least_mark),
217                      fp->_IO_read_base,
218                      fp->_IO_read_end - fp->_IO_read_base);
219 #else
220           memcpy (new_buffer + avail,
221                   fp->_IO_save_end + least_mark,
222                   -least_mark);
223           memcpy (new_buffer + avail - least_mark,
224                   fp->_IO_read_base,
225                   fp->_IO_read_end - fp->_IO_read_base);
226 #endif
227         }
228       else
229         memcpy (new_buffer + avail,
230                 fp->_IO_read_base + least_mark,
231                 needed_size);
232       if (fp->_IO_save_base)
233         free (fp->_IO_save_base);
234       fp->_IO_save_base = new_buffer;
235       fp->_IO_save_end = new_buffer + avail + needed_size;
236     }
237   else
238     {
239       avail = current_Bsize - needed_size;
240       if (least_mark < 0)
241         {
242           memmove (fp->_IO_save_base + avail,
243                    fp->_IO_save_end + least_mark,
244                    -least_mark);
245           memcpy (fp->_IO_save_base + avail - least_mark,
246                   fp->_IO_read_base,
247                   fp->_IO_read_end - fp->_IO_read_base);
248         }
249       else if (needed_size > 0)
250         memcpy (fp->_IO_save_base + avail,
251                 fp->_IO_read_base + least_mark,
252                 needed_size);
253     }
254   /* FIXME: Dubious arithmetic if pointers are NULL */
255   fp->_IO_backup_base = fp->_IO_save_base + avail;
256   /* Adjust all the streammarkers. */
257   delta = fp->_IO_read_end - fp->_IO_read_base;
258   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
259     mark->_pos -= delta;
260   return 0;
261 }
262
263 int
264 __underflow (fp)
265      _IO_FILE *fp;
266 {
267   if (_IO_in_put_mode (fp))
268     if (_IO_switch_to_get_mode (fp) == EOF)
269       return EOF;
270   if (fp->_IO_read_ptr < fp->_IO_read_end)
271     return *(unsigned char *) fp->_IO_read_ptr;
272   if (_IO_in_backup (fp))
273     {
274       _IO_switch_to_main_get_area (fp);
275       if (fp->_IO_read_ptr < fp->_IO_read_end)
276         return *fp->_IO_read_ptr;
277     }
278   if (_IO_have_markers (fp))
279     {
280       if (save_for_backup (fp))
281         return EOF;
282     }
283   else if (_IO_have_backup (fp))
284     _IO_free_backup_area (fp);
285   return _IO_UNDERFLOW (fp);
286 }
287
288 int
289 __uflow (fp)
290      _IO_FILE *fp;
291 {
292   if (_IO_in_put_mode (fp))
293     if (_IO_switch_to_get_mode (fp) == EOF)
294       return EOF;
295   if (fp->_IO_read_ptr < fp->_IO_read_end)
296     return *(unsigned char *) fp->_IO_read_ptr++;
297   if (_IO_in_backup (fp))
298     {
299       _IO_switch_to_main_get_area (fp);
300       if (fp->_IO_read_ptr < fp->_IO_read_end)
301         return *fp->_IO_read_ptr++;
302     }
303   if (_IO_have_markers (fp))
304     {
305       if (save_for_backup (fp))
306         return EOF;
307     }
308   else if (_IO_have_backup (fp))
309     _IO_free_backup_area (fp);
310   return _IO_UFLOW (fp);
311 }
312
313 void
314 _IO_setb (f, b, eb, a)
315      _IO_FILE *f;
316       char *b;
317      char *eb;
318      int a;
319 {
320   if (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF))
321     FREE_BUF (f->_IO_buf_base, _IO_blen (f));
322   f->_IO_buf_base = b;
323   f->_IO_buf_end = eb;
324   if (a)
325     f->_flags &= ~_IO_USER_BUF;
326   else
327     f->_flags |= _IO_USER_BUF;
328 }
329
330 void
331 _IO_doallocbuf (fp)
332      _IO_FILE *fp;
333 {
334   if (fp->_IO_buf_base)
335     return;
336   if (!(fp->_flags & _IO_UNBUFFERED))
337     if (_IO_DOALLOCATE (fp) != EOF)
338       return;
339   _IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
340 }
341
342 int
343 _IO_default_underflow (fp)
344      _IO_FILE *fp;
345 {
346   return EOF;
347 }
348
349 int
350 _IO_default_uflow (fp)
351      _IO_FILE *fp;
352 {
353   int ch = _IO_UNDERFLOW (fp);
354   if (ch == EOF)
355     return EOF;
356   return *(unsigned char *) fp->_IO_read_ptr++;
357 }
358
359 _IO_size_t
360 _IO_default_xsputn (f, data, n)
361      _IO_FILE *f;
362      const void *data;
363      _IO_size_t n;
364 {
365   const char *s = (char *) data;
366   _IO_size_t more = n;
367   if (more <= 0)
368     return 0;
369   for (;;)
370     {
371       /* Space available. */
372       _IO_ssize_t count = f->_IO_write_end - f->_IO_write_ptr;
373       if (count > 0)
374         {
375           if ((_IO_size_t) count > more)
376             count = more;
377           if (count > 20)
378             {
379 #ifdef _LIBC
380               f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
381 #else
382               memcpy (f->_IO_write_ptr, s, count);
383               f->_IO_write_ptr += count;
384 #endif
385               s += count;
386             }
387           else if (count <= 0)
388             count = 0;
389           else
390             {
391               char *p = f->_IO_write_ptr;
392               _IO_ssize_t i;
393               for (i = count; --i >= 0; )
394                 *p++ = *s++;
395               f->_IO_write_ptr = p;
396             }
397           more -= count;
398         }
399       if (more == 0 || __overflow (f, (unsigned char) *s++) == EOF)
400         break;
401       more--;
402     }
403   return n - more;
404 }
405
406 _IO_size_t
407 _IO_sgetn (fp, data, n)
408      _IO_FILE *fp;
409      void *data;
410      _IO_size_t n;
411 {
412   /* FIXME handle putback buffer here! */
413   return _IO_XSGETN (fp, data, n);
414 }
415
416 _IO_size_t
417 _IO_default_xsgetn (fp, data, n)
418      _IO_FILE *fp;
419      void *data;
420      _IO_size_t n;
421 {
422   _IO_size_t more = n;
423   char *s = (char*) data;
424   for (;;)
425     {
426       /* Data available. */
427       _IO_ssize_t count = fp->_IO_read_end - fp->_IO_read_ptr;
428       if (count > 0)
429         {
430           if ((_IO_size_t) count > more)
431             count = more;
432           if (count > 20)
433             {
434 #ifdef _LIBC
435               s = __mempcpy (s, fp->_IO_read_ptr, count);
436 #else
437               memcpy (s, fp->_IO_read_ptr, count);
438               s += count;
439 #endif
440               fp->_IO_read_ptr += count;
441             }
442           else if (count <= 0)
443             count = 0;
444           else
445             {
446               char *p = fp->_IO_read_ptr;
447               int i = (int) count;
448               while (--i >= 0)
449                 *s++ = *p++;
450               fp->_IO_read_ptr = p;
451             }
452             more -= count;
453         }
454       if (more == 0 || __underflow (fp) == EOF)
455         break;
456     }
457   return n - more;
458 }
459
460 #if 0
461 /* Seems not to be needed. --drepper */
462 int
463 _IO_sync (fp)
464      _IO_FILE *fp;
465 {
466   return 0;
467 }
468 #endif
469
470 _IO_FILE *
471 _IO_default_setbuf (fp, p, len)
472      _IO_FILE *fp;
473      char *p;
474      _IO_ssize_t len;
475 {
476     if (_IO_SYNC (fp) == EOF)
477         return NULL;
478     if (p == NULL || len == 0)
479       {
480         fp->_flags |= _IO_UNBUFFERED;
481         _IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
482       }
483     else
484       {
485         fp->_flags &= ~_IO_UNBUFFERED;
486         _IO_setb (fp, p, p+len, 0);
487       }
488     fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = 0;
489     fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end = 0;
490     return fp;
491 }
492
493 _IO_fpos64_t
494 _IO_default_seekpos (fp, pos, mode)
495      _IO_FILE *fp;
496      _IO_fpos64_t pos;
497      int mode;
498 {
499   return _IO_SEEKOFF (fp, _IO_pos_as_off (pos), 0, mode);
500 }
501
502 int
503 _IO_default_doallocate (fp)
504      _IO_FILE *fp;
505 {
506   char *buf;
507
508   ALLOC_BUF (buf, _IO_BUFSIZ, EOF);
509   _IO_setb (fp, buf, buf+_IO_BUFSIZ, 1);
510   return 1;
511 }
512
513 void
514 _IO_init (fp, flags)
515      _IO_FILE *fp;
516      int flags;
517 {
518   fp->_flags = _IO_MAGIC|flags;
519   fp->_IO_buf_base = NULL;
520   fp->_IO_buf_end = NULL;
521   fp->_IO_read_base = NULL;
522   fp->_IO_read_ptr = NULL;
523   fp->_IO_read_end = NULL;
524   fp->_IO_write_base = NULL;
525   fp->_IO_write_ptr = NULL;
526   fp->_IO_write_end = NULL;
527   fp->_chain = NULL; /* Not necessary. */
528
529   fp->_IO_save_base = NULL;
530   fp->_IO_backup_base = NULL;
531   fp->_IO_save_end = NULL;
532   fp->_markers = NULL;
533   fp->_cur_column = 0;
534 #ifdef _IO_MTSAFE_IO
535   _IO_lock_init (*fp->_lock);
536 #endif
537 }
538
539 int
540 _IO_default_sync (fp)
541      _IO_FILE *fp;
542 {
543   return 0;
544 }
545
546 /* The way the C++ classes are mapped into the C functions in the
547    current implementation, this function can get called twice! */
548
549 void
550 _IO_default_finish (fp, dummy)
551      _IO_FILE *fp;
552      int dummy;
553 {
554   struct _IO_marker *mark;
555   if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
556     {
557       FREE_BUF (fp->_IO_buf_base, _IO_blen (fp));
558       fp->_IO_buf_base = fp->_IO_buf_end = NULL;
559     }
560
561   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
562     mark->_sbuf = NULL;
563
564   if (fp->_IO_save_base)
565     {
566       free (fp->_IO_save_base);
567       fp->_IO_save_base = NULL;
568     }
569
570 #ifdef _IO_MTSAFE_IO
571   _IO_lock_fini (*fp->_lock);
572 #endif
573
574   _IO_un_link (fp);
575 }
576
577 _IO_fpos64_t
578 _IO_default_seekoff (fp, offset, dir, mode)
579      _IO_FILE *fp;
580      _IO_off64_t offset;
581      int dir;
582      int mode;
583 {
584     return _IO_pos_BAD;
585 }
586
587 int
588 _IO_sputbackc (fp, c)
589      _IO_FILE *fp;
590      int c;
591 {
592   int result;
593
594   if (fp->_IO_read_ptr > fp->_IO_read_base
595       && (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
596     {
597       fp->_IO_read_ptr--;
598       result = (unsigned char) c;
599     }
600   else
601     result = _IO_PBACKFAIL (fp, c);
602
603   if (result != EOF)
604     fp->_flags &= ~_IO_EOF_SEEN;
605
606   return result;
607 }
608
609 int
610 _IO_sungetc (fp)
611      _IO_FILE *fp;
612 {
613   int result;
614
615   if (fp->_IO_read_ptr > fp->_IO_read_base)
616     {
617       fp->_IO_read_ptr--;
618       result = (unsigned char) *fp->_IO_read_ptr;
619     }
620   else
621     result = _IO_PBACKFAIL (fp, EOF);
622
623   if (result != EOF)
624     fp->_flags &= ~_IO_EOF_SEEN;
625
626   return result;
627 }
628
629 #if 0 /* Work in progress */
630 /* Seems not to be needed.  */
631 #if 0
632 void
633 _IO_set_column (fp, c)
634      _IO_FILE *fp;
635      int c;
636 {
637   if (c == -1)
638     fp->_column = -1;
639   else
640     fp->_column = c - (fp->_IO_write_ptr - fp->_IO_write_base);
641 }
642 #else
643 int
644 _IO_set_column (fp, i)
645      _IO_FILE *fp;
646      int i;
647 {
648   fp->_cur_column = i + 1;
649   return 0;
650 }
651 #endif
652 #endif
653
654
655 unsigned
656 _IO_adjust_column (start, line, count)
657      unsigned start;
658      const char *line;
659      int count;
660 {
661   const char *ptr = line + count;
662   while (ptr > line)
663     if (*--ptr == '\n')
664       return line + count - ptr - 1;
665   return start + count;
666 }
667
668 #if 0
669 /* Seems not to be needed. --drepper */
670 int
671 _IO_get_column (fp)
672      _IO_FILE *fp;
673 {
674   if (fp->_cur_column)
675     return _IO_adjust_column (fp->_cur_column - 1,
676                               fp->_IO_write_base,
677                               fp->_IO_write_ptr - fp->_IO_write_base);
678   return -1;
679 }
680 #endif
681
682 int
683 _IO_flush_all ()
684 {
685   int result = 0;
686   _IO_FILE *fp;
687   for (fp = _IO_list_all; fp != NULL; fp = fp->_chain)
688     if (fp->_IO_write_ptr > fp->_IO_write_base
689         && _IO_OVERFLOW (fp, EOF) == EOF)
690       result = EOF;
691   return result;
692 }
693
694 void
695 _IO_flush_all_linebuffered ()
696 {
697   _IO_FILE *fp;
698   for (fp = _IO_list_all; fp != NULL; fp = fp->_chain)
699     if ((fp->_flags & _IO_NO_WRITES) == 0 && fp->_flags & _IO_LINE_BUF)
700       _IO_OVERFLOW (fp, EOF);
701 }
702
703 static void _IO_unbuffer_all __P ((void));
704
705 static void
706 _IO_unbuffer_all ()
707 {
708   _IO_FILE *fp;
709   for (fp = _IO_list_all; fp != NULL; fp = fp->_chain)
710     if (! (fp->_flags & _IO_UNBUFFERED))
711       _IO_SETBUF (fp, NULL, 0);
712 }
713
714 void
715 _IO_cleanup ()
716 {
717   _IO_flush_all ();
718
719   /* We currently don't have a reliable mechanism for making sure that
720      C++ static destructors are executed in the correct order.
721      So it is possible that other static destructors might want to
722      write to cout - and they're supposed to be able to do so.
723
724      The following will make the standard streambufs be unbuffered,
725      which forces any output from late destructors to be written out. */
726   _IO_unbuffer_all ();
727 }
728
729
730 void
731 _IO_init_marker (marker, fp)
732      struct _IO_marker *marker;
733      _IO_FILE *fp;
734 {
735   marker->_sbuf = fp;
736   if (_IO_in_put_mode (fp))
737     _IO_switch_to_get_mode (fp);
738   if (_IO_in_backup (fp))
739     marker->_pos = fp->_IO_read_ptr - fp->_IO_read_end;
740   else
741     marker->_pos = fp->_IO_read_ptr - fp->_IO_read_base;
742
743   /* Should perhaps sort the chain? */
744   marker->_next = fp->_markers;
745   fp->_markers = marker;
746 }
747
748 void
749 _IO_remove_marker (marker)
750      struct _IO_marker *marker;
751 {
752   /* Unlink from sb's chain. */
753   struct _IO_marker **ptr = &marker->_sbuf->_markers;
754   for (; ; ptr = &(*ptr)->_next)
755     {
756       if (*ptr == NULL)
757         break;
758       else if (*ptr == marker)
759         {
760           *ptr = marker->_next;
761           return;
762         }
763     }
764 #if 0
765     if _sbuf has a backup area that is no longer needed, should we delete
766     it now, or wait until the next underflow?
767 #endif
768 }
769
770 #define BAD_DELTA EOF
771
772 int
773 _IO_marker_difference (mark1, mark2)
774      struct _IO_marker *mark1;
775      struct _IO_marker *mark2;
776 {
777   return mark1->_pos - mark2->_pos;
778 }
779
780 /* Return difference between MARK and current position of MARK's stream. */
781 int
782 _IO_marker_delta (mark)
783      struct _IO_marker *mark;
784 {
785   int cur_pos;
786   if (mark->_sbuf == NULL)
787     return BAD_DELTA;
788   if (_IO_in_backup (mark->_sbuf))
789     cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_end;
790   else
791     cur_pos = mark->_sbuf->_IO_read_ptr - mark->_sbuf->_IO_read_base;
792   return mark->_pos - cur_pos;
793 }
794
795 int
796 _IO_seekmark (fp, mark, delta)
797      _IO_FILE *fp;
798      struct _IO_marker *mark;
799      int delta;
800 {
801   if (mark->_sbuf != fp)
802     return EOF;
803  if (mark->_pos >= 0)
804     {
805       if (_IO_in_backup (fp))
806         _IO_switch_to_main_get_area (fp);
807       fp->_IO_read_ptr = fp->_IO_read_base + mark->_pos;
808     }
809   else
810     {
811       if (!_IO_in_backup (fp))
812         _IO_switch_to_backup_area (fp);
813       fp->_IO_read_ptr = fp->_IO_read_end + mark->_pos;
814     }
815   return 0;
816 }
817
818 void
819 _IO_unsave_markers (fp)
820      _IO_FILE *fp;
821 {
822   struct _IO_marker *mark = fp->_markers;
823   if (mark)
824     {
825 #ifdef TODO
826       streampos offset = seekoff (0, ios::cur, ios::in);
827       if (offset != EOF)
828         {
829           offset += eGptr () - Gbase ();
830           for ( ; mark != NULL; mark = mark->_next)
831             mark->set_streampos (mark->_pos + offset);
832         }
833     else
834       {
835         for ( ; mark != NULL; mark = mark->_next)
836           mark->set_streampos (EOF);
837       }
838 #endif
839       fp->_markers = 0;
840     }
841
842   if (_IO_have_backup (fp))
843     _IO_free_backup_area (fp);
844 }
845
846 #if 0
847 /* Seems not to be needed. --drepper */
848 int
849 _IO_nobackup_pbackfail (fp, c)
850      _IO_FILE *fp;
851      int c;
852 {
853   if (fp->_IO_read_ptr > fp->_IO_read_base)
854         fp->_IO_read_ptr--;
855   if (c != EOF && *fp->_IO_read_ptr != c)
856       *fp->_IO_read_ptr = c;
857   return (unsigned char) c;
858 }
859 #endif
860
861 int
862 _IO_default_pbackfail (fp, c)
863      _IO_FILE *fp;
864      int c;
865 {
866   if (fp->_IO_read_ptr <= fp->_IO_read_base)
867     {
868       /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
869       if (_IO_have_backup (fp) && !_IO_in_backup (fp))
870         _IO_switch_to_backup_area (fp);
871
872       if (!_IO_have_backup (fp))
873         {
874           /* No backup buffer: allocate one. */
875           /* Use nshort buffer, if unused? (probably not)  FIXME */
876           int backup_size = 128;
877           char *bbuf = (char *) malloc (backup_size);
878           if (bbuf == NULL)
879             return EOF;
880           fp->_IO_save_base = bbuf;
881           fp->_IO_save_end = fp->_IO_save_base + backup_size;
882           fp->_IO_backup_base = fp->_IO_save_end;
883           _IO_switch_to_backup_area (fp);
884         }
885       else if (fp->_IO_read_ptr <= fp->_IO_read_base)
886         {
887           /* Increase size of existing backup buffer. */
888           _IO_size_t new_size;
889           _IO_size_t old_size = fp->_IO_read_end - fp->_IO_read_base;
890           char *new_buf;
891           new_size = 2 * old_size;
892           new_buf = (char *) malloc (new_size);
893           if (new_buf == NULL)
894             return EOF;
895           memcpy (new_buf + (new_size - old_size), fp->_IO_read_base,
896                   old_size);
897           free (fp->_IO_read_base);
898           _IO_setg (fp, new_buf, new_buf + (new_size - old_size),
899                     new_buf + new_size);
900           fp->_IO_backup_base = fp->_IO_read_ptr;
901         }
902     }
903   --fp->_IO_read_ptr;
904   if (c != EOF && *fp->_IO_read_ptr != c)
905     *fp->_IO_read_ptr = c;
906   return (unsigned char) *fp->_IO_read_ptr;
907 }
908
909 _IO_fpos64_t
910 _IO_default_seek (fp, offset, dir)
911      _IO_FILE *fp;
912      _IO_off64_t offset;
913      int dir;
914 {
915   return _IO_pos_BAD;
916 }
917
918 int
919 _IO_default_stat (fp, st)
920      _IO_FILE *fp;
921      void* st;
922 {
923   return EOF;
924 }
925
926 _IO_ssize_t
927 _IO_default_read (fp, data, n)
928      _IO_FILE* fp;
929      void *data;
930      _IO_ssize_t n;
931 {
932   return -1;
933 }
934
935 _IO_ssize_t
936 _IO_default_write (fp, data, n)
937      _IO_FILE *fp;
938      const void *data;
939      _IO_ssize_t n;
940 {
941   return 0;
942 }
943
944 int
945 _IO_default_showmanyc (fp)
946      _IO_FILE *fp;
947 {
948   return -1;
949 }
950
951 void
952 _IO_default_imbue (fp, locale)
953      _IO_FILE *fp;
954      void *locale;
955 {
956 }
957
958
959 #ifdef TODO
960 #if defined(linux)
961 #define IO_CLEANUP ;
962 #endif
963
964 #ifdef IO_CLEANUP
965   IO_CLEANUP
966 #else
967 struct __io_defs {
968     __io_defs() { }
969     ~__io_defs() { _IO_cleanup (); }
970 };
971 __io_defs io_defs__;
972 #endif
973
974 #endif /* TODO */
975
976 #ifdef weak_alias
977 weak_alias (_IO_cleanup, _cleanup)
978 #endif
979
980 #ifdef text_set_element
981 text_set_element(__libc_atexit, _cleanup);
982 #endif