1 /* Copyright (C) 1993, 1995, 1997, 1998, 1999 Free Software Foundation, Inc.
2 This file is part of the GNU IO Library.
3 Written by Ulrich Drepper <drepper@cygnus.com>.
4 Based on the single byte version by Per Bothner <bothner@cygnus.com>.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2, or (at
9 your option) any later version.
11 This library is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this library; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
21 As a special exception, if you link this library with files
22 compiled with a GNU compiler to produce an executable, this does
23 not cause the resulting executable to be covered by the GNU General
24 Public License. This exception does not however invalidate any
25 other reasons why the executable file might be covered by the GNU
26 General Public License. */
28 /* Generic or default I/O operations. */
39 static int save_for_wbackup
__P ((_IO_FILE
*fp
, wchar_t *end_p
))
45 /* Return minimum _pos markers
46 Assumes the current get area is the main get area. */
47 _IO_ssize_t _IO_least_wmarker
__P ((_IO_FILE
*fp
, wchar_t *end_p
));
50 _IO_least_wmarker (fp
, end_p
)
54 _IO_ssize_t least_so_far
= end_p
- fp
->_wide_data
->_IO_read_base
;
55 struct _IO_marker
*mark
;
56 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
57 if (mark
->_pos
< least_so_far
)
58 least_so_far
= mark
->_pos
;
62 /* Switch current get area from backup buffer to (start of) main get area. */
64 _IO_switch_to_main_wget_area (fp
)
68 fp
->_flags
&= ~_IO_IN_BACKUP
;
69 /* Swap _IO_read_end and _IO_save_end. */
70 tmp
= fp
->_wide_data
->_IO_read_end
;
71 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
72 fp
->_wide_data
->_IO_save_end
= tmp
;
73 /* Swap _IO_read_base and _IO_save_base. */
74 tmp
= fp
->_wide_data
->_IO_read_base
;
75 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
76 fp
->_wide_data
->_IO_save_base
= tmp
;
77 /* Set _IO_read_ptr. */
78 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_base
;
82 /* Switch current get area from main get area to (end of) backup area. */
84 _IO_switch_to_wbackup_area (fp
)
88 fp
->_flags
|= _IO_IN_BACKUP
;
89 /* Swap _IO_read_end and _IO_save_end. */
90 tmp
= fp
->_wide_data
->_IO_read_end
;
91 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_save_end
;
92 fp
->_wide_data
->_IO_save_end
= tmp
;
93 /* Swap _IO_read_base and _IO_save_base. */
94 tmp
= fp
->_wide_data
->_IO_read_base
;
95 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_save_base
;
96 fp
->_wide_data
->_IO_save_base
= tmp
;
97 /* Set _IO_read_ptr. */
98 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
103 _IO_wsetb (f
, b
, eb
, a
)
109 if (f
->_wide_data
->_IO_buf_base
&& !(f
->_flags
& _IO_USER_BUF
))
110 FREE_BUF (f
->_wide_data
->_IO_buf_base
, _IO_wblen (f
));
111 f
->_wide_data
->_IO_buf_base
= b
;
112 f
->_wide_data
->_IO_buf_end
= eb
;
114 f
->_flags
&= ~_IO_USER_BUF
;
116 f
->_flags
|= _IO_USER_BUF
;
121 _IO_wdefault_pbackfail (fp
, c
)
125 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
126 && !_IO_in_backup (fp
)
127 && (wint_t) fp
->_IO_read_ptr
[-1] == c
)
131 /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
132 if (!_IO_in_backup (fp
))
134 /* We need to keep the invariant that the main get area
135 logically follows the backup area. */
136 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
137 && _IO_have_wbackup (fp
))
139 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_ptr
))
142 else if (!_IO_have_wbackup (fp
))
144 /* No backup buffer: allocate one. */
145 /* Use nshort buffer, if unused? (probably not) FIXME */
146 int backup_size
= 128;
147 wchar_t *bbuf
= (wchar_t *) malloc (backup_size
151 fp
->_wide_data
->_IO_save_base
= bbuf
;
152 fp
->_wide_data
->_IO_save_end
= (fp
->_wide_data
->_IO_save_base
154 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_end
;
156 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_ptr
;
157 _IO_switch_to_wbackup_area (fp
);
159 else if (fp
->_wide_data
->_IO_read_ptr
<= fp
->_wide_data
->_IO_read_base
)
161 /* Increase size of existing backup buffer. */
163 _IO_size_t old_size
= (fp
->_wide_data
->_IO_read_end
164 - fp
->_wide_data
->_IO_read_base
);
166 new_size
= 2 * old_size
;
167 new_buf
= (wchar_t *) malloc (new_size
* sizeof (wchar_t));
170 __wmemcpy (new_buf
+ (new_size
- old_size
),
171 fp
->_wide_data
->_IO_read_base
, old_size
);
172 free (fp
->_wide_data
->_IO_read_base
);
173 _IO_wsetg (fp
, new_buf
, new_buf
+ (new_size
- old_size
),
175 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_read_ptr
;
178 *--fp
->_wide_data
->_IO_read_ptr
= c
;
185 _IO_wdefault_finish (fp
, dummy
)
189 struct _IO_marker
*mark
;
190 if (fp
->_wide_data
->_IO_buf_base
&& !(fp
->_flags
& _IO_USER_BUF
))
192 FREE_BUF (fp
->_wide_data
->_IO_buf_base
,
193 _IO_wblen (fp
) * sizeof (wchar_t));
194 fp
->_wide_data
->_IO_buf_base
= fp
->_wide_data
->_IO_buf_end
= NULL
;
197 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
200 if (fp
->_IO_save_base
)
202 free (fp
->_wide_data
->_IO_save_base
);
203 fp
->_IO_save_base
= NULL
;
207 _IO_lock_fini (*fp
->_lock
);
215 _IO_wdefault_uflow (fp
)
219 wch
= _IO_UNDERFLOW (fp
);
222 return *fp
->_wide_data
->_IO_read_ptr
++;
233 return _IO_OVERFLOW (f
, wch
);
241 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
246 if (_IO_in_put_mode (fp
))
247 if (_IO_switch_to_wget_mode (fp
) == EOF
)
249 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
250 return *fp
->_wide_data
->_IO_read_ptr
++;
251 if (_IO_in_backup (fp
))
253 _IO_switch_to_main_wget_area (fp
);
254 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
255 return *fp
->_wide_data
->_IO_read_ptr
++;
257 if (_IO_have_markers (fp
))
259 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
262 else if (_IO_have_wbackup (fp
))
263 _IO_free_wbackup_area (fp
);
264 return _IO_UFLOW (fp
);
272 if (fp
->_mode
< 0 || (fp
->_mode
== 0 && _IO_fwide (fp
, 1) != 1))
275 if (_IO_in_put_mode (fp
))
276 if (_IO_switch_to_wget_mode (fp
) == EOF
)
278 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
279 return *fp
->_wide_data
->_IO_read_ptr
;
280 if (_IO_in_backup (fp
))
282 _IO_switch_to_main_wget_area (fp
);
283 if (fp
->_wide_data
->_IO_read_ptr
< fp
->_wide_data
->_IO_read_end
)
284 return *fp
->_wide_data
->_IO_read_ptr
;
286 if (_IO_have_markers (fp
))
288 if (save_for_wbackup (fp
, fp
->_wide_data
->_IO_read_end
))
291 else if (_IO_have_backup (fp
))
292 _IO_free_wbackup_area (fp
);
293 return _IO_UNDERFLOW (fp
);
298 _IO_wdefault_xsputn (f
, data
, n
)
303 const wchar_t *s
= (const wchar_t *) data
;
309 /* Space available. */
310 _IO_ssize_t count
= (f
->_wide_data
->_IO_write_end
311 - f
->_wide_data
->_IO_write_ptr
);
314 if ((_IO_size_t
) count
> more
)
319 f
->_wide_data
->_IO_write_ptr
=
320 __wmempcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
322 memcpy (f
->_wide_data
->_IO_write_ptr
, s
, count
);
323 f
->_wide_data
->_IO_write_ptr
+= count
;
331 wchar_t *p
= f
->_wide_data
->_IO_write_ptr
;
333 for (i
= count
; --i
>= 0; )
335 f
->_wide_data
->_IO_write_ptr
= p
;
339 if (more
== 0 || __woverflow (f
, *s
++) == WEOF
)
348 _IO_wdefault_xsgetn (fp
, data
, n
)
354 wchar_t *s
= (wchar_t*) data
;
357 /* Data available. */
358 _IO_ssize_t count
= (fp
->_wide_data
->_IO_read_end
359 - fp
->_wide_data
->_IO_read_ptr
);
362 if ((_IO_size_t
) count
> more
)
367 s
= __wmempcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
369 memcpy (s
, fp
->_wide_data
->_IO_read_ptr
, count
);
372 fp
->_wide_data
->_IO_read_ptr
+= count
;
378 wchar_t *p
= fp
->_wide_data
->_IO_read_ptr
;
382 fp
->_wide_data
->_IO_read_ptr
= p
;
386 if (more
== 0 || __wunderflow (fp
) == WEOF
)
397 if (fp
->_wide_data
->_IO_buf_base
)
399 if (!(fp
->_flags
& _IO_UNBUFFERED
))
400 if (_IO_DOALLOCATE (fp
) != WEOF
)
402 _IO_wsetb (fp
, fp
->_wide_data
->_shortbuf
, fp
->_wide_data
->_shortbuf
+ 1, 0);
407 _IO_wdefault_setbuf (fp
, p
, len
)
412 if (_IO_SYNC (fp
) == EOF
)
414 if (p
== NULL
|| len
== 0)
416 fp
->_flags
|= _IO_UNBUFFERED
;
417 _IO_wsetb (fp
, fp
->_wide_data
->_shortbuf
, fp
->_wide_data
->_shortbuf
+ 1,
422 fp
->_flags
&= ~_IO_UNBUFFERED
;
423 _IO_wsetb (fp
, p
, p
+ len
, 0);
425 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_write_ptr
426 = fp
->_wide_data
->_IO_write_end
= 0;
427 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_ptr
428 = fp
->_wide_data
->_IO_read_end
= 0;
434 _IO_wdefault_doallocate (fp
)
439 ALLOC_WBUF (buf
, _IO_BUFSIZ
, EOF
);
440 _IO_wsetb (fp
, buf
, buf
+ _IO_BUFSIZ
, 1);
446 _IO_switch_to_wget_mode (fp
)
449 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_write_base
)
450 if (_IO_OVERFLOW (fp
, WEOF
) == WEOF
)
452 if (_IO_in_backup (fp
))
453 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_backup_base
;
456 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_buf_base
;
457 if (fp
->_wide_data
->_IO_write_ptr
> fp
->_wide_data
->_IO_read_end
)
458 fp
->_wide_data
->_IO_read_end
= fp
->_wide_data
->_IO_write_ptr
;
460 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_write_ptr
;
462 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_write_ptr
463 = fp
->_wide_data
->_IO_write_end
= fp
->_wide_data
->_IO_read_ptr
;
465 fp
->_flags
&= ~_IO_CURRENTLY_PUTTING
;
470 _IO_free_wbackup_area (fp
)
473 if (_IO_in_backup (fp
))
474 _IO_switch_to_main_wget_area (fp
); /* Just in case. */
475 free (fp
->_wide_data
->_IO_save_base
);
476 fp
->_wide_data
->_IO_save_base
= NULL
;
477 fp
->_wide_data
->_IO_save_end
= NULL
;
478 fp
->_wide_data
->_IO_backup_base
= NULL
;
483 _IO_switch_to_wput_mode (fp
)
486 fp
->_wide_data
->_IO_write_base
= fp
->_wide_data
->_IO_read_ptr
;
487 fp
->_wide_data
->_IO_write_ptr
= fp
->_wide_data
->_IO_read_ptr
;
488 /* Following is wrong if line- or un-buffered? */
489 fp
->_wide_data
->_IO_write_end
= (fp
->_flags
& _IO_IN_BACKUP
490 ? fp
->_wide_data
->_IO_read_end
491 : fp
->_wide_data
->_IO_buf_end
);
493 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
;
494 fp
->_wide_data
->_IO_read_base
= fp
->_wide_data
->_IO_read_end
;
496 fp
->_flags
|= _IO_CURRENTLY_PUTTING
;
506 save_for_wbackup (fp
, end_p
)
510 /* Append [_IO_read_base..end_p] to backup area. */
511 _IO_ssize_t least_mark
= _IO_least_wmarker (fp
, end_p
);
512 /* needed_size is how much space we need in the backup area. */
513 _IO_size_t needed_size
= ((end_p
- fp
->_wide_data
->_IO_read_base
)
515 /* FIXME: Dubious arithmetic if pointers are NULL */
516 _IO_size_t current_Bsize
= (fp
->_wide_data
->_IO_save_end
517 - fp
->_wide_data
->_IO_save_base
);
518 _IO_size_t avail
; /* Extra space available for future expansion. */
520 struct _IO_marker
*mark
;
521 if (needed_size
> current_Bsize
)
525 new_buffer
= (wchar_t *) malloc ((avail
+ needed_size
)
527 if (new_buffer
== NULL
)
528 return EOF
; /* FIXME */
532 __wmempcpy (__wmempcpy (new_buffer
+ avail
,
533 fp
->_wide_data
->_IO_save_end
+ least_mark
,
535 fp
->_wide_data
->_IO_read_base
,
536 end_p
- fp
->_wide_data
->_IO_read_base
);
538 memcpy (new_buffer
+ avail
,
539 fp
->_wide_data
->_IO_save_end
+ least_mark
,
540 -least_mark
* sizeof (wchar_t));
541 memcpy (new_buffer
+ avail
- least_mark
,
542 fp
->_wide_data
->_IO_read_base
,
543 (end_p
- fp
->_wide_data
->_IO_read_base
) * sizeof (wchar_t));
549 __wmemcpy (new_buffer
+ avail
,
550 fp
->_wide_data
->_IO_read_base
+ least_mark
,
553 memcpy (new_buffer
+ avail
,
554 fp
->_wide_data
->_IO_read_base
+ least_mark
,
555 needed_size
* sizeof (wchar_t));
558 if (fp
->_wide_data
->_IO_save_base
)
559 free (fp
->_wide_data
->_IO_save_base
);
560 fp
->_wide_data
->_IO_save_base
= new_buffer
;
561 fp
->_wide_data
->_IO_save_end
= new_buffer
+ avail
+ needed_size
;
565 avail
= current_Bsize
- needed_size
;
569 __wmemmove (fp
->_wide_data
->_IO_save_base
+ avail
,
570 fp
->_wide_data
->_IO_save_end
+ least_mark
,
572 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
573 fp
->_wide_data
->_IO_read_base
,
574 end_p
- fp
->_wide_data
->_IO_read_base
);
576 memmove (fp
->_wide_data
->_IO_save_base
+ avail
,
577 fp
->_wide_data
->_IO_save_end
+ least_mark
,
578 -least_mark
* sizeof (wchar_t));
579 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
- least_mark
,
580 fp
->_wide_data
->_IO_read_base
,
581 (end_p
- fp
->_wide_data
->_IO_read_base
) * sizeof (wchar_t));
584 else if (needed_size
> 0)
586 __wmemcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
587 fp
->_wide_data
->_IO_read_base
+ least_mark
,
590 memcpy (fp
->_wide_data
->_IO_save_base
+ avail
,
591 fp
->_wide_data
->_IO_read_base
+ least_mark
,
592 needed_size
* sizeof (wchar_t));
595 fp
->_wide_data
->_IO_backup_base
= fp
->_wide_data
->_IO_save_base
+ avail
;
596 /* Adjust all the streammarkers. */
597 delta
= end_p
- fp
->_wide_data
->_IO_read_base
;
598 for (mark
= fp
->_markers
; mark
!= NULL
; mark
= mark
->_next
)
604 _IO_sputbackwc (fp
, c
)
610 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
611 && (wchar_t)fp
->_wide_data
->_IO_read_ptr
[-1] == (wchar_t) c
)
613 fp
->_wide_data
->_IO_read_ptr
--;
617 result
= _IO_PBACKFAIL (fp
, c
);
620 fp
->_flags
&= ~_IO_EOF_SEEN
;
631 if (fp
->_wide_data
->_IO_read_ptr
> fp
->_wide_data
->_IO_read_base
)
633 fp
->_wide_data
->_IO_read_ptr
--;
634 result
= *fp
->_wide_data
->_IO_read_ptr
;
637 result
= _IO_PBACKFAIL (fp
, EOF
);
640 fp
->_flags
&= ~_IO_EOF_SEEN
;
647 _IO_adjust_wcolumn (start
, line
, count
)
652 const wchar_t *ptr
= line
+ count
;
655 return line
+ count
- ptr
- 1;
656 return start
+ count
;
660 _IO_init_wmarker (marker
, fp
)
661 struct _IO_marker
*marker
;
665 if (_IO_in_put_mode (fp
))
666 _IO_switch_to_wget_mode (fp
);
667 if (_IO_in_backup (fp
))
668 marker
->_pos
= fp
->_wide_data
->_IO_read_ptr
- fp
->_wide_data
->_IO_read_end
;
670 marker
->_pos
= (fp
->_wide_data
->_IO_read_ptr
671 - fp
->_wide_data
->_IO_read_base
);
673 /* Should perhaps sort the chain? */
674 marker
->_next
= fp
->_markers
;
675 fp
->_markers
= marker
;
678 #define BAD_DELTA EOF
680 /* Return difference between MARK and current position of MARK's stream. */
682 _IO_wmarker_delta (mark
)
683 struct _IO_marker
*mark
;
686 if (mark
->_sbuf
== NULL
)
688 if (_IO_in_backup (mark
->_sbuf
))
689 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
690 - mark
->_sbuf
->_wide_data
->_IO_read_end
);
692 cur_pos
= (mark
->_sbuf
->_wide_data
->_IO_read_ptr
693 - mark
->_sbuf
->_wide_data
->_IO_read_base
);
694 return mark
->_pos
- cur_pos
;
698 _IO_seekwmark (fp
, mark
, delta
)
700 struct _IO_marker
*mark
;
703 if (mark
->_sbuf
!= fp
)
707 if (_IO_in_backup (fp
))
708 _IO_switch_to_main_wget_area (fp
);
709 fp
->_wide_data
->_IO_read_ptr
= (fp
->_wide_data
->_IO_read_base
714 if (!_IO_in_backup (fp
))
715 _IO_switch_to_wbackup_area (fp
);
716 fp
->_wide_data
->_IO_read_ptr
= fp
->_wide_data
->_IO_read_end
+ mark
->_pos
;
722 _IO_unsave_wmarkers (fp
)
725 struct _IO_marker
*mark
= fp
->_markers
;
729 streampos offset
= seekoff (0, ios::cur
, ios::in
);
732 offset
+= eGptr () - Gbase ();
733 for ( ; mark
!= NULL
; mark
= mark
->_next
)
734 mark
->set_streampos (mark
->_pos
+ offset
);
738 for ( ; mark
!= NULL
; mark
= mark
->_next
)
739 mark
->set_streampos (EOF
);
745 if (_IO_have_backup (fp
))
746 _IO_free_wbackup_area (fp
);