1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

stdio-common: Introduce buffers for implementing printf

These buffers will eventually be used instead of FILE * objects
to implement printf functions.  The multibyte buffer is struct
__printf_buffer, the wide buffer is struct __wprintf_buffer.

To enable writing type-generic code, the header files
printf_buffer-char.h and printf_buffer-wchar_t.h define the
Xprintf macro differently, enabling Xprintf (buffer) to stand
for __printf_buffer and __wprintf_buffer as appropriate.  For
common cases, macros like Xprintf_buffer are provided as a more
syntactically convenient shortcut.

Buffer-specific flush callbacks are implemented with a switch
statement instead of a function pointer, to avoid hardening issues
similar to those of libio vtables.  struct __printf_buffer_as_file
is needed to support custom printf specifiers because the public
interface for that requires passing a FILE *, which is why there
is a trapdoor back from these buffers to FILE * streams.

Since the immediate user of these interfaces knows when processing
has finished, there is no flush callback for the end of processing,
only a flush callback for the intermediate buffer flush.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
This commit is contained in:
Florian Weimer
2022-12-19 18:56:54 +01:00
parent ffde06c915
commit 659fe9fdd1
29 changed files with 1534 additions and 0 deletions

View File

@ -602,6 +602,7 @@ $(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
--required=_IO_helper_jumps \ --required=_IO_helper_jumps \
--required=_IO_mem_jumps \ --required=_IO_mem_jumps \
--required=_IO_obstack_jumps \ --required=_IO_obstack_jumps \
--required=_IO_printf_buffer_as_file_jumps \
--required=_IO_proc_jumps \ --required=_IO_proc_jumps \
--required=_IO_str_chk_jumps \ --required=_IO_str_chk_jumps \
--required=_IO_str_jumps \ --required=_IO_str_jumps \
@ -610,6 +611,7 @@ $(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
--required=_IO_wfile_jumps_maybe_mmap \ --required=_IO_wfile_jumps_maybe_mmap \
--required=_IO_wfile_jumps_mmap \ --required=_IO_wfile_jumps_mmap \
--required=_IO_wmem_jumps \ --required=_IO_wmem_jumps \
--required=_IO_wprintf_buffer_as_file_jumps \
--required=_IO_wstr_jumps \ --required=_IO_wstr_jumps \
--required=_IO_wstrn_jumps \ --required=_IO_wstrn_jumps \
--optional=_IO_old_cookie_jumps \ --optional=_IO_old_cookie_jumps \

291
include/printf_buffer.h Normal file
View File

@ -0,0 +1,291 @@
/* Multibyte and wide buffers for implementing printf-related functions.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* The naming of the multibyte and wide variants is intentionally
consistent, so that it is possible to use the Xprintf macro in
stdio-common/printf_buffer-char.h and
stdio-common/printf_buffer-wchar_t.h to select between them in
type-generic code. */
#ifndef PRINTF_BUFFER_H
#define PRINTF_BUFFER_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <wchar.h>
/* <printf_buffer_as_file.h> introduces a way to use struct
__printf_buffer objects from FILE * streams. To avoid storing a
function pointer (or vtable pointer) in struct __printf_buffer
(which would defeat libio vtable hardening), a switch statement
over the different flush implementations is used to implement
__printf_buffer_flush.
__printf_buffer_mode_failed is special: it is the sticky failure
indicator. Unlike struct alloc_buffer, this is not folded into
write_ptr, so that snprintf and other string-writing functions can
discover the end of the string even in the error case, to be able
to add the null terminator. */
enum __printf_buffer_mode
{
__printf_buffer_mode_failed,
__printf_buffer_mode_to_file,
};
/* Buffer for fast character writing with overflow handling.
Typically embedded in another struct with further data that is used
by the flush function. */
struct __printf_buffer
{
/* These pointer members follow FILE streams. write_ptr and
write_end must be initialized to cover the target buffer. See
__printf_buffer_init.
Data can be written directly to *write_ptr while write_ptr !=
write_end, and write_ptr can be advanced accordingly. Note that
is not possible to use the apparently-unused part of the buffer
as scratch space because sprintf (and snprintf, but that is a bit
iffy) must only write the minimum number of characters produced
by the format string and its arguments.
write_base must be initialized to be equal to write_ptr. The
framework uses this pointer to compute the total number of
written bytes, together with the written field. See
__printf_buffer_done.
write_base and write_end are only read by the generic functions
after initialization, only the flush implementation called from
__printf_buffer_flush might change these pointers. See the
comment on Xprintf (buffer_do_flush) in Xprintf_buffer_flush.c
for details regarding the flush operation. */
char *write_base;
char *write_ptr;
char *write_end;
/* Number of characters written so far (excluding the current
buffer). Potentially updated on flush. The actual number of
written bytes also includes the unflushed-but-written buffer
part, write_ptr - write_base. A 64-bit value is used to avoid
the need for overflow checks. */
uint64_t written;
/* Identifies the flush callback. */
enum __printf_buffer_mode mode;
};
/* Marks the buffer as failed, so that __printf_buffer_has_failed
returns true and future flush operations are no-ops. */
static inline void
__printf_buffer_mark_failed (struct __printf_buffer *buf)
{
buf->mode = __printf_buffer_mode_failed;
}
/* Returns true if the sticky error indicator of the buffer has been
set to failed. */
static inline bool __attribute_warn_unused_result__
__printf_buffer_has_failed (struct __printf_buffer *buf)
{
return buf->mode == __printf_buffer_mode_failed;
}
/* Initialization of a buffer, using the memory region from [BASE, BASE +LEN)
as the initial buffer contents. LEN can be zero. */
static inline void
__printf_buffer_init (struct __printf_buffer *buf, char *base, size_t len,
enum __printf_buffer_mode mode)
{
buf->write_base = base;
buf->write_ptr = base;
buf->write_end = base + len;
buf->written = 0;
buf->mode = mode;
}
/* Called by printf_buffer_putc for a full buffer. */
void __printf_buffer_putc_1 (struct __printf_buffer *buf, char ch)
attribute_hidden;
/* Writes CH to BUF. */
static inline void
__printf_buffer_putc (struct __printf_buffer *buf, char ch)
{
if (buf->write_ptr != buf->write_end)
*buf->write_ptr++ = ch;
else
__printf_buffer_putc_1 (buf, ch);
}
/* Writes COUNT repeats of CH to BUF. */
void __printf_buffer_pad_1 (struct __printf_buffer *buf,
char ch, size_t count) attribute_hidden;
/* __printf_buffer_pad with fast path for no padding. COUNT is
ssize_t to accomodate signed uses in printf and elsewhere. */
static inline void
__printf_buffer_pad (struct __printf_buffer *buf, char ch, ssize_t count)
{
if (count > 0)
__printf_buffer_pad_1 (buf, ch, count);
}
/* Write COUNT bytes starting at S to BUF. S must not overlap with
the internal buffer. */
void __printf_buffer_write (struct __printf_buffer *buf, const char *s,
size_t count) attribute_hidden;
/* Write S to BUF. S must not overlap with the internal buffer. */
void __printf_buffer_puts_1 (struct __printf_buffer *buf, const char *s)
attribute_hidden;
static inline void
__printf_buffer_puts (struct __printf_buffer *buf, const char *s)
{
if (__builtin_constant_p (__builtin_strlen (s)))
__printf_buffer_write (buf, s, __builtin_strlen (s));
else
__printf_buffer_puts_1 (buf, s);
}
/* Returns the number of bytes written through the buffer, or -1 if
there was an error (that is, __printf_buffer_has_failed (BUF) is true).
The number of written bytes includes pending bytes in the buffer
(between BUF->write_base and BUF->write_ptr).
If the number is larger than INT_MAX, returns -1 and sets errno to
EOVERFLOW. This function does not flush the buffer. If the caller
needs the side effect of flushing, it has to do this
separately. */
int __printf_buffer_done (struct __printf_buffer *buf) attribute_hidden;
/* Internally used to call the flush function. This can be called
explicitly for certain modes to flush the buffer prematuraly. In
such cases, it is often the case that the buffer mode is statically
known, and the flush implementation can be called directly. */
bool __printf_buffer_flush (struct __printf_buffer *buf) attribute_hidden;
/* Wide version of struct __printf_buffer follows. */
enum __wprintf_buffer_mode
{
__wprintf_buffer_mode_failed,
__wprintf_buffer_mode_to_file,
};
struct __wprintf_buffer
{
wchar_t *write_base;
wchar_t *write_ptr;
wchar_t *write_end;
uint64_t written;
enum __wprintf_buffer_mode mode;
};
static inline void
__wprintf_buffer_mark_failed (struct __wprintf_buffer *buf)
{
buf->mode = __wprintf_buffer_mode_failed;
}
static inline bool __attribute_warn_unused_result__
__wprintf_buffer_has_failed (struct __wprintf_buffer *buf)
{
return buf->mode == __wprintf_buffer_mode_failed;
}
static inline void
__wprintf_buffer_init (struct __wprintf_buffer *buf,
wchar_t *base, size_t len,
enum __wprintf_buffer_mode mode)
{
buf->write_base = base;
buf->write_ptr = base;
buf->write_end = base + len;
buf->written = 0;
buf->mode = mode;
}
void __wprintf_buffer_putc_1 (struct __wprintf_buffer *buf, wchar_t ch)
attribute_hidden;
static inline void
__wprintf_buffer_putc (struct __wprintf_buffer *buf, wchar_t ch)
{
if (buf->write_ptr != buf->write_end)
*buf->write_ptr++ = ch;
else
__wprintf_buffer_putc_1 (buf, ch);
}
void __wprintf_buffer_pad_1 (struct __wprintf_buffer *buf,
wchar_t ch, size_t count) attribute_hidden;
static inline void
__wprintf_buffer_pad (struct __wprintf_buffer *buf, char ch, ssize_t count)
{
if (count > 0)
__wprintf_buffer_pad_1 (buf, ch, count);
}
void __wprintf_buffer_write (struct __wprintf_buffer *buf, const wchar_t *s,
size_t count) attribute_hidden;
void __wprintf_buffer_puts (struct __wprintf_buffer *buf, const wchar_t *s)
attribute_hidden;
int __wprintf_buffer_done (struct __wprintf_buffer *buf) attribute_hidden;
bool __wprintf_buffer_flush (struct __wprintf_buffer *buf) attribute_hidden;
/* Type-generic convenience macros. They are useful if
printf_buffer-char.h or printf_buffer-wchar_t.h is included as
well. */
#define Xprintf_buffer Xprintf (buffer)
#define Xprintf_buffer_done Xprintf (buffer_done)
#define Xprintf_buffer_flush Xprintf (buffer_flush)
#define Xprintf_buffer_has_failed Xprintf (buffer_has_failed)
#define Xprintf_buffer_mark_failed Xprintf (buffer_mark_failed)
#define Xprintf_buffer_pad Xprintf (buffer_pad)
#define Xprintf_buffer_putc Xprintf (buffer_putc)
#define Xprintf_buffer_puts Xprintf (buffer_puts)
#define Xprintf_buffer_write Xprintf (buffer_write)
/* Flush function implementations follow. They are called from
__printf_buffer_flush. Generic code should not call these flush
functions directly. Some modes have inline implementations. */
struct __printf_buffer_to_file;
void __printf_buffer_flush_to_file (struct __printf_buffer_to_file *)
attribute_hidden;
struct __wprintf_buffer_to_file;
void __wprintf_buffer_flush_to_file (struct __wprintf_buffer_to_file *)
attribute_hidden;
/* Buffer sizes. These can be tuned as necessary. There is a tension
here between stack consumption, cache usage, and additional system
calls or heap allocations (if the buffer is too small). */
/* Fallback buffer if the underlying FILE * stream does not provide
buffer space. */
#define PRINTF_BUFFER_SIZE_TO_FILE_STAGE 128
#endif /* PRINTF_BUFFER_H */

View File

@ -53,6 +53,14 @@ routines := \
perror \ perror \
printf \ printf \
printf-prs \ printf-prs \
printf_buffer_as_file \
printf_buffer_done \
printf_buffer_flush \
printf_buffer_pad_1 \
printf_buffer_putc_1 \
printf_buffer_puts_1 \
printf_buffer_to_file \
printf_buffer_write \
printf_fp \ printf_fp \
printf_fphex \ printf_fphex \
printf_size \ printf_size \
@ -85,6 +93,14 @@ routines := \
vfwscanf \ vfwscanf \
vfwscanf-internal \ vfwscanf-internal \
vprintf \ vprintf \
wprintf_buffer_as_file \
wprintf_buffer_done \
wprintf_buffer_flush \
wprintf_buffer_pad_1 \
wprintf_buffer_putc_1 \
wprintf_buffer_puts_1 \
wprintf_buffer_to_file \
wprintf_buffer_write \
# routines # routines
aux := \ aux := \

View File

@ -0,0 +1,40 @@
/* Final status reporting for struct __*printf_buffer. Generic version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <errno.h>
#include <intprops.h>
#include <stdint.h>
int
Xprintf_buffer_done (struct Xprintf_buffer *buf)
{
if (Xprintf_buffer_has_failed (buf))
return -1;
/* Use uintptr_t here because for sprintf, the buffer range may
cover more than half of the address space. */
uintptr_t written_current = buf->write_ptr - buf->write_base;
int written_total;
if (INT_ADD_WRAPV (buf->written, written_current, &written_total))
{
__set_errno (EOVERFLOW);
return -1;
}
else
return written_total;
}

View File

@ -0,0 +1,72 @@
/* Flush wrapper for struct __*printf_buffer. Generic version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include <assert.h>
#include <stdint.h>
/* Xprintf (buffer_do_flush) (BUF) performs the flush operation. The
actual implementation is specific to the multibyte and wide
variants.
If the flush fails, Xprintf_buffer_mark_failed (BUF) must be
called, and BUF->write_ptr and BUF->write_end can be left
unchanged.
The function must not do anything if failure has already occurred,
that is, if BUF->mode == Xprintf (buffer_mode_failed).
The framework implicitly invokes flush with BUF->write_ptr ==
BUF->write_end only. (This is particularly relevant to the
__sprintf_chk flush, which just calls __chk_fail.) But in some
cases, Xprintf_buffer_flush may be called explicitly (when
BUF->mode/the backing function is known). In that case, it is
possible that BUF->write_ptr < BUF->write_end is true.
If the flush succeeds, the pointers are changed so that
BUF->write_ptr < BUF->write_end. It is possible to switch to a
completely different buffer here. If the buffer is moved, it may
be necessary to updated BUF->write_base and BUF->written from the
flush function as well.
Note that when chaining buffers, in the flush function for the
outer buffer (to which data is written first), it is necessary to
check for BUF->next->failed (for the inner buffer) and set
BUF->base.failed to true (for the outer buffer). This should come
towards the end of the outer flush function. Usually, there is
also some unwrapping step afterwards; it has to check the outer
buffer (BUF->base.failed) and propagate any error to the inner
buffer (BUF->next->failed), so essentially in the other
direction. */
static void Xprintf (buffer_do_flush) (struct Xprintf_buffer *buf);
bool
Xprintf_buffer_flush (struct Xprintf_buffer *buf)
{
if (__glibc_unlikely (Xprintf_buffer_has_failed (buf)))
return false;
Xprintf (buffer_do_flush) (buf);
if (Xprintf_buffer_has_failed (buf))
return false;
/* Ensure that the flush has made available some bytes. */
assert (buf->write_ptr != buf->write_end);
return true;
}

View File

@ -0,0 +1,44 @@
/* Write repeated characters to struct __*printf_buffer. Generic version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <assert.h>
#include <string.h>
void
Xprintf (buffer_pad_1) (struct Xprintf_buffer *buf, CHAR_T ch, size_t count)
{
if (__glibc_unlikely (Xprintf_buffer_has_failed (buf)))
return;
do
{
/* Proactively make room. __*printf_buffer_pad has already
checked for a zero-length write, so this function is only
called when there is actually data to write. */
if (buf->write_ptr == buf->write_end && !Xprintf_buffer_flush (buf))
return;
assert (buf->write_ptr != buf->write_end);
size_t to_fill = buf->write_end - buf->write_ptr;
if (to_fill > count)
to_fill = count;
MEMSET (buf->write_ptr, ch, to_fill);
buf->write_ptr += to_fill;
count -= to_fill;
}
while (count > 0);
}

