]> git.ipfire.org Git - thirdparty/glibc.git/blame - libio/wfileops.c
Separate ftell from fseek logic and avoid modifying FILE data (#16532)
[thirdparty/glibc.git] / libio / wfileops.c
CommitLineData
d4697bc9 1/* Copyright (C) 1993-2014 Free Software Foundation, Inc.
41bdb6e2 2 This file is part of the GNU C Library.
d64b6ad0
UD
3 Written by Ulrich Drepper <drepper@cygnus.com>.
4 Based on the single byte version by Per Bothner <bothner@cygnus.com>.
5
41bdb6e2
AJ
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.
d64b6ad0 10
41bdb6e2
AJ
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
d64b6ad0 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
d64b6ad0 15
41bdb6e2 16 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>.
d64b6ad0 19
41bdb6e2
AJ
20 As a special exception, if you link the code in this file with
21 files compiled with a GNU compiler to produce an executable,
22 that does not cause the resulting executable to be covered by
23 the GNU Lesser General Public License. This exception does not
24 however invalidate any other reasons why the executable file
25 might be covered by the GNU Lesser General Public License.
26 This exception applies to code released by its copyright holders
27 in files containing the exception. */
d64b6ad0
UD
28
29#include <assert.h>
30#include <libioP.h>
31#include <wchar.h>
32#include <gconv.h>
33#include <stdlib.h>
34#include <string.h>
35
36
319d719d
UD
37#ifndef _LIBC
38# define _IO_new_do_write _IO_do_write
39# define _IO_new_file_attach _IO_file_attach
40# define _IO_new_file_close_it _IO_file_close_it
41# define _IO_new_file_finish _IO_file_finish
42# define _IO_new_file_fopen _IO_file_fopen
43# define _IO_new_file_init _IO_file_init
44# define _IO_new_file_setbuf _IO_file_setbuf
45# define _IO_new_file_sync _IO_file_sync
46# define _IO_new_file_overflow _IO_file_overflow
47# define _IO_new_file_seekoff _IO_file_seekoff
48# define _IO_new_file_underflow _IO_file_underflow
49# define _IO_new_file_write _IO_file_write
50# define _IO_new_file_xsputn _IO_file_xsputn
51#endif
52
53
d64b6ad0
UD
54/* Convert TO_DO wide character from DATA to FP.
55 Then mark FP as having empty buffers. */
56int
57_IO_wdo_write (fp, data, to_do)
58 _IO_FILE *fp;
59 const wchar_t *data;
60 _IO_size_t to_do;
61{
cd8b7ff9 62 struct _IO_codecvt *cc = fp->_codecvt;
d64b6ad0 63
9494452c 64 if (to_do > 0)
d64b6ad0 65 {
9c38a689
UD
66 if (fp->_IO_write_end == fp->_IO_write_ptr
67 && fp->_IO_write_end != fp->_IO_write_base)
d64b6ad0 68 {
9494452c
UD
69 if (_IO_new_do_write (fp, fp->_IO_write_base,
70 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
f3495a08 71 return WEOF;
d64b6ad0
UD
72 }
73
9494452c
UD
74 do
75 {
76 enum __codecvt_result result;
77 const wchar_t *new_data;
78
79 /* Now convert from the internal format into the external buffer. */
80 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
81 data, data + to_do, &new_data,
82 fp->_IO_write_ptr,
83 fp->_IO_buf_end,
84 &fp->_IO_write_ptr);
85
86 /* Write out what we produced so far. */
87 if (_IO_new_do_write (fp, fp->_IO_write_base,
88 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
89 /* Something went wrong. */
2fdeb7ca 90 return WEOF;
9494452c 91
9494452c
UD
92 to_do -= new_data - data;
93
94 /* Next see whether we had problems during the conversion. If yes,
95 we cannot go on. */
96 if (result != __codecvt_ok
97 && (result != __codecvt_partial || new_data - data == 0))
98 break;
99
100 data = new_data;
101 }
102 while (to_do > 0);
d64b6ad0
UD
103 }
104
105 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
106 fp->_wide_data->_IO_buf_base);
107 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
108 = fp->_wide_data->_IO_buf_base;
109 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
110 ? fp->_wide_data->_IO_buf_base
111 : fp->_wide_data->_IO_buf_end);
112
11fd973a 113 return to_do == 0 ? 0 : WEOF;
d64b6ad0 114}
d18ea0c5 115libc_hidden_def (_IO_wdo_write)
d64b6ad0
UD
116
117
118wint_t
119_IO_wfile_underflow (fp)
120 _IO_FILE *fp;
121{
122 struct _IO_codecvt *cd;
123 enum __codecvt_result status;
124 _IO_ssize_t count;
d64b6ad0 125
a1ffb40e 126 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
d64b6ad0 127 {
58034572 128 fp->_flags |= _IO_ERR_SEEN;
d64b6ad0
UD
129 __set_errno (EBADF);
130 return WEOF;
131 }
132 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
133 return *fp->_wide_data->_IO_read_ptr;
134
cd8b7ff9 135 cd = fp->_codecvt;
d64b6ad0
UD
136
137 /* Maybe there is something left in the external buffer. */
138 if (fp->_IO_read_ptr < fp->_IO_read_end)
139 {
5e473a71
UD
140 /* There is more in the external. Convert it. */
141 const char *read_stop = (const char *) fp->_IO_read_ptr;
d64b6ad0 142
5e473a71 143 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
0469311e
UD
144 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
145 fp->_wide_data->_IO_buf_base;
5e473a71
UD
146 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
147 fp->_IO_read_ptr, fp->_IO_read_end,
148 &read_stop,
0469311e 149 fp->_wide_data->_IO_read_ptr,
5e473a71
UD
150 fp->_wide_data->_IO_buf_end,
151 &fp->_wide_data->_IO_read_end);
152
eb35b097 153 fp->_IO_read_base = fp->_IO_read_ptr;
5e473a71
UD
154 fp->_IO_read_ptr = (char *) read_stop;
155
156 /* If we managed to generate some text return the next character. */
157 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
158 return *fp->_wide_data->_IO_read_ptr;
159
160 if (status == __codecvt_error)
d64b6ad0 161 {
5e473a71
UD
162 __set_errno (EILSEQ);
163 fp->_flags |= _IO_ERR_SEEN;
164 return WEOF;
d64b6ad0
UD
165 }
166
167 /* Move the remaining content of the read buffer to the beginning. */
168 memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
169 fp->_IO_read_end - fp->_IO_read_ptr);
170 fp->_IO_read_end = (fp->_IO_buf_base
171 + (fp->_IO_read_end - fp->_IO_read_ptr));
172 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
173 }
174 else
175 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
176 fp->_IO_buf_base;
177
d64b6ad0
UD
178 if (fp->_IO_buf_base == NULL)
179 {
180 /* Maybe we already have a push back pointer. */
181 if (fp->_IO_save_base != NULL)
182 {
183 free (fp->_IO_save_base);
184 fp->_flags &= ~_IO_IN_BACKUP;
185 }
d18ea0c5 186 _IO_doallocbuf (fp);
a756bab8
UD
187
188 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
189 fp->_IO_buf_base;
d64b6ad0
UD
190 }
191
a756bab8
UD
192 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
193 fp->_IO_buf_base;
194
d64b6ad0
UD
195 if (fp->_wide_data->_IO_buf_base == NULL)
196 {
197 /* Maybe we already have a push back pointer. */
198 if (fp->_wide_data->_IO_save_base != NULL)
199 {
200 free (fp->_wide_data->_IO_save_base);
201 fp->_flags &= ~_IO_IN_BACKUP;
202 }
d18ea0c5 203 _IO_wdoallocbuf (fp);
d64b6ad0
UD
204 }
205
206 /* Flush all line buffered files before reading. */
207 /* FIXME This can/should be moved to genops ?? */
208 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
3d759cb8
UD
209 {
210#if 0
d18ea0c5 211 _IO_flush_all_linebuffered ();
3d759cb8
UD
212#else
213 /* We used to flush all line-buffered stream. This really isn't
214 required by any standard. My recollection is that
215 traditional Unix systems did this for stdout. stderr better
216 not be line buffered. So we do just that here
217 explicitly. --drepper */
0261d33f 218 _IO_acquire_lock (_IO_stdout);
3d759cb8
UD
219
220 if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
221 == (_IO_LINKED | _IO_LINE_BUF))
222 _IO_OVERFLOW (_IO_stdout, EOF);
223
0261d33f 224 _IO_release_lock (_IO_stdout);
3d759cb8
UD
225#endif
226 }
d64b6ad0 227
d18ea0c5 228 _IO_switch_to_get_mode (fp);
d64b6ad0 229
d64b6ad0
UD
230 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
231 fp->_wide_data->_IO_buf_base;
232 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
233 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
234 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
235
82f2e9c6
UD
236 const char *read_ptr_copy;
237 char accbuf[MB_LEN_MAX];
238 size_t naccbuf = 0;
d64b6ad0
UD
239 again:
240 count = _IO_SYSREAD (fp, fp->_IO_read_end,
241 fp->_IO_buf_end - fp->_IO_read_end);
242 if (count <= 0)
243 {
82f2e9c6 244 if (count == 0 && naccbuf == 0)
d64b6ad0
UD
245 fp->_flags |= _IO_EOF_SEEN;
246 else
247 fp->_flags |= _IO_ERR_SEEN, count = 0;
248 }
249 fp->_IO_read_end += count;
250 if (count == 0)
251 {
82f2e9c6 252 if (naccbuf != 0)
d64b6ad0 253 /* There are some bytes in the external buffer but they don't
aaddc98c 254 convert to anything. */
d64b6ad0
UD
255 __set_errno (EILSEQ);
256 return WEOF;
257 }
258 if (fp->_offset != _IO_pos_BAD)
259 _IO_pos_adjust (fp->_offset, count);
260
261 /* Now convert the read input. */
262 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
263 fp->_IO_read_base = fp->_IO_read_ptr;
82f2e9c6
UD
264 const char *from = fp->_IO_read_ptr;
265 const char *to = fp->_IO_read_end;
266 size_t to_copy = count;
a1ffb40e 267 if (__glibc_unlikely (naccbuf != 0))
82f2e9c6
UD
268 {
269 to_copy = MIN (sizeof (accbuf) - naccbuf, count);
270 to = __mempcpy (&accbuf[naccbuf], from, to_copy);
271 naccbuf += to_copy;
272 from = accbuf;
273 }
d64b6ad0 274 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
82f2e9c6 275 from, to, &read_ptr_copy,
d64b6ad0
UD
276 fp->_wide_data->_IO_read_end,
277 fp->_wide_data->_IO_buf_end,
278 &fp->_wide_data->_IO_read_end);
279
a1ffb40e 280 if (__glibc_unlikely (naccbuf != 0))
82f2e9c6
UD
281 fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
282 else
283 fp->_IO_read_ptr = (char *) read_ptr_copy;
d64b6ad0
UD
284 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
285 {
82f2e9c6 286 if (status == __codecvt_error)
d64b6ad0 287 {
82f2e9c6 288 out_eilseq:
d64b6ad0
UD
289 __set_errno (EILSEQ);
290 fp->_flags |= _IO_ERR_SEEN;
291 return WEOF;
292 }
293
294 /* The read bytes make no complete character. Try reading again. */
295 assert (status == __codecvt_partial);
82f2e9c6
UD
296
297 if (naccbuf == 0)
298 {
a71433e7
UD
299 if (fp->_IO_read_base < fp->_IO_read_ptr)
300 {
301 /* Partially used the buffer for some input data that
302 produces no output. */
303 size_t avail = fp->_IO_read_end - fp->_IO_read_ptr;
304 memmove (fp->_IO_read_base, fp->_IO_read_ptr, avail);
305 fp->_IO_read_ptr = fp->_IO_read_base;
306 fp->_IO_read_end -= avail;
307 goto again;
308 }
82f2e9c6
UD
309 naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
310 if (naccbuf >= sizeof (accbuf))
311 goto out_eilseq;
312
313 memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
314 }
a71433e7
UD
315 else
316 {
317 size_t used = read_ptr_copy - accbuf;
318 if (used > 0)
319 {
320 memmove (accbuf, read_ptr_copy, naccbuf - used);
321 naccbuf -= used;
322 }
323
324 if (naccbuf == sizeof (accbuf))
325 goto out_eilseq;
326 }
82f2e9c6
UD
327
328 fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
329
d64b6ad0
UD
330 goto again;
331 }
332
333 return *fp->_wide_data->_IO_read_ptr;
334}
d18ea0c5 335libc_hidden_def (_IO_wfile_underflow)
d64b6ad0
UD
336
337
0469311e
UD
338static wint_t
339_IO_wfile_underflow_mmap (_IO_FILE *fp)
340{
341 struct _IO_codecvt *cd;
284749da 342 const char *read_stop;
0469311e 343
a1ffb40e 344 if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
0469311e
UD
345 {
346 fp->_flags |= _IO_ERR_SEEN;
347 __set_errno (EBADF);
348 return WEOF;
349 }
350 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
351 return *fp->_wide_data->_IO_read_ptr;
352
353 cd = fp->_codecvt;
354
355 /* Maybe there is something left in the external buffer. */
284749da
UD
356 if (fp->_IO_read_ptr >= fp->_IO_read_end
357 /* No. But maybe the read buffer is not fully set up. */
358 && _IO_file_underflow_mmap (fp) == EOF)
acbee5f6
RM
359 /* Nothing available. _IO_file_underflow_mmap has set the EOF or error
360 flags as appropriate. */
361 return WEOF;
284749da
UD
362
363 /* There is more in the external. Convert it. */
364 read_stop = (const char *) fp->_IO_read_ptr;
0469311e 365
284749da
UD
366 if (fp->_wide_data->_IO_buf_base == NULL)
367 {
368 /* Maybe we already have a push back pointer. */
369 if (fp->_wide_data->_IO_save_base != NULL)
0469311e 370 {
284749da
UD
371 free (fp->_wide_data->_IO_save_base);
372 fp->_flags &= ~_IO_IN_BACKUP;
0469311e 373 }
d18ea0c5 374 _IO_wdoallocbuf (fp);
284749da 375 }
0469311e 376
284749da
UD
377 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
378 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
379 fp->_wide_data->_IO_buf_base;
aaddc98c
MP
380 (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
381 fp->_IO_read_ptr, fp->_IO_read_end,
382 &read_stop,
383 fp->_wide_data->_IO_read_ptr,
384 fp->_wide_data->_IO_buf_end,
385 &fp->_wide_data->_IO_read_end);
0469311e 386
284749da 387 fp->_IO_read_ptr = (char *) read_stop;
0469311e 388
284749da
UD
389 /* If we managed to generate some text return the next character. */
390 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
391 return *fp->_wide_data->_IO_read_ptr;
0469311e 392
284749da
UD
393 /* There is some garbage at the end of the file. */
394 __set_errno (EILSEQ);
395 fp->_flags |= _IO_ERR_SEEN;
0469311e
UD
396 return WEOF;
397}
398
acbee5f6
RM
399static wint_t
400_IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
401{
402 /* This is the first read attempt. Doing the underflow will choose mmap
403 or vanilla operations and then punt to the chosen underflow routine.
404 Then we can punt to ours. */
405 if (_IO_file_underflow_maybe_mmap (fp) == EOF)
406 return WEOF;
407
408 return _IO_WUNDERFLOW (fp);
409}
410
0469311e 411
d64b6ad0
UD
412wint_t
413_IO_wfile_overflow (f, wch)
414 _IO_FILE *f;
415 wint_t wch;
416{
417 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
418 {
419 f->_flags |= _IO_ERR_SEEN;
420 __set_errno (EBADF);
421 return WEOF;
422 }
423 /* If currently reading or no buffer allocated. */
424 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
425 {
426 /* Allocate a buffer if needed. */
427 if (f->_wide_data->_IO_write_base == 0)
428 {
d18ea0c5 429 _IO_wdoallocbuf (f);
d64b6ad0
UD
430 _IO_wsetg (f, f->_wide_data->_IO_buf_base,
431 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
9c38a689
UD
432
433 if (f->_IO_write_base == NULL)
434 {
d18ea0c5 435 _IO_doallocbuf (f);
9c38a689
UD
436 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
437 }
d64b6ad0
UD
438 }
439 else
440 {
441 /* Otherwise must be currently reading. If _IO_read_ptr
442 (and hence also _IO_read_end) is at the buffer end,
443 logically slide the buffer forwards one block (by setting
444 the read pointers to all point at the beginning of the
445 block). This makes room for subsequent output.
446 Otherwise, set the read pointers to _IO_read_end (leaving
447 that alone, so it can continue to correspond to the
448 external position). */
449 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
450 {
451 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
452 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
453 f->_wide_data->_IO_buf_base;
454 }
455 }
456 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
457 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
458 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
459 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
460 f->_wide_data->_IO_read_end;
461
9c38a689
UD
462 f->_IO_write_ptr = f->_IO_read_ptr;
463 f->_IO_write_base = f->_IO_write_ptr;
464 f->_IO_write_end = f->_IO_buf_end;
465 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
466
d64b6ad0
UD
467 f->_flags |= _IO_CURRENTLY_PUTTING;
468 if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
469 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
470 }
471 if (wch == WEOF)
472 return _IO_do_flush (f);
9c38a689 473 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
d64b6ad0 474 /* Buffer is really full */
6dd67bd5 475 if (_IO_do_flush (f) == EOF)
d64b6ad0
UD
476 return WEOF;
477 *f->_wide_data->_IO_write_ptr++ = wch;
478 if ((f->_flags & _IO_UNBUFFERED)
479 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
6dd67bd5 480 if (_IO_do_flush (f) == EOF)
d64b6ad0
UD
481 return WEOF;
482 return wch;
483}
d18ea0c5 484libc_hidden_def (_IO_wfile_overflow)
d64b6ad0
UD
485
486wint_t
487_IO_wfile_sync (fp)
488 _IO_FILE *fp;
489{
490 _IO_ssize_t delta;
491 wint_t retval = 0;
492
493 /* char* ptr = cur_ptr(); */
494 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
495 if (_IO_do_flush (fp))
496 return WEOF;
497 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
498 if (delta != 0)
499 {
500 /* We have to find out how many bytes we have to go back in the
501 external buffer. */
cd8b7ff9 502 struct _IO_codecvt *cv = fp->_codecvt;
d64b6ad0
UD
503 _IO_off64_t new_pos;
504
505 int clen = (*cv->__codecvt_do_encoding) (cv);
506
507 if (clen > 0)
508 /* It is easy, a fixed number of input bytes are used for each
509 wide character. */
510 delta *= clen;
511 else
512 {
513 /* We have to find out the hard way how much to back off.
aaddc98c
MP
514 To do this we determine how much input we needed to
515 generate the wide characters up to the current reading
516 position. */
d64b6ad0
UD
517 int nread;
518
519 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
520 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
521 fp->_IO_read_base,
522 fp->_IO_read_end, delta);
523 fp->_IO_read_ptr = fp->_IO_read_base + nread;
524 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
525 }
526
527 new_pos = _IO_SYSSEEK (fp, delta, 1);
528 if (new_pos != (_IO_off64_t) EOF)
529 {
530 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
531 fp->_IO_read_end = fp->_IO_read_ptr;
532 }
533#ifdef ESPIPE
534 else if (errno == ESPIPE)
535 ; /* Ignore error from unseekable devices. */
536#endif
537 else
538 retval = WEOF;
539 }
540 if (retval != WEOF)
541 fp->_offset = _IO_pos_BAD;
542 /* FIXME: Cleanup - can this be shared? */
543 /* setg(base(), ptr, ptr); */
544 return retval;
545}
d18ea0c5 546libc_hidden_def (_IO_wfile_sync)
d64b6ad0 547
4573c6b0
SP
548/* Adjust the internal buffer pointers to reflect the state in the external
549 buffer. The content between fp->_IO_read_base and fp->_IO_read_ptr is
550 assumed to be converted and available in the range
551 fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end.
552
553 Returns 0 on success and -1 on error with the _IO_ERR_SEEN flag set. */
f1d70dad 554static int
4573c6b0
SP
555adjust_wide_data (_IO_FILE *fp, bool do_convert)
556{
557 struct _IO_codecvt *cv = fp->_codecvt;
558
559 int clen = (*cv->__codecvt_do_encoding) (cv);
560
561 /* Take the easy way out for constant length encodings if we don't need to
562 convert. */
563 if (!do_convert && clen > 0)
564 {
565 fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
566 / clen);
567 goto done;
568 }
569
570 enum __codecvt_result status;
571 const char *read_stop = (const char *) fp->_IO_read_base;
572 do
573 {
574
575 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
576 status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
577 fp->_IO_read_base, fp->_IO_read_ptr,
578 &read_stop,
579 fp->_wide_data->_IO_read_base,
580 fp->_wide_data->_IO_buf_end,
581 &fp->_wide_data->_IO_read_end);
582
583 /* Should we return EILSEQ? */
a1ffb40e 584 if (__glibc_unlikely (status == __codecvt_error))
4573c6b0
SP
585 {
586 fp->_flags |= _IO_ERR_SEEN;
587 return -1;
588 }
589 }
590 while (__builtin_expect (status == __codecvt_partial, 0));
591
592done:
593 /* Now seek to _IO_read_end to behave as if we have read it all in. */
594 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
595
596 return 0;
597}
598
000232b9
SP
599/* ftell{,o} implementation for wide mode. Don't modify any state of the file
600 pointer while we try to get the current state of the stream. */
601static _IO_off64_t
602do_ftell_wide (_IO_FILE *fp)
d64b6ad0 603{
000232b9 604 _IO_off64_t result, offset = 0;
adb26fae 605
000232b9
SP
606 /* No point looking for offsets in the buffer if it hasn't even been
607 allocated. */
608 if (fp->_wide_data->_IO_buf_base != NULL)
40a982a9 609 {
000232b9
SP
610 const wchar_t *wide_read_base;
611 const wchar_t *wide_read_ptr;
612 const wchar_t *wide_read_end;
613 bool was_writing = ((fp->_wide_data->_IO_write_ptr
614 > fp->_wide_data->_IO_write_base)
615 || _IO_in_put_mode (fp));
616
40a982a9
UD
617 /* XXX For wide stream with backup store it is not very
618 reasonable to determine the offset. The pushed-back
619 character might require a state change and we need not be
620 able to compute the initial state by reverse transformation
621 since there is no guarantee of symmetry. So we don't even
622 try and return an error. */
623 if (_IO_in_backup (fp))
624 {
625 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
626 {
627 __set_errno (EINVAL);
628 return -1;
629 }
630
000232b9
SP
631 /* Nothing in the backup store, so note the backed up pointers
632 without changing the state. */
633 wide_read_base = fp->_wide_data->_IO_save_base;
634 wide_read_ptr = wide_read_base;
635 wide_read_end = fp->_wide_data->_IO_save_end;
636 }
637 else
638 {
639 wide_read_base = fp->_wide_data->_IO_read_base;
640 wide_read_ptr = fp->_wide_data->_IO_read_ptr;
641 wide_read_end = fp->_wide_data->_IO_read_end;
40a982a9
UD
642 }
643
000232b9
SP
644 struct _IO_codecvt *cv = fp->_codecvt;
645 int clen = (*cv->__codecvt_do_encoding) (cv);
646
647 if (!was_writing)
648 {
649 if (clen > 0)
650 {
651 offset -= (wide_read_end - wide_read_ptr) * clen;
652 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
653 }
654 else
655 {
656 int nread;
657
658 size_t delta = wide_read_ptr - wide_read_base;
659 __mbstate_t state = fp->_wide_data->_IO_last_state;
660 nread = (*cv->__codecvt_do_length) (cv, &state,
661 fp->_IO_read_base,
662 fp->_IO_read_end, delta);
663 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
664 }
665 }
666 else
667 {
668 if (clen > 0)
669 offset += (fp->_wide_data->_IO_write_ptr
670 - fp->_wide_data->_IO_write_base) * clen;
671 else
672 {
673 size_t delta = (fp->_wide_data->_IO_write_ptr
674 - fp->_wide_data->_IO_write_base);
675
676 /* Allocate enough space for the conversion. */
677 size_t outsize = delta * sizeof (wchar_t);
678 char *out = malloc (outsize);
679 char *outstop = out;
680 const wchar_t *in = fp->_wide_data->_IO_write_base;
681
682 enum __codecvt_result status;
683
684 __mbstate_t state = fp->_wide_data->_IO_last_state;
685 status = (*cv->__codecvt_do_out) (cv, &state,
686 in, in + delta, &in,
687 out, out + outsize, &outstop);
688
689 /* We don't check for __codecvt_partial because it can be
690 returned on one of two conditions: either the output
691 buffer is full or the input sequence is incomplete. We
692 take care to allocate enough buffer and our input
693 sequences must be complete since they are accepted as
694 wchar_t; if not, then that is an error. */
695 if (__glibc_unlikely (status != __codecvt_ok))
696 return WEOF;
697
698 offset += outstop - out;
699 }
700
701 /* _IO_read_end coincides with fp._offset, so the actual file position
702 is fp._offset - (_IO_read_end - new_write_ptr). */
703 offset -= fp->_IO_read_end - fp->_IO_write_ptr;
704 }
40a982a9 705 }
d64b6ad0 706
000232b9
SP
707 result = get_file_offset (fp);
708
709 if (result == EOF)
710 return result;
711
712 result += offset;
713
714 return result;
715}
716
717_IO_off64_t
718_IO_wfile_seekoff (fp, offset, dir, mode)
719 _IO_FILE *fp;
720 _IO_off64_t offset;
721 int dir;
722 int mode;
723{
724 _IO_off64_t result;
725 _IO_off64_t delta, new_offset;
726 long int count;
727
728 /* Short-circuit into a separate function. We don't want to mix any
729 functionality and we don't want to touch anything inside the FILE
730 object. */
731 if (mode == 0)
732 return do_ftell_wide (fp);
733
734 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
735 offset of the underlying file must be exact. */
736 int must_be_exact = ((fp->_wide_data->_IO_read_base
737 == fp->_wide_data->_IO_read_end)
738 && (fp->_wide_data->_IO_write_base
739 == fp->_wide_data->_IO_write_ptr));
740
741 bool was_writing = ((fp->_wide_data->_IO_write_ptr
742 > fp->_wide_data->_IO_write_base)
743 || _IO_in_put_mode (fp));
744
d64b6ad0
UD
745 /* Flush unwritten characters.
746 (This may do an unneeded write if we seek within the buffer.
747 But to be able to switch to reading, we would need to set
1ffb8c90 748 egptr to pptr. That can't be done in the current design,
d64b6ad0
UD
749 which assumes file_ptr() is eGptr. Anyway, since we probably
750 end up flushing when we close(), it doesn't make much difference.)
40a982a9 751 FIXME: simulate mem-mapped files. */
000232b9 752 if (was_writing && _IO_switch_to_wget_mode (fp))
adb26fae 753 return WEOF;
d64b6ad0
UD
754
755 if (fp->_wide_data->_IO_buf_base == NULL)
756 {
757 /* It could be that we already have a pushback buffer. */
758 if (fp->_wide_data->_IO_read_base != NULL)
759 {
760 free (fp->_wide_data->_IO_read_base);
761 fp->_flags &= ~_IO_IN_BACKUP;
762 }
d18ea0c5 763 _IO_doallocbuf (fp);
d64b6ad0
UD
764 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
765 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
766 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
767 fp->_wide_data->_IO_buf_base);
768 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
769 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
770 }
771
772 switch (dir)
773 {
774 struct _IO_codecvt *cv;
775 int clen;
776
777 case _IO_seek_cur:
778 /* Adjust for read-ahead (bytes is buffer). To do this we must
aaddc98c
MP
779 find out which position in the external buffer corresponds to
780 the current position in the internal buffer. */
cd8b7ff9 781 cv = fp->_codecvt;
d64b6ad0
UD
782 clen = (*cv->__codecvt_do_encoding) (cv);
783
adb26fae 784 if (mode != 0 || !was_writing)
5d2e6976 785 {
adb26fae
SP
786 if (clen > 0)
787 {
788 offset -= (fp->_wide_data->_IO_read_end
789 - fp->_wide_data->_IO_read_ptr) * clen;
790 /* Adjust by readahead in external buffer. */
791 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
792 }
793 else
794 {
795 int nread;
796
adb26fae
SP
797 delta = (fp->_wide_data->_IO_read_ptr
798 - fp->_wide_data->_IO_read_base);
799 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
800 nread = (*cv->__codecvt_do_length) (cv,
801 &fp->_wide_data->_IO_state,
802 fp->_IO_read_base,
803 fp->_IO_read_end, delta);
804 fp->_IO_read_ptr = fp->_IO_read_base + nread;
805 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
806 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
807 }
5d2e6976 808 }
d64b6ad0
UD
809
810 if (fp->_offset == _IO_pos_BAD)
000232b9 811 goto dumb;
adb26fae 812
d64b6ad0
UD
813 /* Make offset absolute, assuming current pointer is file_ptr(). */
814 offset += fp->_offset;
815
816 dir = _IO_seek_set;
817 break;
818 case _IO_seek_set:
819 break;
820 case _IO_seek_end:
821 {
c8450f70 822 struct stat64 st;
d64b6ad0
UD
823 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
824 {
825 offset += st.st_size;
826 dir = _IO_seek_set;
827 }
828 else
829 goto dumb;
830 }
831 }
832 /* At this point, dir==_IO_seek_set. */
833
d64b6ad0
UD
834 /* If destination is within current buffer, optimize: */
835 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
836 && !_IO_in_backup (fp))
837 {
d840539e
AS
838 _IO_off64_t start_offset = (fp->_offset
839 - (fp->_IO_read_end - fp->_IO_buf_base));
840 if (offset >= start_offset && offset < fp->_offset)
d64b6ad0 841 {
d840539e
AS
842 _IO_setg (fp, fp->_IO_buf_base,
843 fp->_IO_buf_base + (offset - start_offset),
844 fp->_IO_read_end);
845 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
5d2e6976
AS
846 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
847 fp->_wide_data->_IO_buf_base,
848 fp->_wide_data->_IO_buf_base);
849 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
850 fp->_wide_data->_IO_buf_base);
4573c6b0
SP
851
852 if (adjust_wide_data (fp, false))
853 goto dumb;
854
d64b6ad0
UD
855 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
856 goto resync;
857 }
d64b6ad0
UD
858 }
859
d64b6ad0
UD
860 if (fp->_flags & _IO_NO_READS)
861 goto dumb;
862
863 /* Try to seek to a block boundary, to improve kernel page management. */
864 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
865 delta = offset - new_offset;
866 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
867 {
868 new_offset = offset;
869 delta = 0;
870 }
871 result = _IO_SYSSEEK (fp, new_offset, 0);
872 if (result < 0)
873 return EOF;
874 if (delta == 0)
875 count = 0;
876 else
877 {
878 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
879 (must_be_exact
880 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
881 if (count < delta)
882 {
883 /* We weren't allowed to read, but try to seek the remainder. */
884 offset = count == EOF ? delta : delta-count;
885 dir = _IO_seek_cur;
886 goto dumb;
887 }
888 }
889 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
890 fp->_IO_buf_base + count);
891 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
5d2e6976
AS
892 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
893 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
894 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
4573c6b0
SP
895
896 if (adjust_wide_data (fp, true))
897 goto dumb;
898
d64b6ad0
UD
899 fp->_offset = result + count;
900 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
901 return offset;
902 dumb:
903
d18ea0c5 904 _IO_unsave_markers (fp);
d64b6ad0
UD
905 result = _IO_SYSSEEK (fp, offset, dir);
906 if (result != EOF)
907 {
908 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
909 fp->_offset = result;
910 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
911 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
40a982a9
UD
912 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
913 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
914 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
915 fp->_wide_data->_IO_buf_base);
d64b6ad0
UD
916 }
917 return result;
918
919resync:
920 /* We need to do it since it is possible that the file offset in
921 the kernel may be changed behind our back. It may happen when
922 we fopen a file and then do a fork. One process may access the
ded5b9b7 923 file and the kernel file offset will be changed. */
d64b6ad0
UD
924 if (fp->_offset >= 0)
925 _IO_SYSSEEK (fp, fp->_offset, 0);
926
927 return offset;
928}
d18ea0c5 929libc_hidden_def (_IO_wfile_seekoff)
d64b6ad0
UD
930
931
932_IO_size_t
933_IO_wfile_xsputn (f, data, n)
934 _IO_FILE *f;
935 const void *data;
936 _IO_size_t n;
937{
2e09a79a 938 const wchar_t *s = (const wchar_t *) data;
d64b6ad0
UD
939 _IO_size_t to_do = n;
940 int must_flush = 0;
941 _IO_size_t count;
942
943 if (n <= 0)
944 return 0;
945 /* This is an optimized implementation.
946 If the amount to be written straddles a block boundary
947 (or the filebuf is unbuffered), use sys_write directly. */
948
949 /* First figure out how much space is available in the buffer. */
950 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
951 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
952 {
953 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
954 if (count >= n)
955 {
2e09a79a 956 const wchar_t *p;
d64b6ad0
UD
957 for (p = s + n; p > s; )
958 {
959 if (*--p == L'\n')
960 {
961 count = p - s + 1;
962 must_flush = 1;
963 break;
964 }
965 }
966 }
967 }
968 /* Then fill the buffer. */
969 if (count > 0)
970 {
971 if (count > to_do)
972 count = to_do;
973 if (count > 20)
974 {
975#ifdef _LIBC
976 f->_wide_data->_IO_write_ptr =
977 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
978#else
979 wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
980 f->_wide_data->_IO_write_ptr += count;
981#endif
982 s += count;
983 }
984 else
985 {
2e09a79a
JM
986 wchar_t *p = f->_wide_data->_IO_write_ptr;
987 int i = (int) count;
d64b6ad0
UD
988 while (--i >= 0)
989 *p++ = *s++;
990 f->_wide_data->_IO_write_ptr = p;
991 }
992 to_do -= count;
993 }
994 if (to_do > 0)
d18ea0c5 995 to_do -= _IO_wdefault_xsputn (f, s, to_do);
d64b6ad0
UD
996 if (must_flush
997 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
d18ea0c5
AS
998 _IO_wdo_write (f, f->_wide_data->_IO_write_base,
999 f->_wide_data->_IO_write_ptr
1000 - f->_wide_data->_IO_write_base);
d64b6ad0
UD
1001
1002 return n - to_do;
1003}
d18ea0c5 1004libc_hidden_def (_IO_wfile_xsputn)
d64b6ad0
UD
1005
1006
b2637a22 1007const struct _IO_jump_t _IO_wfile_jumps =
d64b6ad0
UD
1008{
1009 JUMP_INIT_DUMMY,
1010 JUMP_INIT(finish, _IO_new_file_finish),
d18ea0c5
AS
1011 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1012 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
1013 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1014 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1015 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1016 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1017 JUMP_INIT(seekoff, _IO_wfile_seekoff),
d64b6ad0
UD
1018 JUMP_INIT(seekpos, _IO_default_seekpos),
1019 JUMP_INIT(setbuf, _IO_new_file_setbuf),
d18ea0c5 1020 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
d64b6ad0 1021 JUMP_INIT(doallocate, _IO_wfile_doallocate),
d18ea0c5 1022 JUMP_INIT(read, _IO_file_read),
d64b6ad0 1023 JUMP_INIT(write, _IO_new_file_write),
d18ea0c5
AS
1024 JUMP_INIT(seek, _IO_file_seek),
1025 JUMP_INIT(close, _IO_file_close),
1026 JUMP_INIT(stat, _IO_file_stat),
d64b6ad0
UD
1027 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1028 JUMP_INIT(imbue, _IO_default_imbue)
1029};
15a686af 1030libc_hidden_data_def (_IO_wfile_jumps)
0469311e
UD
1031
1032
b2637a22 1033const struct _IO_jump_t _IO_wfile_jumps_mmap =
0469311e
UD
1034{
1035 JUMP_INIT_DUMMY,
1036 JUMP_INIT(finish, _IO_new_file_finish),
d18ea0c5 1037 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
0469311e 1038 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
d18ea0c5
AS
1039 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1040 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1041 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1042 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1043 JUMP_INIT(seekoff, _IO_wfile_seekoff),
0469311e 1044 JUMP_INIT(seekpos, _IO_default_seekpos),
bff334e0 1045 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
d18ea0c5 1046 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
0469311e 1047 JUMP_INIT(doallocate, _IO_wfile_doallocate),
d18ea0c5 1048 JUMP_INIT(read, _IO_file_read),
0469311e 1049 JUMP_INIT(write, _IO_new_file_write),
d18ea0c5 1050 JUMP_INIT(seek, _IO_file_seek),
0469311e 1051 JUMP_INIT(close, _IO_file_close_mmap),
d18ea0c5 1052 JUMP_INIT(stat, _IO_file_stat),
0469311e
UD
1053 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1054 JUMP_INIT(imbue, _IO_default_imbue)
1055};
acbee5f6 1056
b2637a22 1057const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
acbee5f6
RM
1058{
1059 JUMP_INIT_DUMMY,
1060 JUMP_INIT(finish, _IO_new_file_finish),
d18ea0c5 1061 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
acbee5f6 1062 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
d18ea0c5
AS
1063 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1064 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1065 JUMP_INIT(xsputn, _IO_wfile_xsputn),
1066 JUMP_INIT(xsgetn, _IO_file_xsgetn),
1067 JUMP_INIT(seekoff, _IO_wfile_seekoff),
acbee5f6
RM
1068 JUMP_INIT(seekpos, _IO_default_seekpos),
1069 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
d18ea0c5 1070 JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
acbee5f6 1071 JUMP_INIT(doallocate, _IO_wfile_doallocate),
d18ea0c5 1072 JUMP_INIT(read, _IO_file_read),
acbee5f6 1073 JUMP_INIT(write, _IO_new_file_write),
d18ea0c5
AS
1074 JUMP_INIT(seek, _IO_file_seek),
1075 JUMP_INIT(close, _IO_file_close),
1076 JUMP_INIT(stat, _IO_file_stat),
acbee5f6
RM
1077 JUMP_INIT(showmanyc, _IO_default_showmanyc),
1078 JUMP_INIT(imbue, _IO_default_imbue)
1079};