UnicodeData has precedence over EastAsianWidth
[glibc.git] / libio / wstrops.c
blobbb62fd6702c80113ba0b13e97e742f768bf8402b
1 /* Copyright (C) 1993-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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 <http://www.gnu.org/licenses/>.
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. */
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>
34 void
35 _IO_wstr_init_static (_IO_FILE *fp, wchar_t *ptr, _IO_size_t size,
36 wchar_t *pstart)
38 wchar_t *end;
40 if (size == 0)
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);
48 _IO_wsetb (fp, ptr, end, 0);
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)
55 fp->_wide_data->_IO_write_ptr = pstart;
56 fp->_wide_data->_IO_write_end = end;
57 fp->_wide_data->_IO_read_end = pstart;
59 else
61 fp->_wide_data->_IO_write_ptr = ptr;
62 fp->_wide_data->_IO_write_end = ptr;
63 fp->_wide_data->_IO_read_end = end;
65 /* A null _allocate_buffer function flags the strfile as being static. */
66 (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0;
69 _IO_wint_t
70 _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c)
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))
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;
82 pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
83 if (pos >= (_IO_size_t) (_IO_wblen (fp) + flush_only))
85 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* not allowed to enlarge */
86 return WEOF;
87 else
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 _IO_size_t new_size = 2 * old_wblen + 100;
94 if (__glibc_unlikely (new_size < old_wblen)
95 || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t)))
96 return EOF;
98 new_buf
99 = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
100 * sizeof (wchar_t));
101 if (new_buf == NULL)
103 /* __ferror(fp) = 1; */
104 return WEOF;
106 if (old_buf)
108 __wmemcpy (new_buf, old_buf, old_wblen);
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;
114 __wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
116 _IO_wsetb (fp, new_buf, new_buf + new_size, 1);
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);
126 fp->_wide_data->_IO_write_base = new_buf;
127 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
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;
139 _IO_wint_t
140 _IO_wstr_underflow (_IO_FILE *fp)
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))
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;
150 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
151 return *fp->_wide_data->_IO_read_ptr;
152 else
153 return WEOF;
157 /* The size of the valid part of the buffer. */
158 _IO_ssize_t
159 _IO_wstr_count (_IO_FILE *fp)
161 struct _IO_wide_data *wd = fp->_wide_data;
163 return ((wd->_IO_write_ptr > wd->_IO_read_end
164 ? wd->_IO_write_ptr : wd->_IO_read_end)
165 - wd->_IO_read_base);
169 static int
170 enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
172 if ((_IO_ssize_t) offset <= _IO_wblen (fp))
173 return 0;
175 struct _IO_wide_data *wd = fp->_wide_data;
177 _IO_ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
179 /* Try to enlarge the buffer. */
180 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
181 /* User-provided buffer. */
182 return 1;
184 _IO_size_t newsize = offset + 100;
185 if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
186 return 1;
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;
195 if (oldbuf != NULL)
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;
204 _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
206 if (reading)
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);
213 wd->_IO_read_base = newbuf;
214 wd->_IO_read_end = wd->_IO_buf_end;
216 else
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);
223 wd->_IO_write_base = newbuf;
224 wd->_IO_write_end = wd->_IO_buf_end;
227 /* Clear the area between the last write position and th
228 new position. */
229 assert (offset >= oldend);
230 if (reading)
231 __wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
232 else
233 __wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
235 return 0;
238 static void
239 _IO_wstr_switch_to_get_mode (_IO_FILE *fp)
241 if (_IO_in_backup (fp))
242 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
243 else
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;
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;
252 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
255 _IO_off64_t
256 _IO_wstr_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
258 _IO_off64_t new_pos;
260 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
261 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
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);
269 if (mode == 0)
271 new_pos = (fp->_wide_data->_IO_write_ptr
272 - fp->_wide_data->_IO_write_base);
274 else
276 _IO_ssize_t cur_size = _IO_wstr_count (fp);
277 new_pos = EOF;
279 /* Move the get pointer, if requested. */
280 if (mode & _IOS_INPUT)
282 _IO_ssize_t base;
283 switch (dir)
285 case _IO_seek_set:
286 base = 0;
287 break;
288 case _IO_seek_cur:
289 base = (fp->_wide_data->_IO_read_ptr
290 - fp->_wide_data->_IO_read_base);
291 break;
292 default: /* case _IO_seek_end: */
293 base = cur_size;
294 break;
296 _IO_ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
297 if (offset < -base || offset > maxval)
299 __set_errno (EINVAL);
300 return EOF;
302 base += offset;
303 if (base > cur_size
304 && enlarge_userbuf (fp, base, 1) != 0)
305 return EOF;
306 fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
307 + base);
308 fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
309 + cur_size);
310 new_pos = offset;
313 /* Move the put pointer, if requested. */
314 if (mode & _IOS_OUTPUT)
316 _IO_ssize_t base;
317 switch (dir)
319 case _IO_seek_set:
320 base = 0;
321 break;
322 case _IO_seek_cur:
323 base = (fp->_wide_data->_IO_write_ptr
324 - fp->_wide_data->_IO_write_base);
325 break;
326 default: /* case _IO_seek_end: */
327 base = cur_size;
328 break;
330 _IO_ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
331 if (offset < -base || offset > maxval)
333 __set_errno (EINVAL);
334 return EOF;
336 base += offset;
337 if (base > cur_size
338 && enlarge_userbuf (fp, base, 0) != 0)
339 return EOF;
340 fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
341 + base);
342 new_pos = base;
345 return new_pos;
348 _IO_wint_t
349 _IO_wstr_pbackfail (_IO_FILE *fp, _IO_wint_t c)
351 if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
352 return WEOF;
353 return _IO_wdefault_pbackfail (fp, c);
356 void
357 _IO_wstr_finish (_IO_FILE *fp, int dummy)
359 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
360 (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base);
361 fp->_wide_data->_IO_buf_base = NULL;
363 _IO_wdefault_finish (fp, 0);
366 const struct _IO_jump_t _IO_wstr_jumps libio_vtable =
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),
372 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
373 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
374 JUMP_INIT(xsputn, _IO_wdefault_xsputn),
375 JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
376 JUMP_INIT(seekoff, _IO_wstr_seekoff),
377 JUMP_INIT(seekpos, _IO_default_seekpos),
378 JUMP_INIT(setbuf, _IO_default_setbuf),
379 JUMP_INIT(sync, _IO_default_sync),
380 JUMP_INIT(doallocate, _IO_wdefault_doallocate),
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)