View File

@ -0,0 +1,29 @@
/* Overflow write function for struct __*printf_buffer. Generic version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <assert.h>
void
Xprintf (buffer_putc_1) (struct Xprintf_buffer *buf, CHAR_T ch)
{
if (__glibc_unlikely (Xprintf_buffer_has_failed (buf))
|| !Xprintf_buffer_flush (buf))
return;
assert (buf->write_ptr < buf->write_end);
*buf->write_ptr++ = ch;
}

View File

@ -0,0 +1,38 @@
/* String write function for struct __*printf_buffer. Generic version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <assert.h>
#include <string.h>
void
Xprintf (buffer_puts_1) (struct Xprintf_buffer *buf, const CHAR_T *s)
{
if (__glibc_unlikely (Xprintf_buffer_has_failed (buf)))
return;
while (*s != 0)
{
if (buf->write_ptr == buf->write_end && !Xprintf_buffer_flush (buf))
return;
assert (buf->write_ptr != buf->write_end);
size_t to_copy = STRNLEN (s, buf->write_end - buf->write_ptr);
MEMCPY (buf->write_ptr, s, to_copy);
buf->write_ptr += to_copy;
s += to_copy;
}
}

View File

@ -0,0 +1,44 @@
/* Blob write function for struct __*printf_buffer. Generic version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include <assert.h>
#include <string.h>
void
Xprintf_buffer_write (struct Xprintf_buffer *buf,
const CHAR_T *s, size_t count)
{
if (__glibc_unlikely (Xprintf_buffer_has_failed (buf)))
return;
while (count > 0)
{
if (buf->write_ptr == buf->write_end && !Xprintf_buffer_flush (buf))
return;
assert (buf->write_ptr != buf->write_end);
size_t to_copy = buf->write_end - buf->write_ptr;
if (to_copy > count)
to_copy = count;
MEMCPY (buf->write_ptr, s, to_copy);
buf->write_ptr += to_copy;
s += to_copy;
count -= to_copy;
}
}

View File

@ -0,0 +1,24 @@
/* Macros for the multibyte (char) implementation of struct __printf_buffer.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#define Xprintf(n) __printf_##n
#define CHAR_T char
#define MEMCPY memcpy
#define MEMSET memset
#define STRNLEN __strnlen

View File

@ -0,0 +1,24 @@
/* Macros for wide (wchar_t) implementation of struct __wprintf_buffer.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#define Xprintf(n) __wprintf_##n
#define CHAR_T wchar_t
#define MEMCPY __wmemcpy
#define MEMSET __wmemset
#define STRNLEN __wcsnlen

View File

@ -0,0 +1,148 @@
/* FILE * interface to a struct __printf_buffer. Multibyte version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer_as_file.h>
#include <assert.h>
#include <printf_buffer.h>
/* Commit the data directly written through the stdio stream. */
static void
__printf_buffer_as_file_commit (struct __printf_buffer_as_file *file)
{
/* Check that the write pointers in the file stream are consistent
with the next buffer. */
assert (file->stream._IO_write_ptr >= file->next->write_ptr);
assert (file->stream._IO_write_ptr <= file->next->write_end);
assert (file->stream._IO_write_base == file->next->write_base);
assert (file->stream._IO_write_end == file->next->write_end);
file->next->write_ptr = file->stream._IO_write_ptr;
}
/* Pointer the FILE * write buffer into the active printf_buffer
area. */
static void
__printf_buffer_as_file_switch_to_buffer (struct __printf_buffer_as_file *file)
{
file->stream._IO_write_base = file->next->write_base;
file->stream._IO_write_ptr = file->next->write_ptr;
file->stream._IO_write_end = file->next->write_end;
}
/* Only a small subset of the vtable functions is implemented here,
following _IO_obstack_jumps. */
static int
__printf_buffer_as_file_overflow (FILE *fp, int ch)
{
struct __printf_buffer_as_file *file = (struct __printf_buffer_as_file *) fp;
__printf_buffer_as_file_commit (file);
/* EOF means only a flush is requested. */
if (ch != EOF)
__printf_buffer_putc (file->next, ch);
/* Ensure that flushing actually produces room. */
if (!__printf_buffer_has_failed (file->next)
&& file->next->write_ptr == file->next->write_end)
__printf_buffer_flush (file->next);
__printf_buffer_as_file_switch_to_buffer (file);
if (!__printf_buffer_has_failed (file->next))
return (unsigned char) ch;
else
return EOF;
}
static size_t
__printf_buffer_as_file_xsputn (FILE *fp, const void *buf, size_t len)
{
struct __printf_buffer_as_file *file = (struct __printf_buffer_as_file *) fp;
__printf_buffer_as_file_commit (file);
/* Copy the data. */
__printf_buffer_write (file->next, buf, len);
__printf_buffer_as_file_switch_to_buffer (file);
if (!__printf_buffer_has_failed (file->next))
return len;
else
/* We may actually have written something. But the stream is
corrupted in this case anyway, so try not to divine the write
count here. */
return 0;
}
static const struct _IO_jump_t _IO_printf_buffer_as_file_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, NULL),
JUMP_INIT(overflow, __printf_buffer_as_file_overflow),
JUMP_INIT(underflow, NULL),
JUMP_INIT(uflow, NULL),
JUMP_INIT(pbackfail, NULL),
JUMP_INIT(xsputn, __printf_buffer_as_file_xsputn),
JUMP_INIT(xsgetn, NULL),
JUMP_INIT(seekoff, NULL),
JUMP_INIT(seekpos, NULL),
JUMP_INIT(setbuf, NULL),
JUMP_INIT(sync, NULL),
JUMP_INIT(doallocate, NULL),
JUMP_INIT(read, NULL),
JUMP_INIT(write, NULL),
JUMP_INIT(seek, NULL),
JUMP_INIT(close, NULL),
JUMP_INIT(stat, NULL),
JUMP_INIT(showmanyc, NULL),
JUMP_INIT(imbue, NULL)
};
void
__printf_buffer_as_file_init (struct __printf_buffer_as_file *file,
struct __printf_buffer *next)
{
file->stream._lock = NULL;
_IO_no_init (&file->stream, _IO_USER_LOCK, -1, NULL, NULL);
file->vtable = &_IO_printf_buffer_as_file_jumps;
/* Set up the write buffer from the next buffer. */
file->next = next;
__printf_buffer_as_file_switch_to_buffer (file);
/* Mark the read area as inactive, by making all pointers equal. */
file->stream._IO_read_base = file->stream._IO_write_base;
file->stream._IO_read_ptr = file->stream._IO_write_base;
file->stream._IO_read_end = file->stream._IO_write_base;
}
bool
__printf_buffer_as_file_terminate (struct __printf_buffer_as_file *file)
{
if (file->stream._flags & _IO_ERR_SEEN)
return false;
else
{
__printf_buffer_as_file_commit (file);
return true;
}
}

