12b0e13f41cc9d095566f244af6f759ba07777e0
[platform/upstream/glibc.git] / stdio-common / printf_buffer_as_file.c
1 /* FILE * interface to a struct __printf_buffer.  Multibyte version.
2    Copyright (C) 2022-2023 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
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.
9
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.
14
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/>.  */
18
19 #include <printf_buffer_as_file.h>
20
21 #include <assert.h>
22 #include <printf_buffer.h>
23
24 /* Commit the data directly written through the stdio stream.  */
25 static void
26 __printf_buffer_as_file_commit (struct __printf_buffer_as_file *file)
27 {
28   /* Check that the write pointers in the file stream are consistent
29      with the next buffer.  */
30   assert (file->stream._IO_write_ptr >= file->next->write_ptr);
31   assert (file->stream._IO_write_ptr <= file->next->write_end);
32   assert (file->stream._IO_write_base == file->next->write_base);
33   assert (file->stream._IO_write_end == file->next->write_end);
34
35   file->next->write_ptr = file->stream._IO_write_ptr;
36 }
37
38 /* Pointer the FILE * write buffer into the active printf_buffer
39    area.  */
40 static void
41 __printf_buffer_as_file_switch_to_buffer (struct __printf_buffer_as_file *file)
42 {
43   file->stream._IO_write_base = file->next->write_base;
44   file->stream._IO_write_ptr = file->next->write_ptr;
45   file->stream._IO_write_end = file->next->write_end;
46 }
47
48 /* Only a small subset of the vtable functions is implemented here,
49    following _IO_obstack_jumps.  */
50
51 static int
52 __printf_buffer_as_file_overflow (FILE *fp, int ch)
53 {
54   struct __printf_buffer_as_file *file = (struct __printf_buffer_as_file *) fp;
55
56   __printf_buffer_as_file_commit (file);
57
58   /* EOF means only a flush is requested.   */
59   if (ch != EOF)
60     __printf_buffer_putc (file->next, ch);
61
62   /* Ensure that flushing actually produces room.  */
63   if (!__printf_buffer_has_failed (file->next)
64       && file->next->write_ptr == file->next->write_end)
65     __printf_buffer_flush (file->next);
66
67   __printf_buffer_as_file_switch_to_buffer (file);
68
69   if (!__printf_buffer_has_failed (file->next))
70     return (unsigned char) ch;
71   else
72     return EOF;
73 }
74
75 static size_t
76 __printf_buffer_as_file_xsputn (FILE *fp, const void *buf, size_t len)
77 {
78   struct __printf_buffer_as_file *file = (struct __printf_buffer_as_file *) fp;
79
80   __printf_buffer_as_file_commit (file);
81
82   /* Copy the data.  */
83   __printf_buffer_write (file->next, buf, len);
84
85   __printf_buffer_as_file_switch_to_buffer (file);
86
87   if (!__printf_buffer_has_failed (file->next))
88     return len;
89   else
90     /* We may actually have written something.  But the stream is
91        corrupted in this case anyway, so try not to divine the write
92        count here.  */
93     return 0;
94 }
95
96 static const struct _IO_jump_t _IO_printf_buffer_as_file_jumps libio_vtable =
97 {
98   JUMP_INIT_DUMMY,
99   JUMP_INIT(finish, NULL),
100   JUMP_INIT(overflow, __printf_buffer_as_file_overflow),
101   JUMP_INIT(underflow, NULL),
102   JUMP_INIT(uflow, NULL),
103   JUMP_INIT(pbackfail, NULL),
104   JUMP_INIT(xsputn, __printf_buffer_as_file_xsputn),
105   JUMP_INIT(xsgetn, NULL),
106   JUMP_INIT(seekoff, NULL),
107   JUMP_INIT(seekpos, NULL),
108   JUMP_INIT(setbuf, NULL),
109   JUMP_INIT(sync, NULL),
110   JUMP_INIT(doallocate, NULL),
111   JUMP_INIT(read, NULL),
112   JUMP_INIT(write, NULL),
113   JUMP_INIT(seek, NULL),
114   JUMP_INIT(close, NULL),
115   JUMP_INIT(stat, NULL),
116   JUMP_INIT(showmanyc, NULL),
117   JUMP_INIT(imbue, NULL)
118 };
119
120 void
121 __printf_buffer_as_file_init (struct __printf_buffer_as_file *file,
122                               struct __printf_buffer *next)
123 {
124   file->stream._lock = NULL;
125   _IO_no_init (&file->stream, _IO_USER_LOCK, -1, NULL, NULL);
126   file->vtable = &_IO_printf_buffer_as_file_jumps;
127
128   /* Set up the write buffer from the next buffer.  */
129   file->next = next;
130   __printf_buffer_as_file_switch_to_buffer (file);
131
132   /* Mark the read area as inactive, by making all pointers equal.  */
133   file->stream._IO_read_base = file->stream._IO_write_base;
134   file->stream._IO_read_ptr = file->stream._IO_write_base;
135   file->stream._IO_read_end = file->stream._IO_write_base;
136 }
137
138 bool
139 __printf_buffer_as_file_terminate (struct __printf_buffer_as_file *file)
140 {
141   if (file->stream._flags & _IO_ERR_SEEN)
142     return false;
143   else
144     {
145       __printf_buffer_as_file_commit (file);
146       return true;
147     }
148 }