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>.
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.
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.
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
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. */
30 /* Generic or default I/O operations. */
41 # define __wmemcpy(dst, src, n) wmemcpy (dst, src, n)
45 static int save_for_wbackup (_IO_FILE
*fp
, wchar_t *end_p
) __THROW
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
;
56 _IO_least_wmarker (fp
, end_p
)
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
;
67 INTDEF(_IO_least_wmarker
)
69 /* Switch current get area from backup buffer to (start of) main get area. */
71 _IO_switch_to_main_wget_area (fp
)
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
;
87 INTDEF(_IO_switch_to_main_wget_area
)
90 /* Switch current get area from main get area to (end of) backup area. */
92 _IO_switch_to_wbackup_area (fp
)
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
;
108 INTDEF(_IO_switch_to_wbackup_area
)
112 _IO_wsetb (f
, b
, eb
, a
)
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
;
123 f
->_flags2
&= ~_IO_FLAGS2_USER_WBUF
;
125 f
->_flags2
|= _IO_FLAGS2_USER_WBUF
;
131 _IO_wdefault_pbackfail (fp
, c
)
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
)
141 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
142 if (!_IO_in_backup (fp
))
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
))
149 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_ptr
))
152 else if (!_IO_have_wbackup (fp
))
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
161 fp
->_wide_data
->_IO_save_base
= bbuf
;
162 fp
->_wide_data
->_IO_save_end
= (fp
->_wide_data
->_IO_save_base
164 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_end
;
166 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_ptr
;
167 INTUSE(_IO_switch_to_wbackup_area
) (fp
);
169 else if (fp
->_wide_data
->_IO_read_ptr
<= fp
->_wide_data
->_IO_read_base
)
171 /* Increase size of existing backup buffer. */
173 _IO_size_t old_size
= (fp
->_wide_data
->_IO_read_end
174 - fp
->_wide_data
->_IO_read_base
);
176 new_size
= 2 * old_size
;
177 new_buf
= (wchar_t *) malloc (new_size
* sizeof (wchar_t));
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
),
185 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_read_ptr
;
188 *--fp
->_wide_data
->_IO_read_ptr
= c
;
192 INTDEF(_IO_wdefault_pbackfail
)
196 _IO_wdefault_finish (fp
, dummy
)
200 struct _IO_marker
*mark
;
201 if (fp
->_wide_data
->_IO_buf_base
&& !(fp
->_flags2
& _IO_FLAGS2_USER_WBUF
))
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
;
208 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
211 if (fp
->_IO_save_base
)
213 free (fp
->_wide_data
->_IO_save_base
);
214 fp
->_IO_save_base
= NULL
;
218 if (fp
->_lock
!= NULL
)
219 _IO_lock_fini (*fp
->_lock
);
222 INTUSE(_IO_un_link
) ((struct _IO_FILE_plus
*) fp
);
224 INTDEF(_IO_wdefault_finish
)
228 _IO_wdefault_uflow (fp
)
232 wch
= _IO_UNDERFLOW (fp
);
235 return *fp
->_wide_data
->_IO_read_ptr
++;
237 INTDEF(_IO_wdefault_uflow
)
247 return _IO_OVERFLOW (f
, wch
);
249 libc_hidden_def (__woverflow
)
256 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
261 if (_IO_in_put_mode (fp
))
262 if (INTUSE(_IO_switch_to_wget_mode
) (fp
) == EOF
)
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
))
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
++;
272 if (_IO_have_markers (fp
))
274 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
277 else if (_IO_have_wbackup (fp
))
278 INTUSE(_IO_free_wbackup_area
) (fp
);
279 return _IO_UFLOW (fp
);
281 libc_hidden_def (__wuflow
)
287 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
292 if (_IO_in_put_mode (fp
))
293 if (INTUSE(_IO_switch_to_wget_mode
) (fp
) == EOF
)
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
))
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
;
303 if (_IO_have_markers (fp
))
305 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
308 else if (_IO_have_backup (fp
))
309 INTUSE(_IO_free_wbackup_area
) (fp
);
310 return _IO_UNDERFLOW (fp
);
312 libc_hidden_def (__wunderflow
)
316 _IO_wdefault_xsputn (f
, data
, n
)
321 const wchar_t *s
= (const wchar_t *) data
;
327 /* Space available. */
328 _IO_ssize_t count
= (f
->_wide_data
->_IO_write_end
329 - f
->_wide_data
->_IO_write_ptr
);
332 if ((_IO_size_t
) count
> more
)
337 f
->_wide_data
->_IO_write_ptr
=
338 __wmempcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
340 memcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
341 f
->_wide_data
->_IO_write_ptr
+= count
;
349 wchar_t *p
= f
->_wide_data
->_IO_write_ptr
;
351 for (i
= count
; --i
>= 0; )
353 f
->_wide_data
->_IO_write_ptr
= p
;
357 if (more
== 0 || __woverflow (f
, *s
++) == WEOF
)
363 INTDEF(_IO_wdefault_xsputn
)
367 _IO_wdefault_xsgetn (fp
, data
, n
)
373 wchar_t *s
= (wchar_t*) data
;
376 /* Data available. */
377 _IO_ssize_t count
= (fp
->_wide_data
->_IO_read_end
378 - fp
->_wide_data
->_IO_read_ptr
);
381 if ((_IO_size_t
) count
> more
)
386 s
= __wmempcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
388 memcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
391 fp
->_wide_data
->_IO_read_ptr
+= count
;
397 wchar_t *p
= fp
->_wide_data
->_IO_read_ptr
;
401 fp
->_wide_data
->_IO_read_ptr
= p
;
405 if (more
== 0 || __wunderflow (fp
) == WEOF
)
410 INTDEF(_IO_wdefault_xsgetn
)
417 if (fp
->_wide_data
->_IO_buf_base
)
419 if (!(fp
->_flags
& _IO_UNBUFFERED
))
420 if ((wint_t)_IO_WDOALLOCATE (fp
) != WEOF
)
422 INTUSE(_IO_wsetb
) (fp
, fp
->_wide_data
->_shortbuf
,
423 fp
->_wide_data
->_shortbuf
+ 1, 0);
425 INTDEF(_IO_wdoallocbuf
)
429 _IO_wdefault_doallocate (fp
)
434 ALLOC_WBUF (buf
, _IO_BUFSIZ
, EOF
);
435 INTUSE(_IO_wsetb
) (fp
, buf
, buf
+ _IO_BUFSIZ
, 1);
438 INTDEF(_IO_wdefault_doallocate
)
442 _IO_switch_to_wget_mode (fp
)
445 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_write_base
)
446 if ((wint_t)_IO_WOVERFLOW (fp
, WEOF
) == WEOF
)
448 if (_IO_in_backup (fp
))
449 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_backup_base
;
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
;
456 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_write_ptr
;
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
;
461 fp
->_flags
&= ~_IO_CURRENTLY_PUTTING
;
464 INTDEF(_IO_switch_to_wget_mode
)
467 _IO_free_wbackup_area (fp
)
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
;
477 INTDEF(_IO_free_wbackup_area
)
481 _IO_switch_to_wput_mode (fp
)
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
);
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
;
494 fp
->_flags
|= _IO_CURRENTLY_PUTTING
;
504 save_for_wbackup (fp
, end_p
)
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
)
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. */
518 struct _IO_marker
*mark
;
519 if (needed_size
> current_Bsize
)
523 new_buffer
= (wchar_t *) malloc ((avail
+ needed_size
)
525 if (new_buffer
== NULL
)
526 return EOF
; /* FIXME */
530 __wmempcpy (__wmempcpy (new_buffer
+ avail
,
531 fp
->_wide_data
->_IO_save_end
+ least_mark
,
533 fp
->_wide_data
->_IO_read_base
,
534 end_p
- fp
->_wide_data
->_IO_read_base
);
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));
547 __wmemcpy (new_buffer
+ avail
,
548 fp
->_wide_data
->_IO_read_base
+ least_mark
,
551 memcpy (new_buffer
+ avail
,
552 fp
->_wide_data
->_IO_read_base
+ least_mark
,
553 needed_size
* sizeof (wchar_t));
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
;
563 avail
= current_Bsize
- needed_size
;
567 __wmemmove (fp
->_wide_data
->_IO_save_base
+ avail
,
568 fp
->_wide_data
->_IO_save_end
+ 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
);
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));
582 else if (needed_size
> 0)
584 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
585 fp
->_wide_data
->_IO_read_base
+ least_mark
,
588 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
589 fp
->_wide_data
->_IO_read_base
+ least_mark
,
590 needed_size
* sizeof (wchar_t));
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
)
602 _IO_sputbackwc (fp
, c
)
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
)
611 fp
->_wide_data
->_IO_read_ptr
--;
615 result
= _IO_PBACKFAIL (fp
, c
);
618 fp
->_flags
&= ~_IO_EOF_SEEN
;
622 INTDEF(_IO_sputbackwc
)
630 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
)
632 fp
->_wide_data
->_IO_read_ptr
--;
633 result
= *fp
->_wide_data
->_IO_read_ptr
;
636 result
= _IO_PBACKFAIL (fp
, EOF
);
639 fp
->_flags
&= ~_IO_EOF_SEEN
;
646 _IO_adjust_wcolumn (start
, line
, count
)
651 const wchar_t *ptr
= line
+ count
;
654 return line
+ count
- ptr
- 1;
655 return start
+ count
;
659 _IO_init_wmarker (marker
, fp
)
660 struct _IO_marker
*marker
;
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
;
669 marker
->_pos
= (fp
->_wide_data
->_IO_read_ptr
670 - fp
->_wide_data
->_IO_read_base
);
672 /* Should perhaps sort the chain? */
673 marker
->_next
= fp
->_markers
;
674 fp
->_markers
= marker
;
677 #define BAD_DELTA EOF
679 /* Return difference between MARK and current position of MARK's stream. */
681 _IO_wmarker_delta (mark
)
682 struct _IO_marker
*mark
;
685 if (mark
->_sbuf
== NULL
)
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
);
691 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
692 - mark
->_sbuf
->_wide_data
->_IO_read_base
);
693 return mark
->_pos
- cur_pos
;
697 _IO_seekwmark (fp
, mark
, delta
)
699 struct _IO_marker
*mark
;
702 if (mark
->_sbuf
!= fp
)
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
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
;
721 _IO_unsave_wmarkers (fp
)
724 struct _IO_marker
*mark
= fp
->_markers
;
728 streampos offset
= seekoff (0, ios::cur
, ios::in
);
731 offset
+= eGptr () - Gbase ();
732 for ( ; mark
!= NULL
; mark
= mark
->_next
)
733 mark
->set_streampos (mark
->_pos
+ offset
);
737 for ( ; mark
!= NULL
; mark
= mark
->_next
)
738 mark
->set_streampos (EOF
);
744 if (_IO_have_backup (fp
))
745 INTUSE(_IO_free_wbackup_area
) (fp
);