View File

@ -0,0 +1,87 @@
/* FILE * interface to a struct __*printf_buffer.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* Registered printf format specifier callbacks produce data via a
FILE * stream. struct __printf_buffer_as_file enables vfprintf to
create a suitable stdio stream. Likewise struct
__wprintf_buffer_as_file for vfwprintf. */
#ifndef PRINTF_BUFFER_AS_FILE_H
#define PRINTF_BUFFER_AS_FILE_H
#include <libio/libioP.h>
struct __printf_buffer;
struct __printf_buffer_as_file
{
/* Interface to libio. */
FILE stream;
const struct _IO_jump_t *vtable;
/* Pointer to the underlying buffer. */
struct __printf_buffer *next;
};
/* Initialization *FP so that data written to its FILE * stream ends
up in NEXT. */
void __printf_buffer_as_file_init (struct __printf_buffer_as_file *fp,
struct __printf_buffer *next)
attribute_hidden;
/* Returns the FILE * that can be used to write data to the
buffer. */
static inline FILE *
__printf_buffer_as_file_get (struct __printf_buffer_as_file *file)
{
return &file->stream;
}
/* Transfers all pending data from the FILE * to the underlying
buffer. Returns true if there have been no errors. */
bool __printf_buffer_as_file_terminate (struct __printf_buffer_as_file *)
attribute_hidden;
/* Wide variant follows. */
struct __wprintf_buffer;
struct __wprintf_buffer_as_file
{
/* Interface to libio. */
FILE stream;
const struct _IO_jump_t *vtable;
struct _IO_wide_data wide_stream;
/* Pointer to the underlying buffer. */
struct __wprintf_buffer *next;
};
void __wprintf_buffer_as_file_init (struct __wprintf_buffer_as_file *fp,
struct __wprintf_buffer *next)
attribute_hidden;
static inline FILE *
__wprintf_buffer_as_file_get (struct __wprintf_buffer_as_file *file)
{
return &file->stream;
}
bool __wprintf_buffer_as_file_terminate (struct __wprintf_buffer_as_file *)
attribute_hidden;
#endif /* PRINTF_BUFFER_AS_FILE_H */

