Back to index

glibc  2.9
wfileops.c
Go to the documentation of this file.
00001 /* Copyright (C) 1993,1995,1997-2003,2004, 2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Written by Ulrich Drepper <drepper@cygnus.com>.
00004    Based on the single byte version by Per Bothner <bothner@cygnus.com>.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.
00020 
00021    As a special exception, if you link the code in this file with
00022    files compiled with a GNU compiler to produce an executable,
00023    that does not cause the resulting executable to be covered by
00024    the GNU Lesser General Public License.  This exception does not
00025    however invalidate any other reasons why the executable file
00026    might be covered by the GNU Lesser General Public License.
00027    This exception applies to code released by its copyright holders
00028    in files containing the exception.  */
00029 
00030 #include <assert.h>
00031 #include <libioP.h>
00032 #include <wchar.h>
00033 #include <gconv.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 
00037 
00038 #ifndef _LIBC
00039 # define _IO_new_do_write _IO_do_write
00040 # define _IO_new_file_attach _IO_file_attach
00041 # define _IO_new_file_close_it _IO_file_close_it
00042 # define _IO_new_file_finish _IO_file_finish
00043 # define _IO_new_file_fopen _IO_file_fopen
00044 # define _IO_new_file_init _IO_file_init
00045 # define _IO_new_file_setbuf _IO_file_setbuf
00046 # define _IO_new_file_sync _IO_file_sync
00047 # define _IO_new_file_overflow _IO_file_overflow
00048 # define _IO_new_file_seekoff _IO_file_seekoff
00049 # define _IO_new_file_underflow _IO_file_underflow
00050 # define _IO_new_file_write _IO_file_write
00051 # define _IO_new_file_xsputn _IO_file_xsputn
00052 #endif
00053 
00054 
00055 /* Convert TO_DO wide character from DATA to FP.
00056    Then mark FP as having empty buffers. */
00057 int
00058 _IO_wdo_write (fp, data, to_do)
00059      _IO_FILE *fp;
00060      const wchar_t *data;
00061      _IO_size_t to_do;
00062 {
00063   struct _IO_codecvt *cc = fp->_codecvt;
00064 
00065   if (to_do > 0)
00066     {
00067       if (fp->_IO_write_end == fp->_IO_write_ptr
00068          && fp->_IO_write_end != fp->_IO_write_base)
00069        {
00070          if (_IO_new_do_write (fp, fp->_IO_write_base,
00071                             fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
00072            return WEOF;
00073        }
00074 
00075       do
00076        {
00077          enum __codecvt_result result;
00078          const wchar_t *new_data;
00079 
00080          /* Now convert from the internal format into the external buffer.  */
00081          result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
00082                                        data, data + to_do, &new_data,
00083                                        fp->_IO_write_ptr,
00084                                        fp->_IO_buf_end,
00085                                        &fp->_IO_write_ptr);
00086 
00087          /* Write out what we produced so far.  */
00088          if (_IO_new_do_write (fp, fp->_IO_write_base,
00089                             fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
00090            /* Something went wrong.  */
00091            return WEOF;
00092 
00093          to_do -= new_data - data;
00094 
00095          /* Next see whether we had problems during the conversion.  If yes,
00096             we cannot go on.  */
00097          if (result != __codecvt_ok
00098              && (result != __codecvt_partial || new_data - data == 0))
00099            break;
00100 
00101          data = new_data;
00102        }
00103       while (to_do > 0);
00104     }
00105 
00106   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
00107             fp->_wide_data->_IO_buf_base);
00108   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
00109     = fp->_wide_data->_IO_buf_base;
00110   fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
00111                                ? fp->_wide_data->_IO_buf_base
00112                                : fp->_wide_data->_IO_buf_end);
00113 
00114   return to_do == 0 ? 0 : WEOF;
00115 }
00116 INTDEF(_IO_wdo_write)
00117 
00118 
00119 wint_t
00120 _IO_wfile_underflow (fp)
00121      _IO_FILE *fp;
00122 {
00123   struct _IO_codecvt *cd;
00124   enum __codecvt_result status;
00125   _IO_ssize_t count;
00126   int tries;
00127   const char *read_ptr_copy;
00128 
00129   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
00130     {
00131       fp->_flags |= _IO_ERR_SEEN;
00132       __set_errno (EBADF);
00133       return WEOF;
00134     }
00135   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
00136     return *fp->_wide_data->_IO_read_ptr;
00137 
00138   cd = fp->_codecvt;
00139 
00140   /* Maybe there is something left in the external buffer.  */
00141   if (fp->_IO_read_ptr < fp->_IO_read_end)
00142     {
00143       /* There is more in the external.  Convert it.  */
00144       const char *read_stop = (const char *) fp->_IO_read_ptr;
00145 
00146       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
00147       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
00148        fp->_wide_data->_IO_buf_base;
00149       status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
00150                                    fp->_IO_read_ptr, fp->_IO_read_end,
00151                                    &read_stop,
00152                                    fp->_wide_data->_IO_read_ptr,
00153                                    fp->_wide_data->_IO_buf_end,
00154                                    &fp->_wide_data->_IO_read_end);
00155 
00156       fp->_IO_read_base = fp->_IO_read_ptr;
00157       fp->_IO_read_ptr = (char *) read_stop;
00158 
00159       /* If we managed to generate some text return the next character.  */
00160       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
00161        return *fp->_wide_data->_IO_read_ptr;
00162 
00163       if (status == __codecvt_error)
00164        {
00165          __set_errno (EILSEQ);
00166          fp->_flags |= _IO_ERR_SEEN;
00167          return WEOF;
00168        }
00169 
00170       /* Move the remaining content of the read buffer to the beginning.  */
00171       memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
00172               fp->_IO_read_end - fp->_IO_read_ptr);
00173       fp->_IO_read_end = (fp->_IO_buf_base
00174                        + (fp->_IO_read_end - fp->_IO_read_ptr));
00175       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
00176     }
00177   else
00178     fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
00179       fp->_IO_buf_base;
00180 
00181   if (fp->_IO_buf_base == NULL)
00182     {
00183       /* Maybe we already have a push back pointer.  */
00184       if (fp->_IO_save_base != NULL)
00185        {
00186          free (fp->_IO_save_base);
00187          fp->_flags &= ~_IO_IN_BACKUP;
00188        }
00189       INTUSE(_IO_doallocbuf) (fp);
00190 
00191       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
00192        fp->_IO_buf_base;
00193     }
00194 
00195   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
00196     fp->_IO_buf_base;
00197 
00198   if (fp->_wide_data->_IO_buf_base == NULL)
00199     {
00200       /* Maybe we already have a push back pointer.  */
00201       if (fp->_wide_data->_IO_save_base != NULL)
00202        {
00203          free (fp->_wide_data->_IO_save_base);
00204          fp->_flags &= ~_IO_IN_BACKUP;
00205        }
00206       INTUSE(_IO_wdoallocbuf) (fp);
00207     }
00208 
00209   /* Flush all line buffered files before reading. */
00210   /* FIXME This can/should be moved to genops ?? */
00211   if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
00212     {
00213 #if 0
00214       INTUSE(_IO_flush_all_linebuffered) ();
00215 #else
00216       /* We used to flush all line-buffered stream.  This really isn't
00217         required by any standard.  My recollection is that
00218         traditional Unix systems did this for stdout.  stderr better
00219         not be line buffered.  So we do just that here
00220         explicitly.  --drepper */
00221       _IO_acquire_lock (_IO_stdout);
00222 
00223       if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
00224          == (_IO_LINKED | _IO_LINE_BUF))
00225        _IO_OVERFLOW (_IO_stdout, EOF);
00226 
00227       _IO_release_lock (_IO_stdout);
00228 #endif
00229     }
00230 
00231   INTUSE(_IO_switch_to_get_mode) (fp);
00232 
00233   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
00234     fp->_wide_data->_IO_buf_base;
00235   fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
00236   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
00237     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
00238 
00239   tries = 0;
00240  again:
00241   count = _IO_SYSREAD (fp, fp->_IO_read_end,
00242                      fp->_IO_buf_end - fp->_IO_read_end);
00243   if (count <= 0)
00244     {
00245       if (count == 0 && tries == 0)
00246        fp->_flags |= _IO_EOF_SEEN;
00247       else
00248        fp->_flags |= _IO_ERR_SEEN, count = 0;
00249     }
00250   fp->_IO_read_end += count;
00251   if (count == 0)
00252     {
00253       if (tries != 0)
00254        /* There are some bytes in the external buffer but they don't
00255            convert to anything.  */
00256        __set_errno (EILSEQ);
00257       return WEOF;
00258     }
00259   if (fp->_offset != _IO_pos_BAD)
00260     _IO_pos_adjust (fp->_offset, count);
00261 
00262   /* Now convert the read input.  */
00263   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
00264   fp->_IO_read_base = fp->_IO_read_ptr;
00265   status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
00266                                fp->_IO_read_ptr, fp->_IO_read_end,
00267                                &read_ptr_copy,
00268                                fp->_wide_data->_IO_read_end,
00269                                fp->_wide_data->_IO_buf_end,
00270                                &fp->_wide_data->_IO_read_end);
00271 
00272   fp->_IO_read_ptr = (char *) read_ptr_copy;
00273   if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
00274     {
00275       if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
00276        {
00277          __set_errno (EILSEQ);
00278          fp->_flags |= _IO_ERR_SEEN;
00279          return WEOF;
00280        }
00281 
00282       /* The read bytes make no complete character.  Try reading again.  */
00283       assert (status == __codecvt_partial);
00284       ++tries;
00285       goto again;
00286     }
00287 
00288   return *fp->_wide_data->_IO_read_ptr;
00289 }
00290 INTDEF(_IO_wfile_underflow)
00291 
00292 
00293 static wint_t
00294 _IO_wfile_underflow_mmap (_IO_FILE *fp)
00295 {
00296   struct _IO_codecvt *cd;
00297   enum __codecvt_result status;
00298   const char *read_stop;
00299 
00300   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
00301     {
00302       fp->_flags |= _IO_ERR_SEEN;
00303       __set_errno (EBADF);
00304       return WEOF;
00305     }
00306   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
00307     return *fp->_wide_data->_IO_read_ptr;
00308 
00309   cd = fp->_codecvt;
00310 
00311   /* Maybe there is something left in the external buffer.  */
00312   if (fp->_IO_read_ptr >= fp->_IO_read_end
00313       /* No.  But maybe the read buffer is not fully set up.  */
00314       && _IO_file_underflow_mmap (fp) == EOF)
00315     /* Nothing available.  _IO_file_underflow_mmap has set the EOF or error
00316        flags as appropriate.  */
00317     return WEOF;
00318 
00319   /* There is more in the external.  Convert it.  */
00320   read_stop = (const char *) fp->_IO_read_ptr;
00321 
00322   if (fp->_wide_data->_IO_buf_base == NULL)
00323     {
00324       /* Maybe we already have a push back pointer.  */
00325       if (fp->_wide_data->_IO_save_base != NULL)
00326        {
00327          free (fp->_wide_data->_IO_save_base);
00328          fp->_flags &= ~_IO_IN_BACKUP;
00329        }
00330       INTUSE(_IO_wdoallocbuf) (fp);
00331     }
00332 
00333   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
00334   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
00335     fp->_wide_data->_IO_buf_base;
00336   status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
00337                                fp->_IO_read_ptr, fp->_IO_read_end,
00338                                &read_stop,
00339                                fp->_wide_data->_IO_read_ptr,
00340                                fp->_wide_data->_IO_buf_end,
00341                                &fp->_wide_data->_IO_read_end);
00342 
00343   fp->_IO_read_ptr = (char *) read_stop;
00344 
00345   /* If we managed to generate some text return the next character.  */
00346   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
00347     return *fp->_wide_data->_IO_read_ptr;
00348 
00349   /* There is some garbage at the end of the file.  */
00350   __set_errno (EILSEQ);
00351   fp->_flags |= _IO_ERR_SEEN;
00352   return WEOF;
00353 }
00354 
00355 static wint_t
00356 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
00357 {
00358   /* This is the first read attempt.  Doing the underflow will choose mmap
00359      or vanilla operations and then punt to the chosen underflow routine.
00360      Then we can punt to ours.  */
00361   if (_IO_file_underflow_maybe_mmap (fp) == EOF)
00362     return WEOF;
00363 
00364   return _IO_WUNDERFLOW (fp);
00365 }
00366 
00367 
00368 wint_t
00369 _IO_wfile_overflow (f, wch)
00370      _IO_FILE *f;
00371      wint_t wch;
00372 {
00373   if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
00374     {
00375       f->_flags |= _IO_ERR_SEEN;
00376       __set_errno (EBADF);
00377       return WEOF;
00378     }
00379   /* If currently reading or no buffer allocated. */
00380   if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
00381     {
00382       /* Allocate a buffer if needed. */
00383       if (f->_wide_data->_IO_write_base == 0)
00384        {
00385          INTUSE(_IO_wdoallocbuf) (f);
00386          _IO_wsetg (f, f->_wide_data->_IO_buf_base,
00387                    f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
00388 
00389          if (f->_IO_write_base == NULL)
00390            {
00391              INTUSE(_IO_doallocbuf) (f);
00392              _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
00393            }
00394        }
00395       else
00396        {
00397          /* Otherwise must be currently reading.  If _IO_read_ptr
00398             (and hence also _IO_read_end) is at the buffer end,
00399             logically slide the buffer forwards one block (by setting
00400             the read pointers to all point at the beginning of the
00401             block).  This makes room for subsequent output.
00402             Otherwise, set the read pointers to _IO_read_end (leaving
00403             that alone, so it can continue to correspond to the
00404             external position). */
00405          if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
00406            {
00407              f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
00408              f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
00409               f->_wide_data->_IO_buf_base;
00410            }
00411        }
00412       f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
00413       f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
00414       f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
00415       f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
00416        f->_wide_data->_IO_read_end;
00417 
00418       f->_IO_write_ptr = f->_IO_read_ptr;
00419       f->_IO_write_base = f->_IO_write_ptr;
00420       f->_IO_write_end = f->_IO_buf_end;
00421       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
00422 
00423       f->_flags |= _IO_CURRENTLY_PUTTING;
00424       if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
00425        f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
00426     }
00427   if (wch == WEOF)
00428     return _IO_do_flush (f);
00429   if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
00430     /* Buffer is really full */
00431     if (_IO_do_flush (f) == EOF)
00432       return WEOF;
00433   *f->_wide_data->_IO_write_ptr++ = wch;
00434   if ((f->_flags & _IO_UNBUFFERED)
00435       || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
00436     if (_IO_do_flush (f) == EOF)
00437       return WEOF;
00438   return wch;
00439 }
00440 INTDEF(_IO_wfile_overflow)
00441 
00442 wint_t
00443 _IO_wfile_sync (fp)
00444      _IO_FILE *fp;
00445 {
00446   _IO_ssize_t delta;
00447   wint_t retval = 0;
00448 
00449   /*    char* ptr = cur_ptr(); */
00450   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
00451     if (_IO_do_flush (fp))
00452       return WEOF;
00453   delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
00454   if (delta != 0)
00455     {
00456       /* We have to find out how many bytes we have to go back in the
00457         external buffer.  */
00458       struct _IO_codecvt *cv = fp->_codecvt;
00459       _IO_off64_t new_pos;
00460 
00461       int clen = (*cv->__codecvt_do_encoding) (cv);
00462 
00463       if (clen > 0)
00464        /* It is easy, a fixed number of input bytes are used for each
00465           wide character.  */
00466        delta *= clen;
00467       else
00468        {
00469          /* We have to find out the hard way how much to back off.
00470              To do this we determine how much input we needed to
00471              generate the wide characters up to the current reading
00472              position.  */
00473          int nread;
00474 
00475          fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
00476          nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
00477                                          fp->_IO_read_base,
00478                                          fp->_IO_read_end, delta);
00479          fp->_IO_read_ptr = fp->_IO_read_base + nread;
00480          delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
00481        }
00482 
00483       new_pos = _IO_SYSSEEK (fp, delta, 1);
00484       if (new_pos != (_IO_off64_t) EOF)
00485        {
00486          fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
00487          fp->_IO_read_end = fp->_IO_read_ptr;
00488        }
00489 #ifdef ESPIPE
00490       else if (errno == ESPIPE)
00491        ; /* Ignore error from unseekable devices. */
00492 #endif
00493       else
00494        retval = WEOF;
00495     }
00496   if (retval != WEOF)
00497     fp->_offset = _IO_pos_BAD;
00498   /* FIXME: Cleanup - can this be shared? */
00499   /*    setg(base(), ptr, ptr); */
00500   return retval;
00501 }
00502 INTDEF(_IO_wfile_sync)
00503 
00504 _IO_off64_t
00505 _IO_wfile_seekoff (fp, offset, dir, mode)
00506      _IO_FILE *fp;
00507      _IO_off64_t offset;
00508      int dir;
00509      int mode;
00510 {
00511   _IO_off64_t result;
00512   _IO_off64_t delta, new_offset;
00513   long int count;
00514   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
00515      offset of the underlying file must be exact.  */
00516   int must_be_exact = ((fp->_wide_data->_IO_read_base
00517                      == fp->_wide_data->_IO_read_end)
00518                      && (fp->_wide_data->_IO_write_base
00519                         == fp->_wide_data->_IO_write_ptr));
00520 
00521   if (mode == 0)
00522     {
00523       /* XXX For wide stream with backup store it is not very
00524         reasonable to determine the offset.  The pushed-back
00525         character might require a state change and we need not be
00526         able to compute the initial state by reverse transformation
00527         since there is no guarantee of symmetry.  So we don't even
00528         try and return an error.  */
00529       if (_IO_in_backup (fp))
00530        {
00531          if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
00532            {
00533              __set_errno (EINVAL);
00534              return -1;
00535            }
00536 
00537          /* There is no more data in the backup buffer.  We can
00538             switch back.  */
00539          INTUSE(_IO_switch_to_main_wget_area) (fp);
00540        }
00541 
00542       dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
00543     }
00544 
00545   /* Flush unwritten characters.
00546      (This may do an unneeded write if we seek within the buffer.
00547      But to be able to switch to reading, we would need to set
00548      egptr to ptr.  That can't be done in the current design,
00549      which assumes file_ptr() is eGptr.  Anyway, since we probably
00550      end up flushing when we close(), it doesn't make much difference.)
00551      FIXME: simulate mem-mapped files. */
00552 
00553   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
00554       || _IO_in_put_mode (fp))
00555     if (INTUSE(_IO_switch_to_wget_mode) (fp))
00556       return WEOF;
00557 
00558   if (fp->_wide_data->_IO_buf_base == NULL)
00559     {
00560       /* It could be that we already have a pushback buffer.  */
00561       if (fp->_wide_data->_IO_read_base != NULL)
00562        {
00563          free (fp->_wide_data->_IO_read_base);
00564          fp->_flags &= ~_IO_IN_BACKUP;
00565        }
00566       INTUSE(_IO_doallocbuf) (fp);
00567       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
00568       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
00569       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
00570                fp->_wide_data->_IO_buf_base);
00571       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
00572                fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
00573     }
00574 
00575   switch (dir)
00576     {
00577       struct _IO_codecvt *cv;
00578       int clen;
00579 
00580     case _IO_seek_cur:
00581       /* Adjust for read-ahead (bytes is buffer).  To do this we must
00582          find out which position in the external buffer corresponds to
00583          the current position in the internal buffer.  */
00584       cv = fp->_codecvt;
00585       clen = (*cv->__codecvt_do_encoding) (cv);
00586 
00587       if (clen > 0)
00588        offset -= (fp->_wide_data->_IO_read_end
00589                  - fp->_wide_data->_IO_read_ptr) * clen;
00590       else
00591        {
00592          int nread;
00593 
00594          delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
00595          fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
00596          nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
00597                                          fp->_IO_read_base,
00598                                          fp->_IO_read_end, delta);
00599          fp->_IO_read_ptr = fp->_IO_read_base + nread;
00600          fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
00601          offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
00602        }
00603 
00604       if (fp->_offset == _IO_pos_BAD)
00605        goto dumb;
00606       /* Make offset absolute, assuming current pointer is file_ptr(). */
00607       offset += fp->_offset;
00608 
00609       dir = _IO_seek_set;
00610       break;
00611     case _IO_seek_set:
00612       break;
00613     case _IO_seek_end:
00614       {
00615        struct _G_stat64 st;
00616        if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
00617          {
00618            offset += st.st_size;
00619            dir = _IO_seek_set;
00620          }
00621        else
00622          goto dumb;
00623       }
00624     }
00625   /* At this point, dir==_IO_seek_set. */
00626 
00627   /* If we are only interested in the current position we've found it now.  */
00628   if (mode == 0)
00629     return offset;
00630 
00631   /* If destination is within current buffer, optimize: */
00632   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
00633       && !_IO_in_backup (fp))
00634     {
00635       /* Offset relative to start of main get area. */
00636       _IO_off64_t rel_offset = (offset - fp->_offset
00637                             + (fp->_IO_read_end - fp->_IO_read_base));
00638       if (rel_offset >= 0)
00639        {
00640 #if 0
00641          if (_IO_in_backup (fp))
00642            _IO_switch_to_main_get_area (fp);
00643 #endif
00644          if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
00645            {
00646              enum __codecvt_result status;
00647              struct _IO_codecvt *cd = fp->_codecvt;
00648              const char *read_ptr_copy;
00649 
00650              fp->_IO_read_ptr = fp->_IO_read_base + rel_offset;
00651              _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
00652 
00653              /* Now set the pointer for the internal buffer.  This
00654                  might be an iterative process.  Though the read
00655                  pointer is somewhere in the current external buffer
00656                  this does not mean we can convert this whole buffer
00657                  at once fitting in the internal buffer.  */
00658              fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
00659              read_ptr_copy = fp->_IO_read_base;
00660              fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
00661              do
00662               {
00663                 wchar_t buffer[1024];
00664                 wchar_t *ignore;
00665                 status = (*cd->__codecvt_do_in) (cd,
00666                                              &fp->_wide_data->_IO_state,
00667                                              read_ptr_copy,
00668                                              fp->_IO_read_ptr,
00669                                              &read_ptr_copy,
00670                                              buffer,
00671                                              buffer
00672                                              + (sizeof (buffer)
00673                                                 / sizeof (buffer[0])),
00674                                              &ignore);
00675                 if (status != __codecvt_ok && status != __codecvt_partial)
00676                   {
00677                     fp->_flags |= _IO_ERR_SEEN;
00678                     goto dumb;
00679                   }
00680               }
00681              while (read_ptr_copy != fp->_IO_read_ptr);
00682 
00683              fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
00684 
00685              _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
00686              goto resync;
00687            }
00688 #ifdef TODO
00689            /* If we have streammarkers, seek forward by reading ahead. */
00690            if (_IO_have_markers (fp))
00691              {
00692               int to_skip = rel_offset
00693                 - (fp->_IO_read_ptr - fp->_IO_read_base);
00694               if (ignore (to_skip) != to_skip)
00695                 goto dumb;
00696               _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
00697               goto resync;
00698              }
00699 #endif
00700        }
00701 #ifdef TODO
00702       if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
00703        {
00704          if (!_IO_in_backup (fp))
00705            _IO_switch_to_backup_area (fp);
00706          gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
00707          _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
00708          goto resync;
00709        }
00710 #endif
00711     }
00712 
00713 #ifdef TODO
00714   INTUSE(_IO_unsave_markers) (fp);
00715 #endif
00716 
00717   if (fp->_flags & _IO_NO_READS)
00718     goto dumb;
00719 
00720   /* Try to seek to a block boundary, to improve kernel page management. */
00721   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
00722   delta = offset - new_offset;
00723   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
00724     {
00725       new_offset = offset;
00726       delta = 0;
00727     }
00728   result = _IO_SYSSEEK (fp, new_offset, 0);
00729   if (result < 0)
00730     return EOF;
00731   if (delta == 0)
00732     count = 0;
00733   else
00734     {
00735       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
00736                         (must_be_exact
00737                          ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
00738       if (count < delta)
00739        {
00740          /* We weren't allowed to read, but try to seek the remainder. */
00741          offset = count == EOF ? delta : delta-count;
00742          dir = _IO_seek_cur;
00743          goto dumb;
00744        }
00745     }
00746   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
00747            fp->_IO_buf_base + count);
00748   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
00749   fp->_offset = result + count;
00750   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
00751   return offset;
00752  dumb:
00753 
00754   INTUSE(_IO_unsave_markers) (fp);
00755   result = _IO_SYSSEEK (fp, offset, dir);
00756   if (result != EOF)
00757     {
00758       _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
00759       fp->_offset = result;
00760       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
00761       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
00762       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
00763                fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
00764       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
00765                fp->_wide_data->_IO_buf_base);
00766     }
00767   return result;
00768 
00769 resync:
00770   /* We need to do it since it is possible that the file offset in
00771      the kernel may be changed behind our back. It may happen when
00772      we fopen a file and then do a fork. One process may access the
00773      the file and the kernel file offset will be changed. */
00774   if (fp->_offset >= 0)
00775     _IO_SYSSEEK (fp, fp->_offset, 0);
00776 
00777   return offset;
00778 }
00779 INTDEF(_IO_wfile_seekoff)
00780 
00781 
00782 _IO_size_t
00783 _IO_wfile_xsputn (f, data, n)
00784      _IO_FILE *f;
00785      const void *data;
00786      _IO_size_t n;
00787 {
00788   register const wchar_t *s = (const wchar_t *) data;
00789   _IO_size_t to_do = n;
00790   int must_flush = 0;
00791   _IO_size_t count;
00792 
00793   if (n <= 0)
00794     return 0;
00795   /* This is an optimized implementation.
00796      If the amount to be written straddles a block boundary
00797      (or the filebuf is unbuffered), use sys_write directly. */
00798 
00799   /* First figure out how much space is available in the buffer. */
00800   count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
00801   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
00802     {
00803       count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
00804       if (count >= n)
00805        {
00806          register const wchar_t *p;
00807          for (p = s + n; p > s; )
00808            {
00809              if (*--p == L'\n')
00810               {
00811                 count = p - s + 1;
00812                 must_flush = 1;
00813                 break;
00814               }
00815            }
00816        }
00817     }
00818   /* Then fill the buffer. */
00819   if (count > 0)
00820     {
00821       if (count > to_do)
00822        count = to_do;
00823       if (count > 20)
00824        {
00825 #ifdef _LIBC
00826          f->_wide_data->_IO_write_ptr =
00827            __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
00828 #else
00829          wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
00830          f->_wide_data->_IO_write_ptr += count;
00831 #endif
00832          s += count;
00833        }
00834       else
00835        {
00836          register wchar_t *p = f->_wide_data->_IO_write_ptr;
00837          register int i = (int) count;
00838          while (--i >= 0)
00839            *p++ = *s++;
00840          f->_wide_data->_IO_write_ptr = p;
00841        }
00842       to_do -= count;
00843     }
00844   if (to_do > 0)
00845     to_do -= INTUSE(_IO_wdefault_xsputn) (f, s, to_do);
00846   if (must_flush
00847       && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
00848     INTUSE(_IO_wdo_write) (f, f->_wide_data->_IO_write_base,
00849                         f->_wide_data->_IO_write_ptr
00850                         - f->_wide_data->_IO_write_base);
00851 
00852   return n - to_do;
00853 }
00854 INTDEF(_IO_wfile_xsputn)
00855 
00856 
00857 const struct _IO_jump_t _IO_wfile_jumps =
00858 {
00859   JUMP_INIT_DUMMY,
00860   JUMP_INIT(finish, _IO_new_file_finish),
00861   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
00862   JUMP_INIT(underflow, (_IO_underflow_t) INTUSE(_IO_wfile_underflow)),
00863   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
00864   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
00865   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
00866   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
00867   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
00868   JUMP_INIT(seekpos, _IO_default_seekpos),
00869   JUMP_INIT(setbuf, _IO_new_file_setbuf),
00870   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
00871   JUMP_INIT(doallocate, _IO_wfile_doallocate),
00872   JUMP_INIT(read, INTUSE(_IO_file_read)),
00873   JUMP_INIT(write, _IO_new_file_write),
00874   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
00875   JUMP_INIT(close, INTUSE(_IO_file_close)),
00876   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
00877   JUMP_INIT(showmanyc, _IO_default_showmanyc),
00878   JUMP_INIT(imbue, _IO_default_imbue)
00879 };
00880 libc_hidden_data_def (_IO_wfile_jumps)
00881 
00882 
00883 const struct _IO_jump_t _IO_wfile_jumps_mmap =
00884 {
00885   JUMP_INIT_DUMMY,
00886   JUMP_INIT(finish, _IO_new_file_finish),
00887   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
00888   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
00889   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
00890   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
00891   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
00892   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
00893   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
00894   JUMP_INIT(seekpos, _IO_default_seekpos),
00895   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
00896   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
00897   JUMP_INIT(doallocate, _IO_wfile_doallocate),
00898   JUMP_INIT(read, INTUSE(_IO_file_read)),
00899   JUMP_INIT(write, _IO_new_file_write),
00900   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
00901   JUMP_INIT(close, _IO_file_close_mmap),
00902   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
00903   JUMP_INIT(showmanyc, _IO_default_showmanyc),
00904   JUMP_INIT(imbue, _IO_default_imbue)
00905 };
00906 
00907 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
00908 {
00909   JUMP_INIT_DUMMY,
00910   JUMP_INIT(finish, _IO_new_file_finish),
00911   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
00912   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
00913   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
00914   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
00915   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
00916   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
00917   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
00918   JUMP_INIT(seekpos, _IO_default_seekpos),
00919   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
00920   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
00921   JUMP_INIT(doallocate, _IO_wfile_doallocate),
00922   JUMP_INIT(read, INTUSE(_IO_file_read)),
00923   JUMP_INIT(write, _IO_new_file_write),
00924   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
00925   JUMP_INIT(close, INTUSE(_IO_file_close)),
00926   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
00927   JUMP_INIT(showmanyc, _IO_default_showmanyc),
00928   JUMP_INIT(imbue, _IO_default_imbue)
00929 };