Use INTUSE to reference functions and variables inside libc itself.
[kopensolaris-gnu/glibc.git] / libio / wgenops.c
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
250
251 wint_t
252 __wuflow (fp)
253      _IO_FILE *fp;
254 {
255   if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
256     return WEOF;
257
258   if (fp->_mode == 0)
259     _IO_fwide (fp, 1);
260   if (_IO_in_put_mode (fp))
261     if (INTUSE(_IO_switch_to_wget_mode) (fp) == EOF)
262       return WEOF;
263   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
264     return *fp->_wide_data->_IO_read_ptr++;
265   if (_IO_in_backup (fp))
266     {
267       INTUSE(_IO_switch_to_main_wget_area) (fp);
268       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
269         return *fp->_wide_data->_IO_read_ptr++;
270     }
271   if (_IO_have_markers (fp))
272     {
273       if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
274         return WEOF;
275     }
276   else if (_IO_have_wbackup (fp))
277     INTUSE(_IO_free_wbackup_area) (fp);
278   return _IO_UFLOW (fp);
279 }
280
281
282 wint_t
283 __wunderflow (fp)
284      _IO_FILE *fp;
285 {
286   if (fp->_mode < 0 || (fp->_mode == 0 && _IO_fwide (fp, 1) != 1))
287     return WEOF;
288
289   if (fp->_mode == 0)
290     _IO_fwide (fp, 1);
291   if (_IO_in_put_mode (fp))
292     if (INTUSE(_IO_switch_to_wget_mode) (fp) == EOF)
293       return WEOF;
294   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
295     return *fp->_wide_data->_IO_read_ptr;
296   if (_IO_in_backup (fp))
297     {
298       INTUSE(_IO_switch_to_main_wget_area) (fp);
299       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
300         return *fp->_wide_data->_IO_read_ptr;
301     }
302   if (_IO_have_markers (fp))
303     {
304       if (save_for_wbackup (fp, fp->_wide_data->_IO_read_end))
305         return WEOF;
306     }
307   else if (_IO_have_backup (fp))
308     INTUSE(_IO_free_wbackup_area) (fp);
309   return _IO_UNDERFLOW (fp);
310 }
311
312
313 _IO_size_t
314 _IO_wdefault_xsputn (f, data, n)
315      _IO_FILE *f;
316      const void *data;
317      _IO_size_t n;
318 {
319   const wchar_t *s = (const wchar_t *) data;
320   _IO_size_t more = n;
321   if (more <= 0)
322     return 0;
323   for (;;)
324     {
325       /* Space available. */
326       _IO_ssize_t count = (f->_wide_data->_IO_write_end
327                            - f->_wide_data->_IO_write_ptr);
328       if (count > 0)
329         {
330           if ((_IO_size_t) count > more)
331             count = more;
332           if (count > 20)
333             {
334 #ifdef _LIBC
335               f->_wide_data->_IO_write_ptr =
336                 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
337 #else
338               memcpy (f->_wide_data->_IO_write_ptr, s, count);
339               f->_wide_data->_IO_write_ptr += count;
340 #endif
341               s += count;
342             }
343           else if (count <= 0)
344             count = 0;
345           else
346             {
347               wchar_t *p = f->_wide_data->_IO_write_ptr;
348               _IO_ssize_t i;
349               for (i = count; --i >= 0; )
350                 *p++ = *s++;
351               f->_wide_data->_IO_write_ptr = p;
352             }
353           more -= count;
354         }
355       if (more == 0 || __woverflow (f, *s++) == WEOF)
356         break;
357       more--;
358     }
359   return n - more;
360 }
361 INTDEF(_IO_wdefault_xsputn)
362
363
364 _IO_size_t
365 _IO_wdefault_xsgetn (fp, data, n)
366      _IO_FILE *fp;
367      void *data;
368      _IO_size_t n;
369 {
370   _IO_size_t more = n;
371   wchar_t *s = (wchar_t*) data;
372   for (;;)
373     {
374       /* Data available. */
375       _IO_ssize_t count = (fp->_wide_data->_IO_read_end
376                            - fp->_wide_data->_IO_read_ptr);
377       if (count > 0)
378         {
379           if ((_IO_size_t) count > more)
380             count = more;
381           if (count > 20)
382             {
383 #ifdef _LIBC
384               s = __wmempcpy (s, fp->_wide_data->_IO_read_ptr, count);
385 #else
386               memcpy (s, fp->_wide_data->_IO_read_ptr, count);
387               s += count;
388 #endif
389               fp->_wide_data->_IO_read_ptr += count;
390             }
391           else if (count <= 0)
392             count = 0;
393           else
394             {
395               wchar_t *p = fp->_wide_data->_IO_read_ptr;
396               int i = (int) count;
397               while (--i >= 0)
398                 *s++ = *p++;
399               fp->_wide_data->_IO_read_ptr = p;
400             }
401             more -= count;
402         }
403       if (more == 0 || __wunderflow (fp) == WEOF)
404         break;
405     }
406   return n - more;
407 }
408 INTDEF(_IO_wdefault_xsgetn)
409
410
411 void
412 _IO_wdoallocbuf (fp)
413      _IO_FILE *fp;
414 {
415   if (fp->_wide_data->_IO_buf_base)
416     return;
417   if (!(fp->_flags & _IO_UNBUFFERED))
418     if ((wint_t)_IO_WDOALLOCATE (fp) != WEOF)
419       return;
420   INTUSE(_IO_wsetb) (fp, fp->_wide_data->_shortbuf,
421                      fp->_wide_data->_shortbuf + 1, 0);
422 }
423 INTDEF(_IO_wdoallocbuf)
424
425
426 _IO_FILE *
427 _IO_wdefault_setbuf (fp, p, len)
428      _IO_FILE *fp;
429      wchar_t *p;
430      _IO_ssize_t len;
431 {
432   if (_IO_SYNC (fp) == EOF)
433     return NULL;
434   if (p == NULL || len == 0)
435     {
436       fp->_flags |= _IO_UNBUFFERED;
437       INTUSE(_IO_wsetb) (fp, fp->_wide_data->_shortbuf,
438                          fp->_wide_data->_shortbuf + 1, 0);
439     }
440   else
441     {
442       fp->_flags &= ~_IO_UNBUFFERED;
443       INTUSE(_IO_wsetb) (fp, p, p + len, 0);
444     }
445   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
446     = fp->_wide_data->_IO_write_end = 0;
447   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr
448     = fp->_wide_data->_IO_read_end = 0;
449   return fp;
450 }
451 INTDEF(_IO_wdefault_setbuf)
452
453
454 int
455 _IO_wdefault_doallocate (fp)
456      _IO_FILE *fp;
457 {
458   wchar_t *buf;
459
460   ALLOC_WBUF (buf, _IO_BUFSIZ, EOF);
461   INTUSE(_IO_wsetb) (fp, buf, buf + _IO_BUFSIZ, 1);
462   return 1;
463 }
464 INTDEF(_IO_wdefault_doallocate)
465
466
467 int
468 _IO_switch_to_wget_mode (fp)
469      _IO_FILE *fp;
470 {
471   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
472     if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
473       return EOF;
474   if (_IO_in_backup (fp))
475     fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
476   else
477     {
478       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
479       if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
480         fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
481     }
482   fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
483
484   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
485     = fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_read_ptr;
486
487   fp->_flags &= ~_IO_CURRENTLY_PUTTING;
488   return 0;
489 }
490 INTDEF(_IO_switch_to_wget_mode)
491
492 void
493 _IO_free_wbackup_area (fp)
494      _IO_FILE *fp;
495 {
496   if (_IO_in_backup (fp))
497     INTUSE(_IO_switch_to_main_wget_area) (fp);  /* Just in case. */
498   free (fp->_wide_data->_IO_save_base);
499   fp->_wide_data->_IO_save_base = NULL;
500   fp->_wide_data->_IO_save_end = NULL;
501   fp->_wide_data->_IO_backup_base = NULL;
502 }
503 INTDEF(_IO_free_wbackup_area)
504
505 #if 0
506 int
507 _IO_switch_to_wput_mode (fp)
508      _IO_FILE *fp;
509 {
510   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_read_ptr;
511   fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
512   /* Following is wrong if line- or un-buffered? */
513   fp->_wide_data->_IO_write_end = (fp->_flags & _IO_IN_BACKUP
514                                    ? fp->_wide_data->_IO_read_end
515                                    : fp->_wide_data->_IO_buf_end);
516
517   fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
518   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_end;
519
520   fp->_flags |= _IO_CURRENTLY_PUTTING;
521   return 0;
522 }
523 #endif
524
525
526 static int
527 #ifdef _LIBC
528 internal_function
529 #endif
530 save_for_wbackup (fp, end_p)
531      _IO_FILE *fp;
532      wchar_t *end_p;
533 {
534   /* Append [_IO_read_base..end_p] to backup area. */
535   _IO_ssize_t least_mark = INTUSE(_IO_least_wmarker) (fp, end_p);
536   /* needed_size is how much space we need in the backup area. */
537   _IO_size_t needed_size = ((end_p - fp->_wide_data->_IO_read_base)
538                             - least_mark);
539   /* FIXME: Dubious arithmetic if pointers are NULL */
540   _IO_size_t current_Bsize = (fp->_wide_data->_IO_save_end
541                               - fp->_wide_data->_IO_save_base);
542   _IO_size_t avail; /* Extra space available for future expansion. */
543   _IO_ssize_t delta;
544   struct _IO_marker *mark;
545   if (needed_size > current_Bsize)
546     {
547       wchar_t *new_buffer;
548       avail = 100;
549       new_buffer = (wchar_t *) malloc ((avail + needed_size)
550                                        * sizeof (wchar_t));
551       if (new_buffer == NULL)
552         return EOF;             /* FIXME */
553       if (least_mark < 0)
554         {
555 #ifdef _LIBC
556           __wmempcpy (__wmempcpy (new_buffer + avail,
557                                   fp->_wide_data->_IO_save_end + least_mark,
558                                   -least_mark),
559                       fp->_wide_data->_IO_read_base,
560                       end_p - fp->_wide_data->_IO_read_base);
561 #else
562           memcpy (new_buffer + avail,
563                   fp->_wide_data->_IO_save_end + least_mark,
564                   -least_mark * sizeof (wchar_t));
565           memcpy (new_buffer + avail - least_mark,
566                   fp->_wide_data->_IO_read_base,
567                   (end_p - fp->_wide_data->_IO_read_base) * sizeof (wchar_t));
568 #endif
569         }
570       else
571         {
572 #ifdef _LIBC
573           __wmemcpy (new_buffer + avail,
574                      fp->_wide_data->_IO_read_base + least_mark,
575                      needed_size);
576 #else
577           memcpy (new_buffer + avail,
578                   fp->_wide_data->_IO_read_base + least_mark,
579                   needed_size * sizeof (wchar_t));
580 #endif
581         }
582       if (fp->_wide_data->_IO_save_base)
583         free (fp->_wide_data->_IO_save_base);
584       fp->_wide_data->_IO_save_base = new_buffer;
585       fp->_wide_data->_IO_save_end = new_buffer + avail + needed_size;
586     }
587   else
588     {
589       avail = current_Bsize - needed_size;
590       if (least_mark < 0)
591         {
592 #ifdef _LIBC
593           __wmemmove (fp->_wide_data->_IO_save_base + avail,
594                       fp->_wide_data->_IO_save_end + least_mark,
595                       -least_mark);
596           __wmemcpy (fp->_wide_data->_IO_save_base + avail - least_mark,
597                      fp->_wide_data->_IO_read_base,
598                      end_p - fp->_wide_data->_IO_read_base);
599 #else
600           memmove (fp->_wide_data->_IO_save_base + avail,
601                    fp->_wide_data->_IO_save_end + least_mark,
602                    -least_mark * sizeof (wchar_t));
603           memcpy (fp->_wide_data->_IO_save_base + avail - least_mark,
604                   fp->_wide_data->_IO_read_base,
605                   (end_p - fp->_wide_data->_IO_read_base) * sizeof (wchar_t));
606 #endif
607         }
608       else if (needed_size > 0)
609 #ifdef _LIBC
610         __wmemcpy (fp->_wide_data->_IO_save_base + avail,
611                    fp->_wide_data->_IO_read_base + least_mark,
612                    needed_size);
613 #else
614         memcpy (fp->_wide_data->_IO_save_base + avail,
615                 fp->_wide_data->_IO_read_base + least_mark,
616                 needed_size * sizeof (wchar_t));
617 #endif
618     }
619   fp->_wide_data->_IO_backup_base = fp->_wide_data->_IO_save_base + avail;
620   /* Adjust all the streammarkers. */
621   delta = end_p - fp->_wide_data->_IO_read_base;
622   for (mark = fp->_markers; mark != NULL; mark = mark->_next)
623     mark->_pos -= delta;
624   return 0;
625 }
626
627 wint_t
628 _IO_sputbackwc (fp, c)
629      _IO_FILE *fp;
630      wint_t c;
631 {
632   wint_t result;
633
634   if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
635       && (wchar_t)fp->_wide_data->_IO_read_ptr[-1] == (wchar_t) c)
636     {
637       fp->_wide_data->_IO_read_ptr--;
638       result = c;
639     }
640   else
641     result = _IO_PBACKFAIL (fp, c);
642
643   if (result != WEOF)
644     fp->_flags &= ~_IO_EOF_SEEN;
645
646   return result;
647 }
648 INTDEF(_IO_sputbackwc)
649
650 wint_t
651 _IO_sungetwc (fp)
652      _IO_FILE *fp;
653 {
654   wint_t result;
655
656   if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base)
657     {
658       fp->_wide_data->_IO_read_ptr--;
659       result = *fp->_wide_data->_IO_read_ptr;
660     }
661   else
662     result = _IO_PBACKFAIL (fp, EOF);
663
664   if (result != WEOF)
665     fp->_flags &= ~_IO_EOF_SEEN;
666
667   return result;
668 }
669
670
671 unsigned
672 _IO_adjust_wcolumn (start, line, count)
673      unsigned start;
674      const wchar_t *line;
675      int count;
676 {
677   const wchar_t *ptr = line + count;
678   while (ptr > line)
679     if (*--ptr == L'\n')
680       return line + count - ptr - 1;
681   return start + count;
682 }
683
684 void
685 _IO_init_wmarker (marker, fp)
686      struct _IO_marker *marker;
687      _IO_FILE *fp;
688 {
689   marker->_sbuf = fp;
690   if (_IO_in_put_mode (fp))
691     INTUSE(_IO_switch_to_wget_mode) (fp);
692   if (_IO_in_backup (fp))
693     marker->_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
694   else
695     marker->_pos = (fp->_wide_data->_IO_read_ptr
696                     - fp->_wide_data->_IO_read_base);
697
698   /* Should perhaps sort the chain? */
699   marker->_next = fp->_markers;
700   fp->_markers = marker;
701 }
702
703 #define BAD_DELTA EOF
704
705 /* Return difference between MARK and current position of MARK's stream. */
706 int
707 _IO_wmarker_delta (mark)
708      struct _IO_marker *mark;
709 {
710   int cur_pos;
711   if (mark->_sbuf == NULL)
712     return BAD_DELTA;
713   if (_IO_in_backup (mark->_sbuf))
714     cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
715                - mark->_sbuf->_wide_data->_IO_read_end);
716   else
717     cur_pos = (mark->_sbuf->_wide_data->_IO_read_ptr
718                - mark->_sbuf->_wide_data->_IO_read_base);
719   return mark->_pos - cur_pos;
720 }
721
722 int
723 _IO_seekwmark (fp, mark, delta)
724      _IO_FILE *fp;
725      struct _IO_marker *mark;
726      int delta;
727 {
728   if (mark->_sbuf != fp)
729     return EOF;
730  if (mark->_pos >= 0)
731     {
732       if (_IO_in_backup (fp))
733         INTUSE(_IO_switch_to_main_wget_area) (fp);
734       fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
735                                       + mark->_pos);
736     }
737   else
738     {
739       if (!_IO_in_backup (fp))
740         INTUSE(_IO_switch_to_wbackup_area) (fp);
741       fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end + mark->_pos;
742     }
743   return 0;
744 }
745
746 void
747 _IO_unsave_wmarkers (fp)
748      _IO_FILE *fp;
749 {
750   struct _IO_marker *mark = fp->_markers;
751   if (mark)
752     {
753 #ifdef TODO
754       streampos offset = seekoff (0, ios::cur, ios::in);
755       if (offset != EOF)
756         {
757           offset += eGptr () - Gbase ();
758           for ( ; mark != NULL; mark = mark->_next)
759             mark->set_streampos (mark->_pos + offset);
760         }
761     else
762       {
763         for ( ; mark != NULL; mark = mark->_next)
764           mark->set_streampos (EOF);
765       }
766 #endif
767       fp->_markers = 0;
768     }
769
770   if (_IO_have_backup (fp))
771     INTUSE(_IO_free_wbackup_area) (fp);
772 }