1/* Copyright (C) 1993,1995,1997-2001,2002 Free Software Foundation, Inc.
2   This file is part of the GNU C Library.
3   Written by Ulrich Drepper <drepper@cygnus.com>.
4   Based on the single byte version by Per Bothner <bothner@cygnus.com>.
5
6   The GNU C Library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either
9   version 2.1 of the License, or (at your option) any later version.
10
11   The GNU C Library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with the GNU C Library; if not, write to the Free
18   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19   02111-1307 USA.
20
21   As a special exception, if you link the code in this file with
22   files compiled with a GNU compiler to produce an executable,
23   that does not cause the resulting executable to be covered by
24   the GNU Lesser General Public License.  This exception does not
25   however invalidate any other reasons why the executable file
26   might be covered by the GNU Lesser General Public License.
27   This exception applies to code released by its copyright holders
28   in files containing the exception.  */
29
30/* Generic or default I/O operations. */
31
32#include "libioP.h"
33#ifdef __STDC__
34#include <stdlib.h>
35#endif
36#include <string.h>
37#include <wchar.h>
38
39
40#ifndef _LIBC
41# define __wmemcpy(dst, src, n) wmemcpy (dst, src, n)
42#endif
43
44
45static int save_for_wbackup __P ((_IO_FILE *fp, wchar_t *end_p))
46#ifdef _LIBC
47     internal_function
48#endif
49     ;
50
51/* Return minimum _pos markers
52   Assumes the current get area is the main get area. */
53_IO_ssize_t _IO_least_wmarker __P ((_IO_FILE *fp, wchar_t *end_p));
54
55_IO_ssize_t
56_IO_least_wmarker (fp, end_p)
57     _IO_FILE *fp;
58     wchar_t *end_p;
59{
60  _IO_ssize_t least_so_far = end_p - fp->_wide_data->_IO_read_base;
61  struct _IO_marker *mark;
62  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
63    if (mark->_pos < least_so_far)
64      least_so_far = mark->_pos;
65  return least_so_far;
66}
67INTDEF(_IO_least_wmarker)
68
69/* Switch current get area from backup buffer to (start of) main get area. */
70void
71_IO_switch_to_main_wget_area (fp)
72     _IO_FILE *fp;
73{
74  wchar_t *tmp;
75  fp->_flags &= ~_IO_IN_BACKUP;
76  /* Swap _IO_read_end and _IO_save_end. */
77  tmp = fp->_wide_data->_IO_read_end;
78  fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_save_end;
79  fp->_wide_data->_IO_save_end= tmp;
80  /* Swap _IO_read_base and _IO_save_base. */
81  tmp = fp->_wide_data->_IO_read_base;
82  fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_save_base;
83  fp->_wide_data->_IO_save_base = tmp;
84  /* Set _IO_read_ptr. */
85  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
86}
87INTDEF(_IO_switch_to_main_wget_area)
88
89
90/* Switch current get area from main get area to (end of) backup area. */
91void
92_IO_switch_to_wbackup_area (fp)
93     _IO_FILE *fp;
94{
95  wchar_t *tmp;
96  fp->_flags |= _IO_IN_BACKUP;
97  /* Swap _IO_read_end and _IO_save_end. */
98  tmp = fp->_wide_data->_IO_read_end;
99  fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_save_end;
100  fp->_wide_data->_IO_save_end = tmp;
101  /* Swap _IO_read_base and _IO_save_base. */
102  tmp = fp->_wide_data->_IO_read_base;
103  fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_save_base;
104  fp->_wide_data->_IO_save_base = tmp;
105  /* Set _IO_read_ptr.  */
106  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
107}
108INTDEF(_IO_switch_to_wbackup_area)
109
110
111void
112_IO_wsetb (f, b, eb, a)
113     _IO_FILE *f;
114     wchar_t *b;
115     wchar_t *eb;
116     int a;
117{
118  if (f->_wide_data->_IO_buf_base && !(f->_flags2 & _IO_FLAGS2_USER_WBUF))
119	FREE_BUF (f->_wide_data->_IO_buf_base, _IO_wblen (f));
120  f->_wide_data->_IO_buf_base = b;
121  f->_wide_data->_IO_buf_end = eb;
122  if (a)
123    f->_flags2 &= ~_IO_FLAGS2_USER_WBUF;
124  else
125    f->_flags2 |= _IO_FLAGS2_USER_WBUF;
126}
127INTDEF(_IO_wsetb)
128
129
130wint_t
131_IO_wdefault_pbackfail (fp, c)
132     _IO_FILE *fp;
133     wint_t c;
134{
135  if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
136      && !_IO_in_backup (fp)
137      && (wint_t) fp->_IO_read_ptr[-1] == c)
138    --fp->_IO_read_ptr;
139  else
140    {
141      /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
142      if (!_IO_in_backup (fp))
143	{
144	  /* We need to keep the invariant that the main get area
145	     logically follows the backup area.  */
146	  if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
147	      && _IO_have_wbackup (fp))
148	    {
149	      if (save_for_wbackup (fp, fp->_wide_data->_IO_read_ptr))
150		return WEOF;
151	    }
152	  else if (!_IO_have_wbackup (fp))
153	    {
154	      /* No backup buffer: allocate one. */
155	      /* Use nshort buffer, if unused? (probably not)  FIXME */
156	      int backup_size = 128;
157	      wchar_t *bbuf = (wchar_t *) malloc (backup_size
158						  * sizeof (wchar_t));
159	      if (bbuf == NULL)
160		return WEOF;
161	      fp->_wide_data->_IO_save_base = bbuf;
162	      fp->_wide_data->_IO_save_end = (fp->_wide_data->_IO_save_base
163					      + backup_size);
164	      fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_end;
165	    }
166	  fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr;
167	  INTUSE(_IO_switch_to_wbackup_area) (fp);
168	}
169      else if (fp->_wide_data->_IO_read_ptr <= fp->_wide_data->_IO_read_base)
170	{
171	  /* Increase size of existing backup buffer. */
172	  _IO_size_t new_size;
173	  _IO_size_t old_size = (fp->_wide_data->_IO_read_end
174				 - fp->_wide_data->_IO_read_base);
175	  wchar_t *new_buf;
176	  new_size = 2 * old_size;
177	  new_buf = (wchar_t *) malloc (new_size * sizeof (wchar_t));
178	  if (new_buf == NULL)
179	    return WEOF;
180	  __wmemcpy (new_buf + (new_size - old_size),
181		     fp->_wide_data->_IO_read_base, old_size);
182	  free (fp->_wide_data->_IO_read_base);
183	  _IO_wsetg (fp, new_buf, new_buf + (new_size - old_size),
184		     new_buf + new_size);
185	  fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_read_ptr;
186	}
187
188      *--fp->_wide_data->_IO_read_ptr = c;
189    }
190  return c;
191}
192INTDEF(_IO_wdefault_pbackfail)
193
194
195void
196_IO_wdefault_finish (fp, dummy)
197     _IO_FILE *fp;
198     int dummy;
199{
200  struct _IO_marker *mark;
201  if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
202    {
203      FREE_BUF (fp->_wide_data->_IO_buf_base,
204		_IO_wblen (fp) * sizeof (wchar_t));
205      fp->_wide_data->_IO_buf_base = fp->_wide_data->_IO_buf_end = NULL;
206    }
207
208  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
209    mark->_sbuf = NULL;
210
211  if (fp->_IO_save_base)
212    {
213      free (fp->_wide_data->_IO_save_base);
214      fp->_IO_save_base = NULL;
215    }
216
217#ifdef _IO_MTSAFE_IO
218  if (fp->_lock != NULL)
219    _IO_lock_fini (*fp->_lock);
220#endif
221
222  INTUSE(_IO_un_link) ((struct _IO_FILE_plus *) fp);
223}
224INTDEF(_IO_wdefault_finish)
225
226
227wint_t
228_IO_wdefault_uflow (fp)
229     _IO_FILE *fp;
230{
231  wint_t wch;
232  wch = _IO_UNDERFLOW (fp);
233  if (wch == WEOF)
234    return WEOF;
235  return *fp->_wide_data->_IO_read_ptr++;
236}
237INTDEF(_IO_wdefault_uflow)
238
239
240wint_t
241__woverflow (f, wch)
242     _IO_FILE *f;
243     wint_t wch;
244{
245  if (f->_mode == 0)
246    _IO_fwide (f, 1);
247  return _IO_OVERFLOW (f, wch);
248}
249libc_hidden_def (__woverflow)
250
251
252wint_t
253__wuflow (fp)
254     _IO_FILE *fp;
255{
256  if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
257    return WEOF;
258
259  if (fp->_mode == 0)
260    _IO_fwide (fp, 1);
261  if (_IO_in_put_mode (fp))
262    if (INTUSE(_IO_switch_to_wget_mode) (fp) == EOF)
263      return WEOF;
264  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
265    return *fp->_wide_data->_IO_read_ptr++;
266  if (_IO_in_backup (fp))
267    {
268      INTUSE(_IO_switch_to_main_wget_area) (fp);
269      if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
270	return *fp->_wide_data->_IO_read_ptr++;
271    }
272  if (_IO_have_markers (fp))
273    {
274      if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
275	return WEOF;
276    }
277  else if (_IO_have_wbackup (fp))
278    INTUSE(_IO_free_wbackup_area) (fp);
279  return _IO_UFLOW (fp);
280}
281libc_hidden_def (__wuflow)
282
283wint_t
284__wunderflow (fp)
285     _IO_FILE *fp;
286{
287  if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
288    return WEOF;
289
290  if (fp->_mode == 0)
291    _IO_fwide (fp, 1);
292  if (_IO_in_put_mode (fp))
293    if (INTUSE(_IO_switch_to_wget_mode) (fp) == EOF)
294      return WEOF;
295  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
296    return *fp->_wide_data->_IO_read_ptr;
297  if (_IO_in_backup (fp))
298    {
299      INTUSE(_IO_switch_to_main_wget_area) (fp);
300      if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
301	return *fp->_wide_data->_IO_read_ptr;
302    }
303  if (_IO_have_markers (fp))
304    {
305      if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
306	return WEOF;
307    }
308  else if (_IO_have_backup (fp))
309    INTUSE(_IO_free_wbackup_area) (fp);
310  return _IO_UNDERFLOW (fp);
311}
312libc_hidden_def (__wunderflow)
313
314
315_IO_size_t
316_IO_wdefault_xsputn (f, data, n)
317     _IO_FILE *f;
318     const void *data;
319     _IO_size_t n;
320{
321  const wchar_t *s = (const wchar_t *) data;
322  _IO_size_t more = n;
323  if (more <= 0)
324    return 0;
325  for (;;)
326    {
327      /* Space available. */
328      _IO_ssize_t count = (f->_wide_data->_IO_write_end
329			   - f->_wide_data->_IO_write_ptr);
330      if (count > 0)
331	{
332	  if ((_IO_size_t) count > more)
333	    count = more;
334	  if (count > 20)
335	    {
336#ifdef _LIBC
337	      f->_wide_data->_IO_write_ptr =
338		__wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
339#else
340	      memcpy (f->_wide_data->_IO_write_ptr, s, count);
341	      f->_wide_data->_IO_write_ptr += count;
342#endif
343	      s += count;
344            }
345	  else if (count <= 0)
346	    count = 0;
347	  else
348	    {
349	      wchar_t *p = f->_wide_data->_IO_write_ptr;
350	      _IO_ssize_t i;
351	      for (i = count; --i >= 0; )
352		*p++ = *s++;
353	      f->_wide_data->_IO_write_ptr = p;
354            }
355	  more -= count;
356        }
357      if (more == 0 || __woverflow (f, *s++) == WEOF)
358	break;
359      more--;
360    }
361  return n - more;
362}
363INTDEF(_IO_wdefault_xsputn)
364
365
366_IO_size_t
367_IO_wdefault_xsgetn (fp, data, n)
368     _IO_FILE *fp;
369     void *data;
370     _IO_size_t n;
371{
372  _IO_size_t more = n;
373  wchar_t *s = (wchar_t*) data;
374  for (;;)
375    {
376      /* Data available. */
377      _IO_ssize_t count = (fp->_wide_data->_IO_read_end
378			   - fp->_wide_data->_IO_read_ptr);
379      if (count > 0)
380	{
381	  if ((_IO_size_t) count > more)
382	    count = more;
383	  if (count > 20)
384	    {
385#ifdef _LIBC
386	      s = __wmempcpy (s, fp->_wide_data->_IO_read_ptr, count);
387#else
388	      memcpy (s, fp->_wide_data->_IO_read_ptr, count);
389	      s += count;
390#endif
391	      fp->_wide_data->_IO_read_ptr += count;
392	    }
393	  else if (count <= 0)
394	    count = 0;
395	  else
396	    {
397	      wchar_t *p = fp->_wide_data->_IO_read_ptr;
398	      int i = (int) count;
399	      while (--i >= 0)
400		*s++ = *p++;
401	      fp->_wide_data->_IO_read_ptr = p;
402            }
403            more -= count;
404        }
405      if (more == 0 || __wunderflow (fp) == WEOF)
406	break;
407    }
408  return n - more;
409}
410INTDEF(_IO_wdefault_xsgetn)
411
412
413void
414_IO_wdoallocbuf (fp)
415     _IO_FILE *fp;
416{
417  if (fp->_wide_data->_IO_buf_base)
418    return;
419  if (!(fp->_flags & _IO_UNBUFFERED))
420    if ((wint_t)_IO_WDOALLOCATE (fp) != WEOF)
421      return;
422  INTUSE(_IO_wsetb) (fp, fp->_wide_data->_shortbuf,
423		     fp->_wide_data->_shortbuf + 1, 0);
424}
425INTDEF(_IO_wdoallocbuf)
426
427
428int
429_IO_wdefault_doallocate (fp)
430     _IO_FILE *fp;
431{
432  wchar_t *buf;
433
434  ALLOC_WBUF (buf, _IO_BUFSIZ, EOF);
435  INTUSE(_IO_wsetb) (fp, buf, buf + _IO_BUFSIZ, 1);
436  return 1;
437}
438INTDEF(_IO_wdefault_doallocate)
439
440
441int
442_IO_switch_to_wget_mode (fp)
443     _IO_FILE *fp;
444{
445  if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
446    if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
447      return EOF;
448  if (_IO_in_backup (fp))
449    fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
450  else
451    {
452      fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
453      if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
454	fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
455    }
456  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
457
458  fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
459    = fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_read_ptr;
460
461  fp->_flags &= ~_IO_CURRENTLY_PUTTING;
462  return 0;
463}
464INTDEF(_IO_switch_to_wget_mode)
465
466void
467_IO_free_wbackup_area (fp)
468     _IO_FILE *fp;
469{
470  if (_IO_in_backup (fp))
471    INTUSE(_IO_switch_to_main_wget_area) (fp);  /* Just in case. */
472  free (fp->_wide_data->_IO_save_base);
473  fp->_wide_data->_IO_save_base = NULL;
474  fp->_wide_data->_IO_save_end = NULL;
475  fp->_wide_data->_IO_backup_base = NULL;
476}
477INTDEF(_IO_free_wbackup_area)
478
479#if 0
480int
481_IO_switch_to_wput_mode (fp)
482     _IO_FILE *fp;
483{
484  fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_read_ptr;
485  fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
486  /* Following is wrong if line- or un-buffered? */
487  fp->_wide_data->_IO_write_end = (fp->_flags & _IO_IN_BACKUP
488				   ? fp->_wide_data->_IO_read_end
489				   : fp->_wide_data->_IO_buf_end);
490
491  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
492  fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_end;
493
494  fp->_flags |= _IO_CURRENTLY_PUTTING;
495  return 0;
496}
497#endif
498
499
500static int
501#ifdef _LIBC
502internal_function
503#endif
504save_for_wbackup (fp, end_p)
505     _IO_FILE *fp;
506     wchar_t *end_p;
507{
508  /* Append [_IO_read_base..end_p] to backup area. */
509  _IO_ssize_t least_mark = INTUSE(_IO_least_wmarker) (fp, end_p);
510  /* needed_size is how much space we need in the backup area. */
511  _IO_size_t needed_size = ((end_p - fp->_wide_data->_IO_read_base)
512			    - least_mark);
513  /* FIXME: Dubious arithmetic if pointers are NULL */
514  _IO_size_t current_Bsize = (fp->_wide_data->_IO_save_end
515			      - fp->_wide_data->_IO_save_base);
516  _IO_size_t avail; /* Extra space available for future expansion. */
517  _IO_ssize_t delta;
518  struct _IO_marker *mark;
519  if (needed_size > current_Bsize)
520    {
521      wchar_t *new_buffer;
522      avail = 100;
523      new_buffer = (wchar_t *) malloc ((avail + needed_size)
524				       * sizeof (wchar_t));
525      if (new_buffer == NULL)
526	return EOF;		/* FIXME */
527      if (least_mark < 0)
528	{
529#ifdef _LIBC
530	  __wmempcpy (__wmempcpy (new_buffer + avail,
531				  fp->_wide_data->_IO_save_end + least_mark,
532				  -least_mark),
533		      fp->_wide_data->_IO_read_base,
534		      end_p - fp->_wide_data->_IO_read_base);
535#else
536	  memcpy (new_buffer + avail,
537		  fp->_wide_data->_IO_save_end + least_mark,
538		  -least_mark * sizeof (wchar_t));
539	  memcpy (new_buffer + avail - least_mark,
540		  fp->_wide_data->_IO_read_base,
541		  (end_p - fp->_wide_data->_IO_read_base) * sizeof (wchar_t));
542#endif
543	}
544      else
545	{
546#ifdef _LIBC
547	  __wmemcpy (new_buffer + avail,
548		     fp->_wide_data->_IO_read_base + least_mark,
549		     needed_size);
550#else
551	  memcpy (new_buffer + avail,
552		  fp->_wide_data->_IO_read_base + least_mark,
553		  needed_size * sizeof (wchar_t));
554#endif
555	}
556      if (fp->_wide_data->_IO_save_base)
557	free (fp->_wide_data->_IO_save_base);
558      fp->_wide_data->_IO_save_base = new_buffer;
559      fp->_wide_data->_IO_save_end = new_buffer + avail + needed_size;
560    }
561  else
562    {
563      avail = current_Bsize - needed_size;
564      if (least_mark < 0)
565	{
566#ifdef _LIBC
567	  __wmemmove (fp->_wide_data->_IO_save_base + avail,
568		      fp->_wide_data->_IO_save_end + least_mark,
569		      -least_mark);
570	  __wmemcpy (fp->_wide_data->_IO_save_base + avail - least_mark,
571		     fp->_wide_data->_IO_read_base,
572		     end_p - fp->_wide_data->_IO_read_base);
573#else
574	  memmove (fp->_wide_data->_IO_save_base + avail,
575		   fp->_wide_data->_IO_save_end + least_mark,
576		   -least_mark * sizeof (wchar_t));
577	  memcpy (fp->_wide_data->_IO_save_base + avail - least_mark,
578		  fp->_wide_data->_IO_read_base,
579		  (end_p - fp->_wide_data->_IO_read_base) * sizeof (wchar_t));
580#endif
581	}
582      else if (needed_size > 0)
583#ifdef _LIBC
584	__wmemcpy (fp->_wide_data->_IO_save_base + avail,
585		   fp->_wide_data->_IO_read_base + least_mark,
586		   needed_size);
587#else
588	memcpy (fp->_wide_data->_IO_save_base + avail,
589		fp->_wide_data->_IO_read_base + least_mark,
590		needed_size * sizeof (wchar_t));
591#endif
592    }
593  fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_base + avail;
594  /* Adjust all the streammarkers. */
595  delta = end_p - fp->_wide_data->_IO_read_base;
596  for (mark = fp->_markers; mark != NULL; mark = mark->_next)
597    mark->_pos -= delta;
598  return 0;
599}
600
601wint_t
602_IO_sputbackwc (fp, c)
603     _IO_FILE *fp;
604     wint_t c;
605{
606  wint_t result;
607
608  if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
609      && (wchar_t)fp->_wide_data->_IO_read_ptr[-1] == (wchar_t) c)
610    {
611      fp->_wide_data->_IO_read_ptr--;
612      result = c;
613    }
614  else
615    result = _IO_PBACKFAIL (fp, c);
616
617  if (result != WEOF)
618    fp->_flags &= ~_IO_EOF_SEEN;
619
620  return result;
621}
622INTDEF(_IO_sputbackwc)
623
624wint_t
625_IO_sungetwc (fp)
626     _IO_FILE *fp;
627{
628  wint_t result;
629
630  if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base)
631    {
632      fp->_wide_data->_IO_read_ptr--;
633      result = *fp->_wide_data->_IO_read_ptr;
634    }
635  else
636    result = _IO_PBACKFAIL (fp, EOF);
637
638  if (result != WEOF)
639    fp->_flags &= ~_IO_EOF_SEEN;
640
641  return result;
642}
643
644
645unsigned
646_IO_adjust_wcolumn (start, line, count)
647     unsigned start;
648     const wchar_t *line;
649     int count;
650{
651  const wchar_t *ptr = line + count;
652  while (ptr > line)
653    if (*--ptr == L'\n')
654      return line + count - ptr - 1;
655  return start + count;
656}
657
658void
659_IO_init_wmarker (marker, fp)
660     struct _IO_marker *marker;
661     _IO_FILE *fp;
662{
663  marker->_sbuf = fp;
664  if (_IO_in_put_mode (fp))
665    INTUSE(_IO_switch_to_wget_mode) (fp);
666  if (_IO_in_backup (fp))
667    marker->_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
668  else
669    marker->_pos = (fp->_wide_data->_IO_read_ptr
670		    - fp->_wide_data->_IO_read_base);
671
672  /* Should perhaps sort the chain? */
673  marker->_next = fp->_markers;
674  fp->_markers = marker;
675}
676
677#define BAD_DELTA EOF
678
679/* Return difference between MARK and current position of MARK's stream. */
680int
681_IO_wmarker_delta (mark)
682     struct _IO_marker *mark;
683{
684  int cur_pos;
685  if (mark->_sbuf == NULL)
686    return BAD_DELTA;
687  if (_IO_in_backup (mark->_sbuf))
688    cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
689	       - mark->_sbuf->_wide_data->_IO_read_end);
690  else
691    cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
692	       - mark->_sbuf->_wide_data->_IO_read_base);
693  return mark->_pos - cur_pos;
694}
695
696int
697_IO_seekwmark (fp, mark, delta)
698     _IO_FILE *fp;
699     struct _IO_marker *mark;
700     int delta;
701{
702  if (mark->_sbuf != fp)
703    return EOF;
704 if (mark->_pos >= 0)
705    {
706      if (_IO_in_backup (fp))
707	INTUSE(_IO_switch_to_main_wget_area) (fp);
708      fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
709				      + mark->_pos);
710    }
711  else
712    {
713      if (!_IO_in_backup (fp))
714	INTUSE(_IO_switch_to_wbackup_area) (fp);
715      fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end + mark->_pos;
716    }
717  return 0;
718}
719
720void
721_IO_unsave_wmarkers (fp)
722     _IO_FILE *fp;
723{
724  struct _IO_marker *mark = fp->_markers;
725  if (mark)
726    {
727#ifdef TODO
728      streampos offset = seekoff (0, ios::cur, ios::in);
729      if (offset != EOF)
730	{
731	  offset += eGptr () - Gbase ();
732	  for ( ; mark != NULL; mark = mark->_next)
733	    mark->set_streampos (mark->_pos + offset);
734	}
735    else
736      {
737	for ( ; mark != NULL; mark = mark->_next)
738	  mark->set_streampos (EOF);
739      }
740#endif
741      fp->_markers = 0;
742    }
743
744  if (_IO_have_backup (fp))
745    INTUSE(_IO_free_wbackup_area) (fp);
746}
747