View File

@ -0,0 +1,21 @@
/* Final status reporting for struct __printf_buffer. Multibyte version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-char.h"
#include "Xprintf_buffer_done.c"

View File

@ -0,0 +1,42 @@
/* Flush a struct __printf_buffer. Multibyte version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-char.h"
#include "Xprintf_buffer_flush.c"
/* The __printf_buffer_flush_* functions are defined together with
functions that are pulled in by strong references. */
#ifndef SHARED
# pragma weak __printf_buffer_flush_to_file
#endif /* !SHARED */
static void
__printf_buffer_do_flush (struct __printf_buffer *buf)
{
switch (buf->mode)
{
case __printf_buffer_mode_failed:
return;
case __printf_buffer_mode_to_file:
__printf_buffer_flush_to_file ((struct __printf_buffer_to_file *) buf);
return;
}
__builtin_trap ();
}

View File

@ -0,0 +1,21 @@
/* Write repeated characters to struct __printf_buffer. Multibyte version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-char.h"
#include "Xprintf_buffer_pad_1.c"

View File

@ -0,0 +1,21 @@
/* Overflow character write function for struct __printf_buffer.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-char.h"
#include "Xprintf_buffer_putc_1.c"

View File

@ -0,0 +1,21 @@
/* String write function for struct __printf_buffer. Multibyte version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-char.h"
#include "Xprintf_buffer_puts_1.c"

View File

@ -0,0 +1,122 @@
/* Multibyte printf buffers writing data to a FILE * stream.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer_to_file.h>
#include <assert.h>
#include <array_length.h>
#include <libio/libioP.h>
/* Switch to the file buffer if possible. If the file has write_ptr
== write_end, use the stage buffer instead. */
void
__printf_buffer_to_file_switch (struct __printf_buffer_to_file *buf)
{
if (buf->fp->_IO_write_ptr < buf->fp->_IO_write_end)
{
/* buf->fp has a buffer associated with it, so write directly to
it from now on. */
buf->base.write_ptr = buf->fp->_IO_write_ptr;
buf->base.write_end = buf->fp->_IO_write_end;
}
else
{
/* Use the staging area if no buffer is available in buf->fp. */
buf->base.write_ptr = buf->stage;
buf->base.write_end = array_end (buf->stage);
}
buf->base.write_base = buf->base.write_ptr;
}
void
__printf_buffer_flush_to_file (struct __printf_buffer_to_file *buf)
{
/* The bytes in the buffer are always consumed. */
buf->base.written += buf->base.write_ptr - buf->base.write_base;
if (buf->base.write_end == array_end (buf->stage))
{
/* If the stage buffer is used, make a copy into the file. The
stage buffer is always consumed fully, even if just partially
written, to ensure that the file stream has all the data. */
size_t count = buf->base.write_ptr - buf->stage;
if ((size_t) _IO_sputn (buf->fp, buf->stage, count) != count)
{
__printf_buffer_mark_failed (&buf->base);
return;
}
/* buf->fp may have a buffer now. */
__printf_buffer_to_file_switch (buf);
return;
}
else if (buf->base.write_end == buf->stage + 1)
{
/* Special one-character buffer case. This is used to avoid
flush-only overflow below. */
if (buf->base.write_ptr == buf->base.write_end)
{
if (__overflow (buf->fp, (unsigned char) *buf->stage) == EOF)
{
__printf_buffer_mark_failed (&buf->base);
return;
}
__printf_buffer_to_file_switch (buf);
}
/* Else there is nothing to write. */
return;
}
/* We have written directly into the buf->fp buffer. */
assert (buf->base.write_end == buf->fp->_IO_write_end);
/* Mark the bytes as written. */
buf->fp->_IO_write_ptr = buf->base.write_ptr;
if (buf->base.write_ptr == buf->base.write_end)
{
/* The buffer in buf->fp has been filled. This should just call
__overflow (buf->fp, EOF), but flush-only overflow is obscure
and not always correctly implemented. See bug 28949. Be
conservative and switch to a one-character buffer instead, to
obtain one more character for a regular __overflow call. */
buf->base.write_ptr = buf->stage;
buf->base.write_end = buf->stage + 1;
}
/* The bytes in the file stream were already marked as written above. */
buf->base.write_base = buf->base.write_ptr;
}
void
__printf_buffer_to_file_init (struct __printf_buffer_to_file *buf, FILE *fp)
{
__printf_buffer_init (&buf->base, buf->stage, array_length (buf->stage),
__printf_buffer_mode_to_file);
buf->fp = fp;
__printf_buffer_to_file_switch (buf);
}
int
__printf_buffer_to_file_done (struct __printf_buffer_to_file *buf)
{
if (__printf_buffer_has_failed (&buf->base))
return -1;
__printf_buffer_flush_to_file (buf);
return __printf_buffer_done (&buf->base);
}

