1 /* Copyright (C) 1993,95,97,98,99,2000,2001,2002 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 #include <assert.h> 31 #include <libioP.h> 32 #include <wchar.h> 33 #include <gconv.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/stat.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 /* Convert TO_DO wide character from DATA to FP. 57 Then mark FP as having empty buffers. */ 58 int 59 _IO_wdo_write (fp, data, to_do) 60 _IO_FILE *fp; 61 const wchar_t *data; 62 _IO_size_t to_do; 63 { 64 struct _IO_codecvt *cc = fp->_codecvt; 65 66 if (to_do > 0) 67 { 68 if (fp->_IO_write_end == fp->_IO_write_ptr 69 && fp->_IO_write_end != fp->_IO_write_base) 70 { 71 if (_IO_new_do_write (fp, fp->_IO_write_base, 72 fp->_IO_write_ptr - fp->_IO_write_base) == EOF) 73 return EOF; 74 } 75 76 do 77 { 78 enum __codecvt_result result; 79 const wchar_t *new_data; 80 81 /* Now convert from the internal format into the external buffer. */ 82 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state, 83 data, data + to_do, &new_data, 84 fp->_IO_write_ptr, 85 fp->_IO_buf_end, 86 &fp->_IO_write_ptr); 87 88 /* Write out what we produced so far. */ 89 if (_IO_new_do_write (fp, fp->_IO_write_base, 90 fp->_IO_write_ptr - fp->_IO_write_base) == EOF) 91 /* Something went wrong. */ 92 return WEOF; 93 94 to_do -= new_data - data; 95 96 /* Next see whether we had problems during the conversion. If yes, 97 we cannot go on. */ 98 if (result != __codecvt_ok 99 && (result != __codecvt_partial || new_data - data == 0)) 100 break; 101 102 data = new_data; 103 } 104 while (to_do > 0); 105 } 106 107 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base, 108 fp->_wide_data->_IO_buf_base); 109 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr 110 = fp->_wide_data->_IO_buf_base; 111 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) 112 ? fp->_wide_data->_IO_buf_base 113 : fp->_wide_data->_IO_buf_end); 114 115 return to_do == 0 ? 0 : WEOF; 116 } 117 INTDEF(_IO_wdo_write) 118 119 120 wint_t 121 _IO_wfile_underflow (fp) 122 _IO_FILE *fp; 123 { 124 struct _IO_codecvt *cd; 125 enum __codecvt_result status; 126 _IO_ssize_t count; 127 int tries; 128 const char *read_ptr_copy; 129 130 if (__builtin_expect (fp->_flags & _IO_NO_READS, 0)) 131 { 132 fp->_flags |= _IO_ERR_SEEN; 133 __set_errno (EBADF); 134 return WEOF; 135 } 136 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) 137 return *fp->_wide_data->_IO_read_ptr; 138 139 cd = fp->_codecvt; 140 141 /* Maybe there is something left in the external buffer. */ 142 if (fp->_IO_read_ptr < fp->_IO_read_end) 143 { 144 /* There is more in the external. Convert it. */ 145 const char *read_stop = (const char *) fp->_IO_read_ptr; 146 147 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; 148 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = 149 fp->_wide_data->_IO_buf_base; 150 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, 151 fp->_IO_read_ptr, fp->_IO_read_end, 152 &read_stop, 153 fp->_wide_data->_IO_read_ptr, 154 fp->_wide_data->_IO_buf_end, 155 &fp->_wide_data->_IO_read_end); 156 157 fp->_IO_read_ptr = (char *) read_stop; 158 159 /* If we managed to generate some text return the next character. */ 160 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) 161 return *fp->_wide_data->_IO_read_ptr; 162 163 if (status == __codecvt_error) 164 { 165 __set_errno (EILSEQ); 166 fp->_flags |= _IO_ERR_SEEN; 167 return WEOF; 168 } 169 170 /* Move the remaining content of the read buffer to the beginning. */ 171 memmove (fp->_IO_buf_base, fp->_IO_read_ptr, 172 fp->_IO_read_end - fp->_IO_read_ptr); 173 fp->_IO_read_end = (fp->_IO_buf_base 174 + (fp->_IO_read_end - fp->_IO_read_ptr)); 175 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base; 176 } 177 else 178 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end = 179 fp->_IO_buf_base; 180 181 if (fp->_IO_buf_base == NULL) 182 { 183 /* Maybe we already have a push back pointer. */ 184 if (fp->_IO_save_base != NULL) 185 { 186 free (fp->_IO_save_base); 187 fp->_flags &= ~_IO_IN_BACKUP; 188 } 189 INTUSE(_IO_doallocbuf) (fp); 190 191 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end = 192 fp->_IO_buf_base; 193 } 194 195 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = 196 fp->_IO_buf_base; 197 198 if (fp->_wide_data->_IO_buf_base == NULL) 199 { 200 /* Maybe we already have a push back pointer. */ 201 if (fp->_wide_data->_IO_save_base != NULL) 202 { 203 free (fp->_wide_data->_IO_save_base); 204 fp->_flags &= ~_IO_IN_BACKUP; 205 } 206 INTUSE(_IO_wdoallocbuf) (fp); 207 } 208 209 /* Flush all line buffered files before reading. */ 210 /* FIXME This can/should be moved to genops ?? */ 211 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) 212 { 213 #if 0 214 INTUSE(_IO_flush_all_linebuffered) (); 215 #else 216 /* We used to flush all line-buffered stream. This really isn't 217 required by any standard. My recollection is that 218 traditional Unix systems did this for stdout. stderr better 219 not be line buffered. So we do just that here 220 explicitly. --drepper */ 221 _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile, 222 _IO_stdout); 223 _IO_flockfile (_IO_stdout); 224 225 if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF)) 226 == (_IO_LINKED | _IO_LINE_BUF)) 227 _IO_OVERFLOW (_IO_stdout, EOF); 228 229 _IO_funlockfile (_IO_stdout); 230 _IO_cleanup_region_end (0); 231 #endif 232 } 233 234 INTUSE(_IO_switch_to_get_mode) (fp); 235 236 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = 237 fp->_wide_data->_IO_buf_base; 238 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base; 239 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr = 240 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base; 241 242 tries = 0; 243 again: 244 count = _IO_SYSREAD (fp, fp->_IO_read_end, 245 fp->_IO_buf_end - fp->_IO_read_end); 246 if (count <= 0) 247 { 248 if (count == 0 && tries == 0) 249 fp->_flags |= _IO_EOF_SEEN; 250 else 251 fp->_flags |= _IO_ERR_SEEN, count = 0; 252 } 253 fp->_IO_read_end += count; 254 if (count == 0) 255 { 256 if (tries != 0) 257 /* There are some bytes in the external buffer but they don't 258 convert to anything. */ 259 __set_errno (EILSEQ); 260 return WEOF; 261 } 262 if (fp->_offset != _IO_pos_BAD) 263 _IO_pos_adjust (fp->_offset, count); 264 265 /* Now convert the read input. */ 266 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; 267 fp->_IO_read_base = fp->_IO_read_ptr; 268 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, 269 fp->_IO_read_ptr, fp->_IO_read_end, 270 &read_ptr_copy, 271 fp->_wide_data->_IO_read_end, 272 fp->_wide_data->_IO_buf_end, 273 &fp->_wide_data->_IO_read_end); 274 275 fp->_IO_read_ptr = (char *) read_ptr_copy; 276 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base) 277 { 278 if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end) 279 { 280 __set_errno (EILSEQ); 281 fp->_flags |= _IO_ERR_SEEN; 282 return WEOF; 283 } 284 285 /* The read bytes make no complete character. Try reading again. */ 286 assert (status == __codecvt_partial); 287 ++tries; 288 goto again; 289 } 290 291 return *fp->_wide_data->_IO_read_ptr; 292 } 293 INTDEF(_IO_wfile_underflow) 294 295 296 #ifdef HAVE_MMAP 297 static wint_t 298 _IO_wfile_underflow_mmap (_IO_FILE *fp) 299 { 300 struct _IO_codecvt *cd; 301 enum __codecvt_result status; 302 const char *read_stop; 303 304 if (__builtin_expect (fp->_flags & _IO_NO_READS, 0)) 305 { 306 fp->_flags |= _IO_ERR_SEEN; 307 __set_errno (EBADF); 308 return WEOF; 309 } 310 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) 311 return *fp->_wide_data->_IO_read_ptr; 312 313 cd = fp->_codecvt; 314 315 /* Maybe there is something left in the external buffer. */ 316 if (fp->_IO_read_ptr >= fp->_IO_read_end 317 /* No. But maybe the read buffer is not fully set up. */ 318 && _IO_file_underflow_mmap (fp) == EOF) 319 /* Nothing available. _IO_file_underflow_mmap has set the EOF or error 320 flags as appropriate. */ 321 return WEOF; 322 323 /* There is more in the external. Convert it. */ 324 read_stop = (const char *) fp->_IO_read_ptr; 325 326 if (fp->_wide_data->_IO_buf_base == NULL) 327 { 328 /* Maybe we already have a push back pointer. */ 329 if (fp->_wide_data->_IO_save_base != NULL) 330 { 331 free (fp->_wide_data->_IO_save_base); 332 fp->_flags &= ~_IO_IN_BACKUP; 333 } 334 INTUSE(_IO_wdoallocbuf) (fp); 335 } 336 337 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state; 338 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr = 339 fp->_wide_data->_IO_buf_base; 340 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state, 341 fp->_IO_read_ptr, fp->_IO_read_end, 342 &read_stop, 343 fp->_wide_data->_IO_read_ptr, 344 fp->_wide_data->_IO_buf_end, 345 &fp->_wide_data->_IO_read_end); 346 347 fp->_IO_read_ptr = (char *) read_stop; 348 349 /* If we managed to generate some text return the next character. */ 350 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) 351 return *fp->_wide_data->_IO_read_ptr; 352 353 /* There is some garbage at the end of the file. */ 354 __set_errno (EILSEQ); 355 fp->_flags |= _IO_ERR_SEEN; 356 return WEOF; 357 } 358 359 static wint_t 360 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp) 361 { 362 /* This is the first read attempt. Doing the underflow will choose mmap 363 or vanilla operations and then punt to the chosen underflow routine. 364 Then we can punt to ours. */ 365 if (_IO_file_underflow_maybe_mmap (fp) == EOF) 366 return WEOF; 367 368 return _IO_WUNDERFLOW (fp); 369 } 370 #endif 371 372 373 wint_t 374 _IO_wfile_overflow (f, wch) 375 _IO_FILE *f; 376 wint_t wch; 377 { 378 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */ 379 { 380 f->_flags |= _IO_ERR_SEEN; 381 __set_errno (EBADF); 382 return WEOF; 383 } 384 /* If currently reading or no buffer allocated. */ 385 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0) 386 { 387 /* Allocate a buffer if needed. */ 388 if (f->_wide_data->_IO_write_base == 0) 389 { 390 INTUSE(_IO_wdoallocbuf) (f); 391 _IO_wsetg (f, f->_wide_data->_IO_buf_base, 392 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base); 393 394 if (f->_IO_write_base == NULL) 395 { 396 INTUSE(_IO_doallocbuf) (f); 397 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); 398 } 399 } 400 else 401 { 402 /* Otherwise must be currently reading. If _IO_read_ptr 403 (and hence also _IO_read_end) is at the buffer end, 404 logically slide the buffer forwards one block (by setting 405 the read pointers to all point at the beginning of the 406 block). This makes room for subsequent output. 407 Otherwise, set the read pointers to _IO_read_end (leaving 408 that alone, so it can continue to correspond to the 409 external position). */ 410 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end) 411 { 412 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base; 413 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr = 414 f->_wide_data->_IO_buf_base; 415 } 416 } 417 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr; 418 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr; 419 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end; 420 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr = 421 f->_wide_data->_IO_read_end; 422 423 f->_IO_write_ptr = f->_IO_read_ptr; 424 f->_IO_write_base = f->_IO_write_ptr; 425 f->_IO_write_end = f->_IO_buf_end; 426 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end; 427 428 f->_flags |= _IO_CURRENTLY_PUTTING; 429 if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) 430 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr; 431 } 432 if (wch == WEOF) 433 return _IO_do_flush (f); 434 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end) 435 /* Buffer is really full */ 436 if (_IO_do_flush (f) == EOF) 437 return WEOF; 438 *f->_wide_data->_IO_write_ptr++ = wch; 439 if ((f->_flags & _IO_UNBUFFERED) 440 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n')) 441 if (_IO_do_flush (f) == EOF) 442 return WEOF; 443 return wch; 444 } 445 INTDEF(_IO_wfile_overflow) 446 447 wint_t 448 _IO_wfile_sync (fp) 449 _IO_FILE *fp; 450 { 451 _IO_ssize_t delta; 452 wint_t retval = 0; 453 454 /* char* ptr = cur_ptr(); */ 455 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base) 456 if (_IO_do_flush (fp)) 457 return WEOF; 458 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end; 459 if (delta != 0) 460 { 461 /* We have to find out how many bytes we have to go back in the 462 external buffer. */ 463 struct _IO_codecvt *cv = fp->_codecvt; 464 _IO_off64_t new_pos; 465 466 int clen = (*cv->__codecvt_do_encoding) (cv); 467 468 if (clen > 0) 469 /* It is easy, a fixed number of input bytes are used for each 470 wide character. */ 471 delta *= clen; 472 else 473 { 474 /* We have to find out the hard way how much to back off. 475 To do this we determine how much input we needed to 476 generate the wide characters up to the current reading 477 position. */ 478 int nread; 479 480 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; 481 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, 482 fp->_IO_read_base, 483 fp->_IO_read_end, delta); 484 fp->_IO_read_ptr = fp->_IO_read_base + nread; 485 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread); 486 } 487 488 new_pos = _IO_SYSSEEK (fp, delta, 1); 489 if (new_pos != (_IO_off64_t) EOF) 490 { 491 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr; 492 fp->_IO_read_end = fp->_IO_read_ptr; 493 } 494 #ifdef ESPIPE 495 else if (errno == ESPIPE) 496 ; /* Ignore error from unseekable devices. */ 497 #endif 498 else 499 retval = WEOF; 500 } 501 if (retval != WEOF) 502 fp->_offset = _IO_pos_BAD; 503 /* FIXME: Cleanup - can this be shared? */ 504 /* setg(base(), ptr, ptr); */ 505 return retval; 506 } 507 INTDEF(_IO_wfile_sync) 508 509 _IO_off64_t 510 _IO_wfile_seekoff (fp, offset, dir, mode) 511 _IO_FILE *fp; 512 _IO_off64_t offset; 513 int dir; 514 int mode; 515 { 516 _IO_off64_t result; 517 _IO_off64_t delta, new_offset; 518 long int count; 519 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file 520 offset of the underlying file must be exact. */ 521 int must_be_exact = ((fp->_wide_data->_IO_read_base 522 == fp->_wide_data->_IO_read_end) 523 && (fp->_wide_data->_IO_write_base 524 == fp->_wide_data->_IO_write_ptr)); 525 526 if (mode == 0) 527 { 528 /* XXX For wide stream with backup store it is not very 529 reasonable to determine the offset. The pushed-back 530 character might require a state change and we need not be 531 able to compute the initial state by reverse transformation 532 since there is no guarantee of symmetry. So we don't even 533 try and return an error. */ 534 if (_IO_in_backup (fp)) 535 { 536 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end) 537 { 538 __set_errno (EINVAL); 539 return -1; 540 } 541 542 /* There is no more data in the backup buffer. We can 543 switch back. */ 544 INTUSE(_IO_switch_to_main_wget_area) (fp); 545 } 546 547 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ 548 } 549 550 /* Flush unwritten characters. 551 (This may do an unneeded write if we seek within the buffer. 552 But to be able to switch to reading, we would need to set 553 egptr to ptr. That can't be done in the current design, 554 which assumes file_ptr() is eGptr. Anyway, since we probably 555 end up flushing when we close(), it doesn't make much difference.) 556 FIXME: simulate mem-mapped files. */ 557 558 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base 559 || _IO_in_put_mode (fp)) 560 if (INTUSE(_IO_switch_to_wget_mode) (fp)) 561 return WEOF; 562 563 if (fp->_wide_data->_IO_buf_base == NULL) 564 { 565 /* It could be that we already have a pushback buffer. */ 566 if (fp->_wide_data->_IO_read_base != NULL) 567 { 568 free (fp->_wide_data->_IO_read_base); 569 fp->_flags &= ~_IO_IN_BACKUP; 570 } 571 INTUSE(_IO_doallocbuf) (fp); 572 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); 573 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); 574 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, 575 fp->_wide_data->_IO_buf_base); 576 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, 577 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base); 578 } 579 580 switch (dir) 581 { 582 struct _IO_codecvt *cv; 583 int clen; 584 585 case _IO_seek_cur: 586 /* Adjust for read-ahead (bytes is buffer). To do this we must 587 find out which position in the external buffer corresponds to 588 the current position in the internal buffer. */ 589 cv = fp->_codecvt; 590 clen = (*cv->__codecvt_do_encoding) (cv); 591 592 if (clen > 0) 593 offset -= (fp->_wide_data->_IO_read_end 594 - fp->_wide_data->_IO_read_ptr) * clen; 595 else 596 { 597 int nread; 598 599 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base; 600 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; 601 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, 602 fp->_IO_read_base, 603 fp->_IO_read_end, delta); 604 fp->_IO_read_ptr = fp->_IO_read_base + nread; 605 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr; 606 offset -= fp->_IO_read_end - fp->_IO_read_base - nread; 607 } 608 609 if (fp->_offset == _IO_pos_BAD) 610 goto dumb; 611 /* Make offset absolute, assuming current pointer is file_ptr(). */ 612 offset += fp->_offset; 613 614 dir = _IO_seek_set; 615 break; 616 case _IO_seek_set: 617 break; 618 case _IO_seek_end: 619 { 620 struct _G_stat64 st; 621 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode)) 622 { 623 offset += st.st_size; 624 dir = _IO_seek_set; 625 } 626 else 627 goto dumb; 628 } 629 } 630 /* At this point, dir==_IO_seek_set. */ 631 632 /* If we are only interested in the current position we've found it now. */ 633 if (mode == 0) 634 return offset; 635 636 /* If destination is within current buffer, optimize: */ 637 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL 638 && !_IO_in_backup (fp)) 639 { 640 /* Offset relative to start of main get area. */ 641 _IO_off64_t rel_offset = (offset - fp->_offset 642 + (fp->_IO_read_end - fp->_IO_buf_base)); 643 if (rel_offset >= 0) 644 { 645 #if 0 646 if (_IO_in_backup (fp)) 647 _IO_switch_to_main_get_area (fp); 648 #endif 649 if (rel_offset <= fp->_IO_read_end - fp->_IO_buf_base) 650 { 651 enum __codecvt_result status; 652 struct _IO_codecvt *cd = fp->_codecvt; 653 const char *read_ptr_copy; 654 655 fp->_IO_read_ptr = fp->_IO_read_base + rel_offset; 656 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); 657 658 /* Now set the pointer for the internal buffer. This 659 might be an iterative process. Though the read 660 pointer is somewhere in the current external buffer 661 this does not mean we can convert this whole buffer 662 at once fitting in the internal buffer. */ 663 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; 664 read_ptr_copy = fp->_IO_read_base; 665 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base; 666 do 667 { 668 wchar_t buffer[1024]; 669 wchar_t *ignore; 670 status = (*cd->__codecvt_do_in) (cd, 671 &fp->_wide_data->_IO_state, 672 read_ptr_copy, 673 fp->_IO_read_ptr, 674 &read_ptr_copy, 675 buffer, 676 buffer 677 + (sizeof (buffer) 678 / sizeof (buffer[0])), 679 &ignore); 680 if (status != __codecvt_ok && status != __codecvt_partial) 681 { 682 fp->_flags |= _IO_ERR_SEEN; 683 goto dumb; 684 } 685 } 686 while (read_ptr_copy != fp->_IO_read_ptr); 687 688 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base; 689 690 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 691 goto resync; 692 } 693 #ifdef TODO 694 /* If we have streammarkers, seek forward by reading ahead. */ 695 if (_IO_have_markers (fp)) 696 { 697 int to_skip = rel_offset 698 - (fp->_IO_read_ptr - fp->_IO_read_base); 699 if (ignore (to_skip) != to_skip) 700 goto dumb; 701 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 702 goto resync; 703 } 704 #endif 705 } 706 #ifdef TODO 707 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ()) 708 { 709 if (!_IO_in_backup (fp)) 710 _IO_switch_to_backup_area (fp); 711 gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr); 712 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 713 goto resync; 714 } 715 #endif 716 } 717 718 #ifdef TODO 719 INTUSE(_IO_unsave_markers) (fp); 720 #endif 721 722 if (fp->_flags & _IO_NO_READS) 723 goto dumb; 724 725 /* Try to seek to a block boundary, to improve kernel page management. */ 726 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1); 727 delta = offset - new_offset; 728 if (delta > fp->_IO_buf_end - fp->_IO_buf_base) 729 { 730 new_offset = offset; 731 delta = 0; 732 } 733 result = _IO_SYSSEEK (fp, new_offset, 0); 734 if (result < 0) 735 return EOF; 736 if (delta == 0) 737 count = 0; 738 else 739 { 740 count = _IO_SYSREAD (fp, fp->_IO_buf_base, 741 (must_be_exact 742 ? delta : fp->_IO_buf_end - fp->_IO_buf_base)); 743 if (count < delta) 744 { 745 /* We weren't allowed to read, but try to seek the remainder. */ 746 offset = count == EOF ? delta : delta-count; 747 dir = _IO_seek_cur; 748 goto dumb; 749 } 750 } 751 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta, 752 fp->_IO_buf_base + count); 753 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); 754 fp->_offset = result + count; 755 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 756 return offset; 757 dumb: 758 759 INTUSE(_IO_unsave_markers) (fp); 760 result = _IO_SYSSEEK (fp, offset, dir); 761 if (result != EOF) 762 { 763 _IO_mask_flags (fp, 0, _IO_EOF_SEEN); 764 fp->_offset = result; 765 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); 766 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); 767 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, 768 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base); 769 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, 770 fp->_wide_data->_IO_buf_base); 771 } 772 return result; 773 774 resync: 775 /* We need to do it since it is possible that the file offset in 776 the kernel may be changed behind our back. It may happen when 777 we fopen a file and then do a fork. One process may access the 778 the file and the kernel file offset will be changed. */ 779 if (fp->_offset >= 0) 780 _IO_SYSSEEK (fp, fp->_offset, 0); 781 782 return offset; 783 } 784 INTDEF(_IO_wfile_seekoff) 785 786 787 _IO_size_t 788 _IO_wfile_xsputn (f, data, n) 789 _IO_FILE *f; 790 const void *data; 791 _IO_size_t n; 792 { 793 register const wchar_t *s = (const wchar_t *) data; 794 _IO_size_t to_do = n; 795 int must_flush = 0; 796 _IO_size_t count; 797 798 if (n <= 0) 799 return 0; 800 /* This is an optimized implementation. 801 If the amount to be written straddles a block boundary 802 (or the filebuf is unbuffered), use sys_write directly. */ 803 804 /* First figure out how much space is available in the buffer. */ 805 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr; 806 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) 807 { 808 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr; 809 if (count >= n) 810 { 811 register const wchar_t *p; 812 for (p = s + n; p > s; ) 813 { 814 if (*--p == L'\n') 815 { 816 count = p - s + 1; 817 must_flush = 1; 818 break; 819 } 820 } 821 } 822 } 823 /* Then fill the buffer. */ 824 if (count > 0) 825 { 826 if (count > to_do) 827 count = to_do; 828 if (count > 20) 829 { 830 #ifdef _LIBC 831 f->_wide_data->_IO_write_ptr = 832 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count); 833 #else 834 wmemcpy (f->_wide_data->_IO_write_ptr, s, count); 835 f->_wide_data->_IO_write_ptr += count; 836 #endif 837 s += count; 838 } 839 else 840 { 841 register wchar_t *p = f->_wide_data->_IO_write_ptr; 842 register int i = (int) count; 843 while (--i >= 0) 844 *p++ = *s++; 845 f->_wide_data->_IO_write_ptr = p; 846 } 847 to_do -= count; 848 } 849 if (to_do > 0) 850 to_do -= INTUSE(_IO_wdefault_xsputn) (f, s, to_do); 851 if (must_flush 852 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base) 853 INTUSE(_IO_wdo_write) (f, f->_wide_data->_IO_write_base, 854 f->_wide_data->_IO_write_ptr 855 - f->_wide_data->_IO_write_base); 856 857 return n - to_do; 858 } 859 INTDEF(_IO_wfile_xsputn) 860 861 862 struct _IO_jump_t _IO_wfile_jumps = 863 { 864 JUMP_INIT_DUMMY, 865 JUMP_INIT(finish, _IO_new_file_finish), 866 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)), 867 JUMP_INIT(underflow, (_IO_underflow_t) INTUSE(_IO_wfile_underflow)), 868 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)), 869 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)), 870 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)), 871 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)), 872 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)), 873 JUMP_INIT(seekpos, _IO_default_seekpos), 874 JUMP_INIT(setbuf, _IO_new_file_setbuf), 875 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)), 876 JUMP_INIT(doallocate, _IO_wfile_doallocate), 877 JUMP_INIT(read, INTUSE(_IO_file_read)), 878 JUMP_INIT(write, _IO_new_file_write), 879 JUMP_INIT(seek, INTUSE(_IO_file_seek)), 880 JUMP_INIT(close, INTUSE(_IO_file_close)), 881 JUMP_INIT(stat, INTUSE(_IO_file_stat)), 882 JUMP_INIT(showmanyc, _IO_default_showmanyc), 883 JUMP_INIT(imbue, _IO_default_imbue) 884 }; 885 INTVARDEF(_IO_wfile_jumps) 886 887 888 #ifdef HAVE_MMAP 889 struct _IO_jump_t _IO_wfile_jumps_mmap = 890 { 891 JUMP_INIT_DUMMY, 892 JUMP_INIT(finish, _IO_new_file_finish), 893 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)), 894 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap), 895 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)), 896 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)), 897 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)), 898 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)), 899 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)), 900 JUMP_INIT(seekpos, _IO_default_seekpos), 901 JUMP_INIT(setbuf, _IO_file_setbuf_mmap), 902 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)), 903 JUMP_INIT(doallocate, _IO_wfile_doallocate), 904 JUMP_INIT(read, INTUSE(_IO_file_read)), 905 JUMP_INIT(write, _IO_new_file_write), 906 JUMP_INIT(seek, INTUSE(_IO_file_seek)), 907 JUMP_INIT(close, _IO_file_close_mmap), 908 JUMP_INIT(stat, INTUSE(_IO_file_stat)), 909 JUMP_INIT(showmanyc, _IO_default_showmanyc), 910 JUMP_INIT(imbue, _IO_default_imbue) 911 }; 912 913 struct _IO_jump_t _IO_wfile_jumps_maybe_mmap = 914 { 915 JUMP_INIT_DUMMY, 916 JUMP_INIT(finish, _IO_new_file_finish), 917 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)), 918 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap), 919 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)), 920 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)), 921 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)), 922 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)), 923 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)), 924 JUMP_INIT(seekpos, _IO_default_seekpos), 925 JUMP_INIT(setbuf, _IO_file_setbuf_mmap), 926 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)), 927 JUMP_INIT(doallocate, _IO_wfile_doallocate), 928 JUMP_INIT(read, INTUSE(_IO_file_read)), 929 JUMP_INIT(write, _IO_new_file_write), 930 JUMP_INIT(seek, INTUSE(_IO_file_seek)), 931 JUMP_INIT(close, INTUSE(_IO_file_close)), 932 JUMP_INIT(stat, INTUSE(_IO_file_stat)), 933 JUMP_INIT(showmanyc, _IO_default_showmanyc), 934 JUMP_INIT(imbue, _IO_default_imbue) 935 }; 936 #endif 937