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