2.5-18.1
[jlayton/glibc.git] / libio / wgenops.c
1 /* Copyright (C) 1993,1995,1997-2002,2004,2006 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 (_IO_FILE *fp, wchar_t *end_p) __THROW
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 (_IO_FILE *fp, wchar_t *end_p) __THROW;
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->_flags2 & _IO_FLAGS2_USER_WBUF))
119     FREE_BUF (f->_wide_data->_IO_buf_base, _IO_wblen (f) * sizeof (wchar_t));
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 }
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->_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 }
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 }