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