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