1 /* Copyright (C) 1993, 95, 97, 98, 99, 2000 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>. 5 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. 10 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. 15 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, 19 MA 02111-1307, USA. 20 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. */ 27 28 #include <assert.h> 29 #include <libioP.h> 30 #if defined(_GLIBCPP_USE_WCHAR_T) || defined(_GLIBCPP_USE_TYPE_WCHAR_T) 31 #include <wchar.h> 32 #ifdef HAVE_GCONV_H 33 # include <gconv.h> 34 #endif 35 #include <stdlib.h> 36 #include <string.h> 37 38 39 #ifndef _LIBC 40 # define _IO_new_do_write _IO_do_write 41 # define _IO_new_file_attach _IO_file_attach 42 # define _IO_new_file_close_it _IO_file_close_it 43 # define _IO_new_file_finish _IO_file_finish 44 # define _IO_new_file_fopen _IO_file_fopen 45 # define _IO_new_file_init _IO_file_init 46 # define _IO_new_file_setbuf _IO_file_setbuf 47 # define _IO_new_file_sync _IO_file_sync 48 # define _IO_new_file_overflow _IO_file_overflow 49 # define _IO_new_file_seekoff _IO_file_seekoff 50 # define _IO_new_file_underflow _IO_file_underflow 51 # define _IO_new_file_write _IO_file_write 52 # define _IO_new_file_xsputn _IO_file_xsputn 53 #endif 54 55 56 _IO_FILE * 57 _IO_wfile_setbuf (fp, p, len) 58 _IO_FILE *fp; 59 wchar_t *p; 60 _IO_ssize_t len; 61 { 62 if (_IO_wdefault_setbuf (fp, p, len) == NULL) 63 return NULL; 64 65 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr = 66 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base; 67 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base, 68 fp->_wide_data->_IO_buf_base); 69 70 return fp; 71 } 72 73 74 /* Convert TO_DO wide character from DATA to FP. 75 Then mark FP as having empty buffers. */ 76 int 77 _IO_wdo_write (fp, data, to_do) 78 _IO_FILE *fp; 79 const wchar_t *data; 80 _IO_size_t to_do; 81 { 82 struct _IO_codecvt *cc = fp->_codecvt; 83 84 if (to_do > 0) 85 { 86 if (fp->_IO_write_end == fp->_IO_write_ptr 87 && fp->_IO_write_end != fp->_IO_write_base) 88 { 89 if (_IO_new_do_write (fp, fp->_IO_write_base, 90 fp->_IO_write_ptr - fp->_IO_write_base) == EOF) 91 return EOF; 92 } 93 94 do 95 { 96 enum __codecvt_result result; 97 const wchar_t *new_data; 98 99 /* Now convert from the internal format into the external buffer. */ 100 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state, 101 data, data + to_do, &new_data, 102 fp->_IO_write_ptr, 103 fp->_IO_buf_end, 104 &fp->_IO_write_ptr); 105 106 /* Write out what we produced so far. */ 107 if (_IO_new_do_write (fp, fp->_IO_write_base, 108 fp->_IO_write_ptr - fp->_IO_write_base) == EOF) 109 /* Something went wrong. */ 110 return EOF; 111 112 to_do -= new_data - data; 113 114 /* Next see whether we had problems during the conversion. If yes, 115 we cannot go on. */ 116 if (result != __codecvt_ok 117 && (result != __codecvt_partial || new_data - data == 0)) 118 break; 119 120 data = new_data; 121 } 122 while (to_do > 0); 123 } 124 125 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base, 126 fp->_wide_data->_IO_buf_base); 127 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr 128 = fp->_wide_data->_IO_buf_base; 129 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) 130 ? fp->_wide_data->_IO_buf_base 131 : fp->_wide_data->_IO_buf_end); 132 133 return to_do == 0 ? 0 : WEOF; 134 } 135 136 137 wint_t 138 _IO_wfile_underflow (fp) 139 _IO_FILE *fp; 140 { 141 struct _IO_codecvt *cd; 142 enum __codecvt_result status; 143 _IO_ssize_t count; 144 int tries; 145 const char *read_ptr_copy; 146 147 if (fp->_flags & _IO_NO_READS) 148 { 149 fp->_flags |= _IO_ERR_SEEN; 150 __set_errno (EBADF); 151 return WEOF; 152 } 153 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) 154 return *fp->_wide_data->_IO_read_ptr; 155 156 cd = fp->_codecvt; 157 158 /* Maybe there is something left in the external buffer. */ 159 if (fp->_IO_read_ptr < fp->_IO_read_end) 160 { 161 /* Convert it. */ 162 size_t avail_bytes = fp->_IO_read_end - fp->_IO_read_ptr; 163 164 if (avail_bytes >= (*cd->__codecvt_do_max_length) (cd)) 165 { 166 /* There is more in the external. */ 167 const char *read_stop = (const char *) fp->_IO_read_ptr; 168 169 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; 170 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, 171 fp->_IO_read_ptr, fp->_IO_read_end, 172 &read_stop, 173 fp->_wide_data->_IO_read_end, 174 fp->_wide_data->_IO_buf_end, 175 &fp->_wide_data->_IO_read_end); 176 177 fp->_IO_read_ptr = (char *) read_stop; 178 179 /* If we managed to generate some text return the next character. */ 180 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) 181 return *fp->_wide_data->_IO_read_ptr; 182 183 if (status == __codecvt_error) 184 { 185 __set_errno (EILSEQ); 186 fp->_flags |= _IO_ERR_SEEN; 187 return WEOF; 188 } 189 } 190 191 /* Move the remaining content of the read buffer to the beginning. */ 192 memmove (fp->_IO_buf_base, fp->_IO_read_ptr, 193 fp->_IO_read_end - fp->_IO_read_ptr); 194 fp->_IO_read_end = (fp->_IO_buf_base 195 + (fp->_IO_read_end - fp->_IO_read_ptr)); 196 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base; 197 } 198 else 199 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end = 200 fp->_IO_buf_base; 201 202 if (fp->_IO_buf_base == NULL) 203 { 204 /* Maybe we already have a push back pointer. */ 205 if (fp->_IO_save_base != NULL) 206 { 207 free (fp->_IO_save_base); 208 fp->_flags &= ~_IO_IN_BACKUP; 209 } 210 _IO_doallocbuf (fp); 211 212 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end = 213 fp->_IO_buf_base; 214 } 215 216 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = 217 fp->_IO_buf_base; 218 219 if (fp->_wide_data->_IO_buf_base == NULL) 220 { 221 /* Maybe we already have a push back pointer. */ 222 if (fp->_wide_data->_IO_save_base != NULL) 223 { 224 free (fp->_wide_data->_IO_save_base); 225 fp->_flags &= ~_IO_IN_BACKUP; 226 } 227 _IO_wdoallocbuf (fp); 228 } 229 230 /* Flush all line buffered files before reading. */ 231 /* FIXME This can/should be moved to genops ?? */ 232 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) 233 _IO_flush_all_linebuffered (); 234 235 _IO_switch_to_get_mode (fp); 236 237 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = 238 fp->_wide_data->_IO_buf_base; 239 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base; 240 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr = 241 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base; 242 243 tries = 0; 244 again: 245 count = _IO_SYSREAD (fp, fp->_IO_read_end, 246 fp->_IO_buf_end - fp->_IO_read_end); 247 if (count <= 0) 248 { 249 if (count == 0 && tries == 0) 250 fp->_flags |= _IO_EOF_SEEN; 251 else 252 fp->_flags |= _IO_ERR_SEEN, count = 0; 253 } 254 fp->_IO_read_end += count; 255 if (count == 0) 256 { 257 if (tries != 0) 258 /* There are some bytes in the external buffer but they don't 259 convert to anything. */ 260 __set_errno (EILSEQ); 261 return WEOF; 262 } 263 if (fp->_offset != _IO_pos_BAD) 264 _IO_pos_adjust (fp->_offset, count); 265 266 /* Now convert the read input. */ 267 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; 268 fp->_IO_read_base = fp->_IO_read_ptr; 269 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, 270 fp->_IO_read_ptr, fp->_IO_read_end, 271 &read_ptr_copy, 272 fp->_wide_data->_IO_read_end, 273 fp->_wide_data->_IO_buf_end, 274 &fp->_wide_data->_IO_read_end); 275 276 fp->_IO_read_ptr = (char *) read_ptr_copy; 277 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base) 278 { 279 if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end) 280 { 281 __set_errno (EILSEQ); 282 fp->_flags |= _IO_ERR_SEEN; 283 return WEOF; 284 } 285 286 /* The read bytes make no complete character. Try reading again. */ 287 assert (status == __codecvt_partial); 288 ++tries; 289 goto again; 290 } 291 292 return *fp->_wide_data->_IO_read_ptr; 293 } 294 295 296 wint_t 297 _IO_wfile_overflow (f, wch) 298 _IO_FILE *f; 299 wint_t wch; 300 { 301 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */ 302 { 303 f->_flags |= _IO_ERR_SEEN; 304 __set_errno (EBADF); 305 return WEOF; 306 } 307 /* If currently reading or no buffer allocated. */ 308 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0) 309 { 310 /* Allocate a buffer if needed. */ 311 if (f->_wide_data->_IO_write_base == 0) 312 { 313 _IO_wdoallocbuf (f); 314 _IO_wsetg (f, f->_wide_data->_IO_buf_base, 315 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base); 316 317 if (f->_IO_write_base == NULL) 318 { 319 _IO_doallocbuf (f); 320 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); 321 } 322 } 323 else 324 { 325 /* Otherwise must be currently reading. If _IO_read_ptr 326 (and hence also _IO_read_end) is at the buffer end, 327 logically slide the buffer forwards one block (by setting 328 the read pointers to all point at the beginning of the 329 block). This makes room for subsequent output. 330 Otherwise, set the read pointers to _IO_read_end (leaving 331 that alone, so it can continue to correspond to the 332 external position). */ 333 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end) 334 { 335 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base; 336 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr = 337 f->_wide_data->_IO_buf_base; 338 } 339 } 340 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr; 341 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr; 342 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end; 343 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr = 344 f->_wide_data->_IO_read_end; 345 346 f->_IO_write_ptr = f->_IO_read_ptr; 347 f->_IO_write_base = f->_IO_write_ptr; 348 f->_IO_write_end = f->_IO_buf_end; 349 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end; 350 351 f->_flags |= _IO_CURRENTLY_PUTTING; 352 if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) 353 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr; 354 } 355 if (wch == WEOF) 356 return _IO_do_flush (f); 357 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end) 358 /* Buffer is really full */ 359 if (_IO_do_flush (f) == WEOF) 360 return WEOF; 361 *f->_wide_data->_IO_write_ptr++ = wch; 362 if ((f->_flags & _IO_UNBUFFERED) 363 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n')) 364 if (_IO_do_flush (f) == WEOF) 365 return WEOF; 366 return wch; 367 } 368 369 wint_t 370 _IO_wfile_sync (fp) 371 _IO_FILE *fp; 372 { 373 _IO_ssize_t delta; 374 wint_t retval = 0; 375 376 /* char* ptr = cur_ptr(); */ 377 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base) 378 if (_IO_do_flush (fp)) 379 return WEOF; 380 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end; 381 if (delta != 0) 382 { 383 /* We have to find out how many bytes we have to go back in the 384 external buffer. */ 385 struct _IO_codecvt *cv = fp->_codecvt; 386 _IO_off64_t new_pos; 387 388 int clen = (*cv->__codecvt_do_encoding) (cv); 389 390 if (clen > 0) 391 /* It is easy, a fixed number of input bytes are used for each 392 wide character. */ 393 delta *= clen; 394 else 395 { 396 /* We have to find out the hard way how much to back off. 397 To do this we determine how much input we needed to 398 generate the wide characters up to the current reading 399 position. */ 400 int nread; 401 402 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; 403 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, 404 fp->_IO_read_base, 405 fp->_IO_read_end, delta); 406 fp->_IO_read_ptr = fp->_IO_read_base + nread; 407 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread); 408 } 409 410 new_pos = _IO_SYSSEEK (fp, delta, 1); 411 if (new_pos != (_IO_off64_t) EOF) 412 { 413 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr; 414 fp->_IO_read_end = fp->_IO_read_ptr; 415 } 416 #ifdef ESPIPE 417 else if (errno == ESPIPE) 418 ; /* Ignore error from unseekable devices. */ 419 #endif 420 else 421 retval = WEOF; 422 } 423 if (retval != WEOF) 424 fp->_offset = _IO_pos_BAD; 425 /* FIXME: Cleanup - can this be shared? */ 426 /* setg(base(), ptr, ptr); */ 427 return retval; 428 } 429 430 _IO_off64_t 431 _IO_wfile_seekoff (fp, offset, dir, mode) 432 _IO_FILE *fp; 433 _IO_off64_t offset; 434 int dir; 435 int mode; 436 { 437 _IO_off64_t result; 438 _IO_off64_t delta, new_offset; 439 long int count; 440 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file 441 offset of the underlying file must be exact. */ 442 int must_be_exact = ((fp->_wide_data->_IO_read_base 443 == fp->_wide_data->_IO_read_end) 444 && (fp->_wide_data->_IO_write_base 445 == fp->_wide_data->_IO_write_ptr)); 446 447 if (mode == 0) 448 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ 449 450 /* Flush unwritten characters. 451 (This may do an unneeded write if we seek within the buffer. 452 But to be able to switch to reading, we would need to set 453 egptr to ptr. That can't be done in the current design, 454 which assumes file_ptr() is eGptr. Anyway, since we probably 455 end up flushing when we close(), it doesn't make much difference.) 456 FIXME: simulate mem-papped files. */ 457 458 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base 459 || _IO_in_put_mode (fp)) 460 if (_IO_switch_to_wget_mode (fp)) 461 return WEOF; 462 463 if (fp->_wide_data->_IO_buf_base == NULL) 464 { 465 /* It could be that we already have a pushback buffer. */ 466 if (fp->_wide_data->_IO_read_base != NULL) 467 { 468 free (fp->_wide_data->_IO_read_base); 469 fp->_flags &= ~_IO_IN_BACKUP; 470 } 471 _IO_doallocbuf (fp); 472 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); 473 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); 474 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, 475 fp->_wide_data->_IO_buf_base); 476 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, 477 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base); 478 } 479 480 switch (dir) 481 { 482 struct _IO_codecvt *cv; 483 int clen; 484 485 case _IO_seek_cur: 486 /* Adjust for read-ahead (bytes is buffer). To do this we must 487 find out which position in the external buffer corresponds to 488 the current position in the internal buffer. */ 489 cv = fp->_codecvt; 490 clen = (*cv->__codecvt_do_encoding) (cv); 491 492 if (clen > 0) 493 offset -= (fp->_wide_data->_IO_read_end 494 - fp->_wide_data->_IO_read_ptr) * clen; 495 else 496 { 497 int nread; 498 499 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end; 500 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; 501 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, 502 fp->_IO_read_base, 503 fp->_IO_read_end, delta); 504 fp->_IO_read_ptr = fp->_IO_read_base + nread; 505 offset -= fp->_IO_read_end - fp->_IO_read_base - nread; 506 } 507 508 if (fp->_offset == _IO_pos_BAD) 509 goto dumb; 510 /* Make offset absolute, assuming current pointer is file_ptr(). */ 511 offset += fp->_offset; 512 513 dir = _IO_seek_set; 514 break; 515 case _IO_seek_set: 516 break; 517 case _IO_seek_end: 518 { 519 struct _G_stat64 st; 520 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode)) 521 { 522 offset += st.st_size; 523 dir = _IO_seek_set; 524 } 525 else 526 goto dumb; 527 } 528 } 529 /* At this point, dir==_IO_seek_set. */ 530 531 /* If we are only interested in the current position we've found it now. */ 532 if (mode == 0) 533 return offset; 534 535 /* If destination is within current buffer, optimize: */ 536 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL 537 && !_IO_in_backup (fp)) 538 { 539 /* Offset relative to start of main get area. */ 540 _IO_off64_t rel_offset = (offset - fp->_offset 541 + (fp->_IO_read_end - fp->_IO_read_base)); 542 if (rel_offset >= 0) 543 { 544 #if 0 545 if (_IO_in_backup (fp)) 546 _IO_switch_to_main_get_area (fp); 547 #endif 548 if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base) 549 { 550 fp->_IO_read_ptr = fp->_IO_read_base + rel_offset; 551 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); 552 553 /* Now set the pointer for the internal buffer. This 554 might be an iterative process. Though the read 555 pointer is somewhere in the current external buffer 556 this does not mean we can convert this whole buffer 557 at once fitting in the internal buffer. */ 558 do 559 { 560 561 } 562 while (0); 563 564 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 565 goto resync; 566 } 567 #ifdef TODO 568 /* If we have streammarkers, seek forward by reading ahead. */ 569 if (_IO_have_markers (fp)) 570 { 571 int to_skip = rel_offset 572 - (fp->_IO_read_ptr - fp->_IO_read_base); 573 if (ignore (to_skip) != to_skip) 574 goto dumb; 575 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 576 goto resync; 577 } 578 #endif 579 } 580 #ifdef TODO 581 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ()) 582 { 583 if (!_IO_in_backup (fp)) 584 _IO_switch_to_backup_area (fp); 585 gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr); 586 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 587 goto resync; 588 } 589 #endif 590 } 591 592 #ifdef TODO 593 _IO_unsave_markers (fp); 594 #endif 595 596 if (fp->_flags & _IO_NO_READS) 597 goto dumb; 598 599 /* Try to seek to a block boundary, to improve kernel page management. */ 600 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1); 601 delta = offset - new_offset; 602 if (delta > fp->_IO_buf_end - fp->_IO_buf_base) 603 { 604 new_offset = offset; 605 delta = 0; 606 } 607 result = _IO_SYSSEEK (fp, new_offset, 0); 608 if (result < 0) 609 return EOF; 610 if (delta == 0) 611 count = 0; 612 else 613 { 614 count = _IO_SYSREAD (fp, fp->_IO_buf_base, 615 (must_be_exact 616 ? delta : fp->_IO_buf_end - fp->_IO_buf_base)); 617 if (count < delta) 618 { 619 /* We weren't allowed to read, but try to seek the remainder. */ 620 offset = count == EOF ? delta : delta-count; 621 dir = _IO_seek_cur; 622 goto dumb; 623 } 624 } 625 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta, 626 fp->_IO_buf_base + count); 627 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); 628 fp->_offset = result + count; 629 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 630 return offset; 631 dumb: 632 633 _IO_unsave_markers (fp); 634 result = _IO_SYSSEEK (fp, offset, dir); 635 if (result != EOF) 636 { 637 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 638 fp->_offset = result; 639 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); 640 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); 641 } 642 return result; 643 644 resync: 645 /* We need to do it since it is possible that the file offset in 646 the kernel may be changed behind our back. It may happen when 647 we fopen a file and then do a fork. One process may access the 648 the file and the kernel file offset will be changed. */ 649 if (fp->_offset >= 0) 650 _IO_SYSSEEK (fp, fp->_offset, 0); 651 652 return offset; 653 } 654 655 656 _IO_size_t 657 _IO_wfile_xsputn (f, data, n) 658 _IO_FILE *f; 659 const void *data; 660 _IO_size_t n; 661 { 662 register const wchar_t *s = (const wchar_t *) data; 663 _IO_size_t to_do = n; 664 int must_flush = 0; 665 _IO_size_t count; 666 667 if (n <= 0) 668 return 0; 669 /* This is an optimized implementation. 670 If the amount to be written straddles a block boundary 671 (or the filebuf is unbuffered), use sys_write directly. */ 672 673 /* First figure out how much space is available in the buffer. */ 674 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr; 675 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) 676 { 677 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr; 678 if (count >= n) 679 { 680 register const wchar_t *p; 681 for (p = s + n; p > s; ) 682 { 683 if (*--p == L'\n') 684 { 685 count = p - s + 1; 686 must_flush = 1; 687 break; 688 } 689 } 690 } 691 } 692 /* Then fill the buffer. */ 693 if (count > 0) 694 { 695 if (count > to_do) 696 count = to_do; 697 if (count > 20) 698 { 699 #ifdef _LIBC 700 f->_wide_data->_IO_write_ptr = 701 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count); 702 #else 703 wmemcpy (f->_wide_data->_IO_write_ptr, s, count); 704 f->_wide_data->_IO_write_ptr += count; 705 #endif 706 s += count; 707 } 708 else 709 { 710 register wchar_t *p = f->_wide_data->_IO_write_ptr; 711 register int i = (int) count; 712 while (--i >= 0) 713 *p++ = *s++; 714 f->_wide_data->_IO_write_ptr = p; 715 } 716 to_do -= count; 717 } 718 if (to_do > 0) 719 to_do -= _IO_wdefault_xsputn (f, s, to_do); 720 if (must_flush 721 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base) 722 _IO_wdo_write (f, f->_wide_data->_IO_write_base, 723 f->_wide_data->_IO_write_ptr 724 - f->_wide_data->_IO_write_base); 725 726 return n - to_do; 727 } 728 729 730 struct _IO_jump_t _IO_wfile_jumps = 731 { 732 JUMP_INIT_DUMMY, 733 JUMP_INIT(finish, _IO_new_file_finish), 734 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow), 735 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow), 736 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow), 737 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail), 738 JUMP_INIT(xsputn, _IO_wfile_xsputn), 739 JUMP_INIT(xsgetn, _IO_file_xsgetn), 740 JUMP_INIT(seekoff, _IO_wfile_seekoff), 741 JUMP_INIT(seekpos, _IO_default_seekpos), 742 JUMP_INIT(setbuf, _IO_new_file_setbuf), 743 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync), 744 JUMP_INIT(doallocate, _IO_wfile_doallocate), 745 JUMP_INIT(read, _IO_file_read), 746 JUMP_INIT(write, _IO_new_file_write), 747 JUMP_INIT(seek, _IO_file_seek), 748 JUMP_INIT(close, _IO_file_close), 749 JUMP_INIT(stat, _IO_file_stat), 750 JUMP_INIT(showmanyc, _IO_default_showmanyc), 751 JUMP_INIT(imbue, _IO_default_imbue) 752 }; 753 754 #endif /* _GLIBCPP_USE_WCHAR_T */ 755