View File

@ -0,0 +1,57 @@
/* Multibyte and wide printf buffers writing data to a FILE * stream.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef PRINTF_BUFFER_TO_FILE_H
#define PRINTF_BUFFER_TO_FILE_H
#include <bits/types/FILE.h>
#include <printf_buffer.h>
struct __printf_buffer_to_file
{
struct __printf_buffer base;
FILE *fp;
/* Staging buffer. Used if fp does not have any available buffer
space. */
char stage[PRINTF_BUFFER_SIZE_TO_FILE_STAGE];
};
/* Initializes *BUF to write data to FP. */
void __printf_buffer_to_file_init (struct __printf_buffer_to_file *buf,
FILE *fp) attribute_hidden;
/* Transfers any pending data in BUF to BUF->FP. The return value
follows the printf convention (number bytes written; or -1 for error). */
int __printf_buffer_to_file_done (struct __printf_buffer_to_file *buf)
attribute_hidden;
/* Wide version below. */
struct __wprintf_buffer_to_file
{
struct __wprintf_buffer base;
FILE *fp;
wchar_t stage[PRINTF_BUFFER_SIZE_TO_FILE_STAGE];
};
void __wprintf_buffer_to_file_init (struct __wprintf_buffer_to_file *buf,
FILE *fp) attribute_hidden;
int __wprintf_buffer_to_file_done (struct __wprintf_buffer_to_file *buf)
attribute_hidden;
#endif /* PRINTF_BUFFER_TO_FILE_H */

