]> git.ipfire.org Git - thirdparty/glibc.git/blame - libio/wstrops.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / libio / wstrops.c
CommitLineData
688903eb 1/* Copyright (C) 1993-2018 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
PE
15 License along with the GNU C Library; if not, see
16 <http://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
9dd346ff
JM
35_IO_wstr_init_static (_IO_FILE *fp, wchar_t *ptr, _IO_size_t size,
36 wchar_t *pstart)
d64b6ad0 37{
40a54e4d 38 wchar_t *end;
b2637a22 39
d64b6ad0 40 if (size == 0)
40a54e4d
UD
41 end = ptr + __wcslen (ptr);
42 else if ((_IO_size_t) ptr + size * sizeof (wchar_t) > (_IO_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 - (_IO_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. */
107b8a92 66 (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0;
d64b6ad0
UD
67}
68
d64b6ad0 69_IO_wint_t
9dd346ff 70_IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c)
d64b6ad0
UD
71{
72 int flush_only = c == WEOF;
73 _IO_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 }
107b8a92 82 pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
d64b6ad0
UD
83 if (pos >= (_IO_size_t) (_IO_wblen (fp) + flush_only))
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
UD
91 size_t old_wblen = _IO_wblen (fp);
92 _IO_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
d64b6ad0
UD
98 new_buf
99 = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
100 * sizeof (wchar_t));
101 if (new_buf == NULL)
102 {
103 /* __ferror(fp) = 1; */
104 return WEOF;
105 }
106 if (old_buf)
107 {
107b8a92 108 __wmemcpy (new_buf, old_buf, old_wblen);
d64b6ad0
UD
109 (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
110 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
111 fp->_wide_data->_IO_buf_base = NULL;
112 }
107b8a92 113
cfac4de6 114 __wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
107b8a92 115
d18ea0c5 116 _IO_wsetb (fp, new_buf, new_buf + new_size, 1);
d64b6ad0
UD
117 fp->_wide_data->_IO_read_base =
118 new_buf + (fp->_wide_data->_IO_read_base - old_buf);
119 fp->_wide_data->_IO_read_ptr =
120 new_buf + (fp->_wide_data->_IO_read_ptr - old_buf);
121 fp->_wide_data->_IO_read_end =
122 new_buf + (fp->_wide_data->_IO_read_end - old_buf);
123 fp->_wide_data->_IO_write_ptr =
124 new_buf + (fp->_wide_data->_IO_write_ptr - old_buf);
125
126 fp->_wide_data->_IO_write_base = new_buf;
127 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
128 }
129 }
130
131 if (!flush_only)
132 *fp->_wide_data->_IO_write_ptr++ = c;
133 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
134 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
135 return c;
136}
137
107b8a92 138
d64b6ad0 139_IO_wint_t
9dd346ff 140_IO_wstr_underflow (_IO_FILE *fp)
d64b6ad0
UD
141{
142 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
143 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
144 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
145 {
146 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
147 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
148 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
149 }
150 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
151 return *fp->_wide_data->_IO_read_ptr;
152 else
0923a2c8 153 return WEOF;
d64b6ad0
UD
154}
155
a334319f 156
107b8a92 157/* The size of the valid part of the buffer. */
d64b6ad0 158_IO_ssize_t
9dd346ff 159_IO_wstr_count (_IO_FILE *fp)
d64b6ad0 160{
107b8a92
UD
161 struct _IO_wide_data *wd = fp->_wide_data;
162
163 return ((wd->_IO_write_ptr > wd->_IO_read_end
164 ? wd->_IO_write_ptr : wd->_IO_read_end)
165 - wd->_IO_read_base);
d64b6ad0
UD
166}
167
107b8a92
UD
168
169static int
170enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
171{
645f97ce 172 if ((_IO_ssize_t) offset <= _IO_wblen (fp))
107b8a92
UD
173 return 0;
174
175 struct _IO_wide_data *wd = fp->_wide_data;
176
177 _IO_ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
178
179 /* Try to enlarge the buffer. */
1e88bd0f 180 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
107b8a92
UD
181 /* User-provided buffer. */
182 return 1;
183
184 _IO_size_t newsize = offset + 100;
bdf1ff05
PP
185 if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
186 return 1;
187
107b8a92
UD
188 wchar_t *oldbuf = wd->_IO_buf_base;
189 wchar_t *newbuf
190 = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize
191 * sizeof (wchar_t));
192 if (newbuf == NULL)
193 return 1;
194
195 if (oldbuf != NULL)
196 {
197 __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
198 (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
199 /* Make sure _IO_setb won't try to delete
200 _IO_buf_base. */
201 wd->_IO_buf_base = NULL;
202 }
203
d18ea0c5 204 _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
107b8a92
UD
205
206 if (reading)
207 {
208 wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf);
209 wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
210 wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf);
211 wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
212
213 wd->_IO_read_base = newbuf;
214 wd->_IO_read_end = wd->_IO_buf_end;
215 }
216 else
217 {
218 wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf);
219 wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
220 wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf);
221 wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
222
223 wd->_IO_write_base = newbuf;
224 wd->_IO_write_end = wd->_IO_buf_end;
225 }
226
227 /* Clear the area between the last write position and th
228 new position. */
229 assert (offset >= oldend);
230 if (reading)
cfac4de6 231 __wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
107b8a92 232 else
cfac4de6 233 __wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
107b8a92
UD
234
235 return 0;
236}
237
645f97ce
AZ
238static void
239_IO_wstr_switch_to_get_mode (_IO_FILE *fp)
240{
241 if (_IO_in_backup (fp))
242 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
243 else
244 {
245 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
246 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
247 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
248 }
249 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
250 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
251
252 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
253}
107b8a92 254
d64b6ad0 255_IO_off64_t
9dd346ff 256_IO_wstr_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
d64b6ad0
UD
257{
258 _IO_off64_t new_pos;
259
260 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
261 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
262
645f97ce
AZ
263 bool was_writing = (fp->_wide_data->_IO_write_ptr >
264 fp->_wide_data->_IO_write_base
265 || _IO_in_put_mode (fp));
266 if (was_writing)
267 _IO_wstr_switch_to_get_mode (fp);
268
d64b6ad0
UD
269 if (mode == 0)
270 {
645f97ce
AZ
271 new_pos = (fp->_wide_data->_IO_write_ptr
272 - fp->_wide_data->_IO_write_base);
d64b6ad0
UD
273 }
274 else
275 {
276 _IO_ssize_t cur_size = _IO_wstr_count (fp);
277 new_pos = EOF;
278
279 /* Move the get pointer, if requested. */
280 if (mode & _IOS_INPUT)
281 {
645f97ce 282 _IO_ssize_t base;
d64b6ad0
UD
283 switch (dir)
284 {
645f97ce
AZ
285 case _IO_seek_set:
286 base = 0;
d64b6ad0
UD
287 break;
288 case _IO_seek_cur:
645f97ce
AZ
289 base = (fp->_wide_data->_IO_read_ptr
290 - fp->_wide_data->_IO_read_base);
d64b6ad0 291 break;
645f97ce
AZ
292 default: /* case _IO_seek_end: */
293 base = cur_size;
d64b6ad0
UD
294 break;
295 }
645f97ce
AZ
296 _IO_ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
297 if (offset < -base || offset > maxval)
298 {
299 __set_errno (EINVAL);
300 return EOF;
301 }
302 base += offset;
303 if (base > cur_size
304 && enlarge_userbuf (fp, base, 1) != 0)
d64b6ad0
UD
305 return EOF;
306 fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
645f97ce 307 + base);
d64b6ad0
UD
308 fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
309 + cur_size);
310 new_pos = offset;
311 }
312
313 /* Move the put pointer, if requested. */
314 if (mode & _IOS_OUTPUT)
315 {
645f97ce 316 _IO_ssize_t base;
d64b6ad0
UD
317 switch (dir)
318 {
645f97ce
AZ
319 case _IO_seek_set:
320 base = 0;
d64b6ad0
UD
321 break;
322 case _IO_seek_cur:
645f97ce
AZ
323 base = (fp->_wide_data->_IO_write_ptr
324 - fp->_wide_data->_IO_write_base);
d64b6ad0 325 break;
645f97ce
AZ
326 default: /* case _IO_seek_end: */
327 base = cur_size;
d64b6ad0
UD
328 break;
329 }
645f97ce
AZ
330 _IO_ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
331 if (offset < -base || offset > maxval)
332 {
333 __set_errno (EINVAL);
334 return EOF;
335 }
336 base += offset;
337 if (base > cur_size
338 && enlarge_userbuf (fp, base, 0) != 0)
d64b6ad0
UD
339 return EOF;
340 fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
645f97ce
AZ
341 + base);
342 new_pos = base;
d64b6ad0
UD
343 }
344 }
345 return new_pos;
346}
347
348_IO_wint_t
9dd346ff 349_IO_wstr_pbackfail (_IO_FILE *fp, _IO_wint_t c)
d64b6ad0 350{
6dd67bd5 351 if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
d64b6ad0 352 return WEOF;
d18ea0c5 353 return _IO_wdefault_pbackfail (fp, c);
d64b6ad0
UD
354}
355
356void
9dd346ff 357_IO_wstr_finish (_IO_FILE *fp, int dummy)
d64b6ad0 358{
1e88bd0f 359 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
d64b6ad0
UD
360 (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base);
361 fp->_wide_data->_IO_buf_base = NULL;
362
d18ea0c5 363 _IO_wdefault_finish (fp, 0);
d64b6ad0
UD
364}
365
db3476af 366const struct _IO_jump_t _IO_wstr_jumps libio_vtable =
d64b6ad0
UD
367{
368 JUMP_INIT_DUMMY,
369 JUMP_INIT(finish, _IO_wstr_finish),
370 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
371 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
d18ea0c5 372 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
d64b6ad0 373 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
d18ea0c5
AS
374 JUMP_INIT(xsputn, _IO_wdefault_xsputn),
375 JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
d64b6ad0
UD
376 JUMP_INIT(seekoff, _IO_wstr_seekoff),
377 JUMP_INIT(seekpos, _IO_default_seekpos),
bff334e0 378 JUMP_INIT(setbuf, _IO_default_setbuf),
d64b6ad0 379 JUMP_INIT(sync, _IO_default_sync),
d18ea0c5 380 JUMP_INIT(doallocate, _IO_wdefault_doallocate),
d64b6ad0
UD
381 JUMP_INIT(read, _IO_default_read),
382 JUMP_INIT(write, _IO_default_write),
383 JUMP_INIT(seek, _IO_default_seek),
384 JUMP_INIT(close, _IO_default_close),
385 JUMP_INIT(stat, _IO_default_stat),
386 JUMP_INIT(showmanyc, _IO_default_showmanyc),
387 JUMP_INIT(imbue, _IO_default_imbue)
388};