Use Linux 6.6 in build-many-glibcs.py
[glibc.git] / stdio-common / printf_buffer_to_file.c
blob8b3adadf70c1bb18c15bdbe4337691648113dc6e
1 /* Multibyte printf buffers writing data to a FILE * stream.
2 Copyright (C) 2022-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <printf_buffer_to_file.h>
21 #include <assert.h>
22 #include <array_length.h>
23 #include <libio/libioP.h>
25 /* Switch to the file buffer if possible. If the file has write_ptr
26 == write_end, use the stage buffer instead. */
27 void
28 __printf_buffer_to_file_switch (struct __printf_buffer_to_file *buf)
30 if (buf->fp->_IO_write_ptr < buf->fp->_IO_write_end)
32 /* buf->fp has a buffer associated with it, so write directly to
33 it from now on. */
34 buf->base.write_ptr = buf->fp->_IO_write_ptr;
35 buf->base.write_end = buf->fp->_IO_write_end;
37 else
39 /* Use the staging area if no buffer is available in buf->fp. */
40 buf->base.write_ptr = buf->stage;
41 buf->base.write_end = array_end (buf->stage);
44 buf->base.write_base = buf->base.write_ptr;
47 void
48 __printf_buffer_flush_to_file (struct __printf_buffer_to_file *buf)
50 /* The bytes in the buffer are always consumed. */
51 buf->base.written += buf->base.write_ptr - buf->base.write_base;
53 if (buf->base.write_end == array_end (buf->stage))
55 /* If the stage buffer is used, make a copy into the file. The
56 stage buffer is always consumed fully, even if just partially
57 written, to ensure that the file stream has all the data. */
58 size_t count = buf->base.write_ptr - buf->stage;
59 if ((size_t) _IO_sputn (buf->fp, buf->stage, count) != count)
61 __printf_buffer_mark_failed (&buf->base);
62 return;
64 /* buf->fp may have a buffer now. */
65 __printf_buffer_to_file_switch (buf);
66 return;
68 else if (buf->base.write_end == buf->stage + 1)
70 /* Special one-character buffer case. This is used to avoid
71 flush-only overflow below. */
72 if (buf->base.write_ptr == buf->base.write_end)
74 if (__overflow (buf->fp, (unsigned char) *buf->stage) == EOF)
76 __printf_buffer_mark_failed (&buf->base);
77 return;
79 __printf_buffer_to_file_switch (buf);
81 /* Else there is nothing to write. */
82 return;
85 /* We have written directly into the buf->fp buffer. */
86 assert (buf->base.write_end == buf->fp->_IO_write_end);
88 /* Mark the bytes as written. */
89 buf->fp->_IO_write_ptr = buf->base.write_ptr;
91 if (buf->base.write_ptr == buf->base.write_end)
93 /* The buffer in buf->fp has been filled. This should just call
94 __overflow (buf->fp, EOF), but flush-only overflow is obscure
95 and not always correctly implemented. See bug 28949. Be
96 conservative and switch to a one-character buffer instead, to
97 obtain one more character for a regular __overflow call. */
98 buf->base.write_ptr = buf->stage;
99 buf->base.write_end = buf->stage + 1;
101 /* The bytes in the file stream were already marked as written above. */
103 buf->base.write_base = buf->base.write_ptr;
106 void
107 __printf_buffer_to_file_init (struct __printf_buffer_to_file *buf, FILE *fp)
109 __printf_buffer_init (&buf->base, buf->stage, array_length (buf->stage),
110 __printf_buffer_mode_to_file);
111 buf->fp = fp;
112 __printf_buffer_to_file_switch (buf);
116 __printf_buffer_to_file_done (struct __printf_buffer_to_file *buf)
118 if (__printf_buffer_has_failed (&buf->base))
119 return -1;
120 __printf_buffer_flush_to_file (buf);
121 return __printf_buffer_done (&buf->base);