View File

@ -0,0 +1,21 @@
/* Blob write function for struct __printf_buffer. Multibyte version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-char.h"
#include "Xprintf_buffer_write.c"

View File

@ -0,0 +1,153 @@
/* FILE * interface to a struct __wprintf_buffer. Wide version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer_as_file.h>
#include <assert.h>
#include <printf_buffer.h>
/* Commit the data directly written through the stdio stream. */
static void
__wprintf_buffer_as_file_commit (struct __wprintf_buffer_as_file *file)
{
/* Check that the write pointers in the file stream are consistent
with the next buffer. */
assert (file->wide_stream._IO_write_ptr >= file->next->write_ptr);
assert (file->wide_stream._IO_write_ptr <= file->next->write_end);
assert (file->wide_stream._IO_write_base == file->next->write_base);
assert (file->wide_stream._IO_write_end == file->next->write_end);
file->next->write_ptr = file->wide_stream._IO_write_ptr;
}
/* Pointer the FILE * write buffer into the active struct __wprintf_buffer
area. */
static void
__wprintf_buffer_as_file_switch_to_buffer (struct __wprintf_buffer_as_file *file)
{
file->wide_stream._IO_write_base = file->next->write_base;
file->wide_stream._IO_write_ptr = file->next->write_ptr;
file->wide_stream._IO_write_end = file->next->write_end;
}
/* Only a small subset of the vtable functions is implemented here,
following _IO_obstack_jumps. */
static wint_t
__wprintf_buffer_as_file_overflow (FILE *fp, int ch)
{
struct __wprintf_buffer_as_file *file
= (struct __wprintf_buffer_as_file *) fp;
__wprintf_buffer_as_file_commit (file);
/* EOF means only a flush is requested. */
if (ch != WEOF)
__wprintf_buffer_putc (file->next, ch);
else
ch = 0;
/* Ensure that flushing actually produces room. */
if (!__wprintf_buffer_has_failed (file->next)
&& file->next->write_ptr == file->next->write_end)
__wprintf_buffer_flush (file->next);
__wprintf_buffer_as_file_switch_to_buffer (file);
if (!__wprintf_buffer_has_failed (file->next))
return (unsigned char) ch;
else
return WEOF;
}
static size_t
__wprintf_buffer_as_file_xsputn (FILE *fp, const void *buf, size_t len)
{
struct __wprintf_buffer_as_file *file
= (struct __wprintf_buffer_as_file *) fp;
__wprintf_buffer_as_file_commit (file);
/* Copy the data. */
__wprintf_buffer_write (file->next, buf, len);
__wprintf_buffer_as_file_switch_to_buffer (file);
if (!__wprintf_buffer_has_failed (file->next))
return len;
else
/* We may actually have written something. But the stream is
corrupted in this case anyway, so try not to divine the write
count here. */
return 0;
}
static const struct _IO_jump_t _IO_wprintf_buffer_as_file_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, NULL),
JUMP_INIT(overflow, (_IO_overflow_t) __wprintf_buffer_as_file_overflow),
JUMP_INIT(underflow, NULL),
JUMP_INIT(uflow, NULL),
JUMP_INIT(pbackfail, NULL),
JUMP_INIT(xsputn, __wprintf_buffer_as_file_xsputn),
JUMP_INIT(xsgetn, NULL),
JUMP_INIT(seekoff, NULL),
JUMP_INIT(seekpos, NULL),
JUMP_INIT(setbuf, NULL),
JUMP_INIT(sync, NULL),
JUMP_INIT(doallocate, NULL),
JUMP_INIT(read, NULL),
JUMP_INIT(write, NULL),
JUMP_INIT(seek, NULL),
JUMP_INIT(close, NULL),
JUMP_INIT(stat, NULL),
JUMP_INIT(showmanyc, NULL),
JUMP_INIT(imbue, NULL)
};
void
__wprintf_buffer_as_file_init (struct __wprintf_buffer_as_file *file,
struct __wprintf_buffer *next)
{
file->stream._lock = NULL;
_IO_no_init (&file->stream, _IO_USER_LOCK, 0, &file->wide_stream,
&_IO_wprintf_buffer_as_file_jumps);
_IO_fwide (&file->stream, 1);
/* Set up the write buffer from the next buffer. */
file->next = next;
__wprintf_buffer_as_file_switch_to_buffer (file);
/* Mark the read area as inactive, by making all pointers equal. */
file->stream._IO_read_base = file->stream._IO_write_base;
file->stream._IO_read_ptr = file->stream._IO_write_base;
file->stream._IO_read_end = file->stream._IO_write_base;
}
bool
__wprintf_buffer_as_file_terminate (struct __wprintf_buffer_as_file *file)
{
if (file->stream._flags & _IO_ERR_SEEN)
return false;
else
{
__wprintf_buffer_as_file_commit (file);
return true;
}
}

