]>
Commit | Line | Data |
---|---|---|
659fe9fd | 1 | /* FILE * interface to a struct __printf_buffer. Multibyte version. |
6d7e8eda | 2 | Copyright (C) 2022-2023 Free Software Foundation, Inc. |
659fe9fd FW |
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 | } |