]> git.ipfire.org Git - thirdparty/glibc.git/blame - libio/wstrops.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / libio / wstrops.c
CommitLineData
04277e02 1/* Copyright (C) 1993-2019 Free Software Foundation, Inc.
41bdb6e2 2 This file is part of the GNU C Library.
d64b6ad0 3
41bdb6e2
AJ
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.
d64b6ad0 8
41bdb6e2
AJ
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
d64b6ad0 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2
AJ
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
59ba27a6 15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>.
41bdb6e2
AJ
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. */
d64b6ad0 26
107b8a92 27#include <assert.h>
d64b6ad0
UD
28#include "strfile.h"
29#include "libioP.h"
30#include <string.h>
31#include <wchar.h>
0d875352 32#include <stdio_ext.h>
d64b6ad0 33
d64b6ad0 34void
9964a145 35_IO_wstr_init_static (FILE *fp, wchar_t *ptr, size_t size,
9dd346ff 36 wchar_t *pstart)
d64b6ad0 37{
40a54e4d 38 wchar_t *end;
b2637a22 39
d64b6ad0 40 if (size == 0)
40a54e4d 41 end = ptr + __wcslen (ptr);
9964a145 42 else if ((size_t) ptr + size * sizeof (wchar_t) > (size_t) ptr)
40a54e4d
UD
43 end = ptr + size;
44 else
45 /* Even for misaligned ptr make sure there is integral number of wide
46 characters. */
9964a145 47 end = ptr + (-1 - (size_t) ptr) / sizeof (wchar_t);
d18ea0c5 48 _IO_wsetb (fp, ptr, end, 0);
d64b6ad0
UD
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;
40a54e4d 56 fp->_wide_data->_IO_write_end = end;
d64b6ad0
UD
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;
40a54e4d 63 fp->_wide_data->_IO_read_end = end;
d64b6ad0
UD
64 }
65 /* A null _allocate_buffer function flags the strfile as being static. */
4e8a6346 66 (((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0;
d64b6ad0
UD
67}
68
9964a145
ZW
69wint_t
70_IO_wstr_overflow (FILE *fp, wint_t c)
d64b6ad0
UD
71{
72 int flush_only = c == WEOF;
9964a145 73 size_t pos;
d64b6ad0
UD
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 }
107b8a92 82 pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
9964a145 83 if (pos >= (size_t) (_IO_wblen (fp) + flush_only))
d64b6ad0 84 {
1e88bd0f 85 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* not allowed to enlarge */
d64b6ad0
UD
86 return WEOF;
87 else
88 {
89 wchar_t *new_buf;
90 wchar_t *old_buf = fp->_wide_data->_IO_buf_base;
107b8a92 91 size_t old_wblen = _IO_wblen (fp);
9964a145 92 size_t new_size = 2 * old_wblen + 100;
bdf1ff05
PP
93
94 if (__glibc_unlikely (new_size < old_wblen)
95 || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t)))
107b8a92 96 return EOF;
bdf1ff05 97
4e8a6346 98 new_buf = malloc (new_size * sizeof (wchar_t));
d64b6ad0
UD
99 if (new_buf == NULL)
100 {
101 /* __ferror(fp) = 1; */
102 return WEOF;
103 }
104 if (old_buf)
105 {
107b8a92 106 __wmemcpy (new_buf, old_buf, old_wblen);
4e8a6346 107 free (old_buf);
d64b6ad0
UD
108 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
109 fp->_wide_data->_IO_buf_base = NULL;
110 }
107b8a92 111
cfac4de6 112 __wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
107b8a92 113
d18ea0c5 114 _IO_wsetb (fp, new_buf, new_buf + new_size, 1);
d64b6ad0
UD
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
107b8a92 136
9964a145
ZW
137wint_t
138_IO_wstr_underflow (FILE *fp)
d64b6ad0
UD
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
0923a2c8 151 return WEOF;
d64b6ad0
UD
152}
153
a334319f 154
107b8a92 155/* The size of the valid part of the buffer. */
9964a145
ZW
156ssize_t
157_IO_wstr_count (FILE *fp)
d64b6ad0 158{
107b8a92
UD
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);
d64b6ad0
UD
164}
165
107b8a92
UD
166
167static int
9964a145 168enlarge_userbuf (FILE *fp, off64_t offset, int reading)
107b8a92 169{
9964a145 170 if ((ssize_t) offset <= _IO_wblen (fp))
107b8a92
UD
171 return 0;
172
173 struct _IO_wide_data *wd = fp->_wide_data;
174
9964a145 175 ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
107b8a92
UD
176
177 /* Try to enlarge the buffer. */
1e88bd0f 178 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
107b8a92
UD
179 /* User-provided buffer. */
180 return 1;
181
9964a145 182 size_t newsize = offset + 100;
bdf1ff05
PP
183 if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
184 return 1;
185
107b8a92 186 wchar_t *oldbuf = wd->_IO_buf_base;
4e8a6346 187 wchar_t *newbuf = malloc (newsize * sizeof (wchar_t));
107b8a92
UD
188 if (newbuf == NULL)
189 return 1;
190
191 if (oldbuf != NULL)
192 {
193 __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
4e8a6346 194 free (oldbuf);
107b8a92
UD
195 /* Make sure _IO_setb won't try to delete
196 _IO_buf_base. */
197 wd->_IO_buf_base = NULL;
198 }
199
d18ea0c5 200 _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
107b8a92
UD
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)
cfac4de6 227 __wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
107b8a92 228 else
cfac4de6 229 __wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
107b8a92
UD
230
231 return 0;
232}
233
645f97ce 234static void
9964a145 235_IO_wstr_switch_to_get_mode (FILE *fp)
645f97ce
AZ
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}
107b8a92 250
9964a145
ZW
251off64_t
252_IO_wstr_seekoff (FILE *fp, off64_t offset, int dir, int mode)
d64b6ad0 253{
9964a145 254 off64_t new_pos;
d64b6ad0
UD
255
256 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
257 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
258
a04549c1
JM
259 bool was_writing = ((fp->_wide_data->_IO_write_ptr
260 > fp->_wide_data->_IO_write_base)
645f97ce
AZ
261 || _IO_in_put_mode (fp));
262 if (was_writing)
263 _IO_wstr_switch_to_get_mode (fp);
264
d64b6ad0
UD
265 if (mode == 0)
266 {
645f97ce
AZ
267 new_pos = (fp->_wide_data->_IO_write_ptr
268 - fp->_wide_data->_IO_write_base);
d64b6ad0
UD
269 }
270 else
271 {
9964a145 272 ssize_t cur_size = _IO_wstr_count (fp);
d64b6ad0
UD
273 new_pos = EOF;
274
275 /* Move the get pointer, if requested. */
276 if (mode & _IOS_INPUT)
277 {
9964a145 278 ssize_t base;
d64b6ad0
UD
279 switch (dir)
280 {
645f97ce
AZ
281 case _IO_seek_set:
282 base = 0;
d64b6ad0
UD
283 break;
284 case _IO_seek_cur:
645f97ce
AZ
285 base = (fp->_wide_data->_IO_read_ptr
286 - fp->_wide_data->_IO_read_base);
d64b6ad0 287 break;
645f97ce
AZ
288 default: /* case _IO_seek_end: */
289 base = cur_size;
d64b6ad0
UD
290 break;
291 }
9964a145 292 ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
645f97ce
AZ
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, base, 1) != 0)
d64b6ad0
UD
301 return EOF;
302 fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
645f97ce 303 + base);
d64b6ad0
UD
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 {
9964a145 312 ssize_t base;
d64b6ad0
UD
313 switch (dir)
314 {
645f97ce
AZ
315 case _IO_seek_set:
316 base = 0;
d64b6ad0
UD
317 break;
318 case _IO_seek_cur:
645f97ce
AZ
319 base = (fp->_wide_data->_IO_write_ptr
320 - fp->_wide_data->_IO_write_base);
d64b6ad0 321 break;
645f97ce
AZ
322 default: /* case _IO_seek_end: */
323 base = cur_size;
d64b6ad0
UD
324 break;
325 }
9964a145 326 ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
645f97ce
AZ
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, base, 0) != 0)
d64b6ad0
UD
335 return EOF;
336 fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
645f97ce
AZ
337 + base);
338 new_pos = base;
d64b6ad0
UD
339 }
340 }
341 return new_pos;
342}
343
9964a145
ZW
344wint_t
345_IO_wstr_pbackfail (FILE *fp, wint_t c)
d64b6ad0 346{
6dd67bd5 347 if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
d64b6ad0 348 return WEOF;
d18ea0c5 349 return _IO_wdefault_pbackfail (fp, c);
d64b6ad0
UD
350}
351
352void
9964a145 353_IO_wstr_finish (FILE *fp, int dummy)
d64b6ad0 354{
1e88bd0f 355 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
4e8a6346 356 free (fp->_wide_data->_IO_buf_base);
d64b6ad0
UD
357 fp->_wide_data->_IO_buf_base = NULL;
358
d18ea0c5 359 _IO_wdefault_finish (fp, 0);
d64b6ad0
UD
360}
361
db3476af 362const struct _IO_jump_t _IO_wstr_jumps libio_vtable =
d64b6ad0
UD
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),
d18ea0c5 368 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
d64b6ad0 369 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
d18ea0c5
AS
370 JUMP_INIT(xsputn, _IO_wdefault_xsputn),
371 JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
d64b6ad0
UD
372 JUMP_INIT(seekoff, _IO_wstr_seekoff),
373 JUMP_INIT(seekpos, _IO_default_seekpos),
bff334e0 374 JUMP_INIT(setbuf, _IO_default_setbuf),
d64b6ad0 375 JUMP_INIT(sync, _IO_default_sync),
d18ea0c5 376 JUMP_INIT(doallocate, _IO_wdefault_doallocate),
d64b6ad0
UD
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};