View File

@ -0,0 +1,21 @@
/* Final status reporting for struct __wprintf_buffer. Wide version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-wchar_t.h"
#include "Xprintf_buffer_done.c"

View File

@ -0,0 +1,36 @@
/* Flush a struct __wprintf_buffer. Wide version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-wchar_t.h"
#include "Xprintf_buffer_flush.c"
static void
__wprintf_buffer_do_flush (struct __wprintf_buffer *buf)
{
switch (buf->mode)
{
case __wprintf_buffer_mode_failed:
return;
case __wprintf_buffer_mode_to_file:
__wprintf_buffer_flush_to_file ((struct __wprintf_buffer_to_file *) buf);
return;
}
__builtin_trap ();
}

View File

@ -0,0 +1,21 @@
/* Write repeated characters to struct __wprintf_buffer. Wide version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-wchar_t.h"
#include "Xprintf_buffer_pad_1.c"

View File

@ -0,0 +1,21 @@
/* Overflow character write function for struct __wprintf_buffer. Wide version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-wchar_t.h"
#include "Xprintf_buffer_putc_1.c"

View File

@ -0,0 +1,21 @@
/* String write function struct __wprintf_buffer. Wide version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-wchar_t.h"
#include "Xprintf_buffer_puts_1.c"

View File

@ -0,0 +1,55 @@
/* Wide printf buffers writing data to a FILE *.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This implementation is not optimized (unlikely the multibyte
implementation) and always writes to the temporary buffer first. */
#include <printf_buffer_to_file.h>
#include <array_length.h>
#include <libio/libioP.h>
void
__wprintf_buffer_flush_to_file (struct __wprintf_buffer_to_file *buf)
{
size_t count = buf->base.write_ptr - buf->stage;
if ((size_t) _IO_sputn (buf->fp, buf->stage, count) != count)
{
__wprintf_buffer_mark_failed (&buf->base);
return;
}
buf->base.written += count;
buf->base.write_ptr = buf->stage;
}
void
__wprintf_buffer_to_file_init (struct __wprintf_buffer_to_file *buf, FILE *fp)
{
__wprintf_buffer_init (&buf->base, buf->stage, array_length (buf->stage),
__wprintf_buffer_mode_to_file);
buf->fp = fp;
}
int
__wprintf_buffer_to_file_done (struct __wprintf_buffer_to_file *buf)
{
if (__wprintf_buffer_has_failed (&buf->base))
return -1;
__wprintf_buffer_flush_to_file (buf);
return __wprintf_buffer_done (&buf->base);
}

View File

@ -0,0 +1,21 @@
/* Blob write function for struct __wprintf_buffer. Wide version.
Copyright (C) 2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <printf_buffer.h>
#include "printf_buffer-wchar_t.h"
#include "Xprintf_buffer_write.c"