1/* Copyright (C) 1993-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>.
17
18 As a special exception, if you link the code in this file with
19 files compiled with a GNU compiler to produce an executable,
20 that does not cause the resulting executable to be covered by
21 the GNU Lesser General Public License. This exception does not
22 however invalidate any other reasons why the executable file
23 might be covered by the GNU Lesser General Public License.
24 This exception applies to code released by its copyright holders
25 in files containing the exception. */
26
27#include <assert.h>
28#include "strfile.h"
29#include "libioP.h"
30#include <string.h>
31#include <wchar.h>
32#include <stdio_ext.h>
33
34void
35_IO_wstr_init_static (FILE *fp, wchar_t *ptr, size_t size,
36 wchar_t *pstart)
37{
38 wchar_t *end;
39
40 if (size == 0)
41 end = ptr + __wcslen (s: ptr);
42 else if ((size_t) ptr + size * sizeof (wchar_t) > (size_t) ptr)
43 end = ptr + size;
44 else
45 /* Even for misaligned ptr make sure there is integral number of wide
46 characters. */
47 end = ptr + (-1 - (size_t) ptr) / sizeof (wchar_t);
48 _IO_wsetb (fp, ptr, end, 0);
49
50 fp->_wide_data->_IO_write_base = ptr;
51 fp->_wide_data->_IO_read_base = ptr;
52 fp->_wide_data->_IO_read_ptr = ptr;
53 if (pstart)
54 {
55 fp->_wide_data->_IO_write_ptr = pstart;
56 fp->_wide_data->_IO_write_end = end;
57 fp->_wide_data->_IO_read_end = pstart;
58 }
59 else
60 {
61 fp->_wide_data->_IO_write_ptr = ptr;
62 fp->_wide_data->_IO_write_end = ptr;
63 fp->_wide_data->_IO_read_end = end;
64 }
65 /* A null _allocate_buffer function flags the strfile as being static. */
66 (((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0;
67}
68
69wint_t
70_IO_wstr_overflow (FILE *fp, wint_t c)
71{
72 int flush_only = c == WEOF;
73 size_t pos;
74 if (fp->_flags & _IO_NO_WRITES)
75 return flush_only ? 0 : WEOF;
76 if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
77 {
78 fp->_flags |= _IO_CURRENTLY_PUTTING;
79 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
80 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
81 }
82 pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
83 if (pos >= (size_t) (_IO_wblen (fp) + flush_only))
84 {
85 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* not allowed to enlarge */
86 return WEOF;
87 else
88 {
89 wchar_t *new_buf;
90 wchar_t *old_buf = fp->_wide_data->_IO_buf_base;
91 size_t old_wblen = _IO_wblen (fp);
92 size_t new_size = 2 * old_wblen + 100;
93
94 if (__glibc_unlikely (new_size < old_wblen)
95 || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t)))
96 return EOF;
97
98 new_buf = malloc (size: new_size * sizeof (wchar_t));
99 if (new_buf == NULL)
100 {
101 /* __ferror(fp) = 1; */
102 return WEOF;
103 }
104 if (old_buf)
105 {
106 __wmemcpy (s1: new_buf, s2: old_buf, n: old_wblen);
107 free (ptr: old_buf);
108 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
109 fp->_wide_data->_IO_buf_base = NULL;
110 }
111
112 __wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
113
114 _IO_wsetb (fp, new_buf, new_buf + new_size, 1);
115 fp->_wide_data->_IO_read_base =
116 new_buf + (fp->_wide_data->_IO_read_base - old_buf);
117 fp->_wide_data->_IO_read_ptr =
118 new_buf + (fp->_wide_data->_IO_read_ptr - old_buf);
119 fp->_wide_data->_IO_read_end =
120 new_buf + (fp->_wide_data->_IO_read_end - old_buf);
121 fp->_wide_data->_IO_write_ptr =
122 new_buf + (fp->_wide_data->_IO_write_ptr - old_buf);
123
124 fp->_wide_data->_IO_write_base = new_buf;
125 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
126 }
127 }
128
129 if (!flush_only)
130 *fp->_wide_data->_IO_write_ptr++ = c;
131 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
132 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
133 return c;
134}
135
136
137wint_t
138_IO_wstr_underflow (FILE *fp)
139{
140 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
141 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
142 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
143 {
144 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
145 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
146 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
147 }
148 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
149 return *fp->_wide_data->_IO_read_ptr;
150 else
151 return WEOF;
152}
153
154
155/* The size of the valid part of the buffer. */
156ssize_t
157_IO_wstr_count (FILE *fp)
158{
159 struct _IO_wide_data *wd = fp->_wide_data;
160
161 return ((wd->_IO_write_ptr > wd->_IO_read_end
162 ? wd->_IO_write_ptr : wd->_IO_read_end)
163 - wd->_IO_read_base);
164}
165
166
167static int
168enlarge_userbuf (FILE *fp, off64_t offset, int reading)
169{
170 if ((ssize_t) offset <= _IO_wblen (fp))
171 return 0;
172
173 struct _IO_wide_data *wd = fp->_wide_data;
174
175 ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
176
177 /* Try to enlarge the buffer. */
178 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
179 /* User-provided buffer. */
180 return 1;
181
182 size_t newsize = offset + 100;
183 if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
184 return 1;
185
186 wchar_t *oldbuf = wd->_IO_buf_base;
187 wchar_t *newbuf = malloc (size: newsize * sizeof (wchar_t));
188 if (newbuf == NULL)
189 return 1;
190
191 if (oldbuf != NULL)
192 {
193 __wmemcpy (s1: newbuf, s2: oldbuf, _IO_wblen (fp));
194 free (ptr: oldbuf);
195 /* Make sure _IO_setb won't try to delete
196 _IO_buf_base. */
197 wd->_IO_buf_base = NULL;
198 }
199
200 _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
201
202 if (reading)
203 {
204 wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf);
205 wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
206 wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf);
207 wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
208
209 wd->_IO_read_base = newbuf;
210 wd->_IO_read_end = wd->_IO_buf_end;
211 }
212 else
213 {
214 wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf);
215 wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
216 wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf);
217 wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
218
219 wd->_IO_write_base = newbuf;
220 wd->_IO_write_end = wd->_IO_buf_end;
221 }
222
223 /* Clear the area between the last write position and th
224 new position. */
225 assert (offset >= oldend);
226 if (reading)
227 __wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
228 else
229 __wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
230
231 return 0;
232}
233
234static void
235_IO_wstr_switch_to_get_mode (FILE *fp)
236{
237 if (_IO_in_backup (fp))
238 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
239 else
240 {
241 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
242 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
243 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
244 }
245 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
246 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
247
248 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
249}
250
251off64_t
252_IO_wstr_seekoff (FILE *fp, off64_t offset, int dir, int mode)
253{
254 off64_t new_pos;
255
256 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
257 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
258
259 bool was_writing = ((fp->_wide_data->_IO_write_ptr
260 > fp->_wide_data->_IO_write_base)
261 || _IO_in_put_mode (fp));
262 if (was_writing)
263 _IO_wstr_switch_to_get_mode (fp);
264
265 if (mode == 0)
266 {
267 new_pos = (fp->_wide_data->_IO_write_ptr
268 - fp->_wide_data->_IO_write_base);
269 }
270 else
271 {
272 ssize_t cur_size = _IO_wstr_count (fp);
273 new_pos = EOF;
274
275 /* Move the get pointer, if requested. */
276 if (mode & _IOS_INPUT)
277 {
278 ssize_t base;
279 switch (dir)
280 {
281 case _IO_seek_set:
282 base = 0;
283 break;
284 case _IO_seek_cur:
285 base = (fp->_wide_data->_IO_read_ptr
286 - fp->_wide_data->_IO_read_base);
287 break;
288 default: /* case _IO_seek_end: */
289 base = cur_size;
290 break;
291 }
292 ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
293 if (offset < -base || offset > maxval)
294 {
295 __set_errno (EINVAL);
296 return EOF;
297 }
298 base += offset;
299 if (base > cur_size
300 && enlarge_userbuf (fp, offset: base, reading: 1) != 0)
301 return EOF;
302 fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
303 + base);
304 fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
305 + cur_size);
306 new_pos = offset;
307 }
308
309 /* Move the put pointer, if requested. */
310 if (mode & _IOS_OUTPUT)
311 {
312 ssize_t base;
313 switch (dir)
314 {
315 case _IO_seek_set:
316 base = 0;
317 break;
318 case _IO_seek_cur:
319 base = (fp->_wide_data->_IO_write_ptr
320 - fp->_wide_data->_IO_write_base);
321 break;
322 default: /* case _IO_seek_end: */
323 base = cur_size;
324 break;
325 }
326 ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
327 if (offset < -base || offset > maxval)
328 {
329 __set_errno (EINVAL);
330 return EOF;
331 }
332 base += offset;
333 if (base > cur_size
334 && enlarge_userbuf (fp, offset: base, reading: 0) != 0)
335 return EOF;
336 fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
337 + base);
338 new_pos = base;
339 }
340 }
341 return new_pos;
342}
343
344wint_t
345_IO_wstr_pbackfail (FILE *fp, wint_t c)
346{
347 if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
348 return WEOF;
349 return _IO_wdefault_pbackfail (fp, c);
350}
351
352void
353_IO_wstr_finish (FILE *fp, int dummy)
354{
355 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
356 free (ptr: fp->_wide_data->_IO_buf_base);
357 fp->_wide_data->_IO_buf_base = NULL;
358
359 _IO_wdefault_finish (fp, 0);
360}
361
362const struct _IO_jump_t _IO_wstr_jumps libio_vtable =
363{
364 JUMP_INIT_DUMMY,
365 JUMP_INIT(finish, _IO_wstr_finish),
366 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
367 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
368 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
369 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
370 JUMP_INIT(xsputn, _IO_wdefault_xsputn),
371 JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
372 JUMP_INIT(seekoff, _IO_wstr_seekoff),
373 JUMP_INIT(seekpos, _IO_default_seekpos),
374 JUMP_INIT(setbuf, _IO_default_setbuf),
375 JUMP_INIT(sync, _IO_default_sync),
376 JUMP_INIT(doallocate, _IO_wdefault_doallocate),
377 JUMP_INIT(read, _IO_default_read),
378 JUMP_INIT(write, _IO_default_write),
379 JUMP_INIT(seek, _IO_default_seek),
380 JUMP_INIT(close, _IO_default_close),
381 JUMP_INIT(stat, _IO_default_stat),
382 JUMP_INIT(showmanyc, _IO_default_showmanyc),
383 JUMP_INIT(imbue, _IO_default_imbue)
384};
385

source code of glibc/libio/wstrops.c