xref: /haiku/src/system/libroot/posix/glibc/libio/wgenops.c (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
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 
45 static 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 }
67 INTDEF(_IO_least_wmarker)
68 
69 /* Switch current get area from backup buffer to (start of) main get area. */
70 void
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 }
87 INTDEF(_IO_switch_to_main_wget_area)
88 
89 
90 /* Switch current get area from main get area to (end of) backup area. */
91 void
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 }
108 INTDEF(_IO_switch_to_wbackup_area)
109 
110 
111 void
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->_flags & _IO_USER_BUF))
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->_flags &= ~_IO_USER_BUF;
124   else
125     f->_flags |= _IO_USER_BUF;
126 }
127 INTDEF(_IO_wsetb)
128 
129 
130 wint_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 }
192 INTDEF(_IO_wdefault_pbackfail)
193 
194 
195 void
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->_flags & _IO_USER_BUF))
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 }
224 INTDEF(_IO_wdefault_finish)
225 
226 
227 wint_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 }
237 INTDEF(_IO_wdefault_uflow)
238 
239 
240 wint_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 }
249 libc_hidden_def (__woverflow)
250 
251 
252 wint_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 }
281 libc_hidden_def (__wuflow)
282 
283 wint_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 }
312 libc_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 }
363 INTDEF(_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 }
410 INTDEF(_IO_wdefault_xsgetn)
411 
412 
413 void
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 }
425 INTDEF(_IO_wdoallocbuf)
426 
427 
428 int
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 }
438 INTDEF(_IO_wdefault_doallocate)
439 
440 
441 int
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 }
464 INTDEF(_IO_switch_to_wget_mode)
465 
466 void
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 }
477 INTDEF(_IO_free_wbackup_area)
478 
479 #if 0
480 int
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 
500 static int
501 #ifdef _LIBC
502 internal_function
503 #endif
504 save_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 
601 wint_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 }
622 INTDEF(_IO_sputbackwc)
623 
624 wint_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 
645 unsigned
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 
658 void
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. */
680 int
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 
696 int
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 
720 void
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