Setup LOCPATH for tst-ftell-active-handler and tst-ftell-partial-wide in libio
[platform/upstream/glibc.git] / libio / wstrops.c
1 /* Copyright (C) 1993-2014 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    <http://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
34 void
35 _IO_wstr_init_static (fp, ptr, size, pstart)
36      _IO_FILE *fp;
37      wchar_t *ptr;
38      _IO_size_t size;
39      wchar_t *pstart;
40 {
41   wchar_t *end;
42
43   if (size == 0)
44     end = ptr + __wcslen (ptr);
45   else if ((_IO_size_t) ptr + size * sizeof (wchar_t) > (_IO_size_t) ptr)
46     end = ptr + size;
47   else
48     /* Even for misaligned ptr make sure there is integral number of wide
49        characters.  */
50     end = ptr + (-1 - (_IO_size_t) ptr) / sizeof (wchar_t);
51   _IO_wsetb (fp, ptr, end, 0);
52
53   fp->_wide_data->_IO_write_base = ptr;
54   fp->_wide_data->_IO_read_base = ptr;
55   fp->_wide_data->_IO_read_ptr = ptr;
56   if (pstart)
57     {
58       fp->_wide_data->_IO_write_ptr = pstart;
59       fp->_wide_data->_IO_write_end = end;
60       fp->_wide_data->_IO_read_end = pstart;
61     }
62   else
63     {
64       fp->_wide_data->_IO_write_ptr = ptr;
65       fp->_wide_data->_IO_write_end = ptr;
66       fp->_wide_data->_IO_read_end = end;
67     }
68   /* A null _allocate_buffer function flags the strfile as being static. */
69   (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0;
70 }
71
72 _IO_wint_t
73 _IO_wstr_overflow (fp, c)
74      _IO_FILE *fp;
75      _IO_wint_t c;
76 {
77   int flush_only = c == WEOF;
78   _IO_size_t pos;
79   if (fp->_flags & _IO_NO_WRITES)
80       return flush_only ? 0 : WEOF;
81   if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
82     {
83       fp->_flags |= _IO_CURRENTLY_PUTTING;
84       fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
85       fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
86     }
87   pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
88   if (pos >= (_IO_size_t) (_IO_wblen (fp) + flush_only))
89     {
90       if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* not allowed to enlarge */
91         return WEOF;
92       else
93         {
94           wchar_t *new_buf;
95           wchar_t *old_buf = fp->_wide_data->_IO_buf_base;
96           size_t old_wblen = _IO_wblen (fp);
97           _IO_size_t new_size = 2 * old_wblen + 100;
98           if (new_size < old_wblen)
99             return EOF;
100           new_buf
101             = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
102                                                                         * sizeof (wchar_t));
103           if (new_buf == NULL)
104             {
105               /*          __ferror(fp) = 1; */
106               return WEOF;
107             }
108           if (old_buf)
109             {
110               __wmemcpy (new_buf, old_buf, old_wblen);
111               (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
112               /* Make sure _IO_setb won't try to delete _IO_buf_base. */
113               fp->_wide_data->_IO_buf_base = NULL;
114             }
115
116           wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
117
118           _IO_wsetb (fp, new_buf, new_buf + new_size, 1);
119           fp->_wide_data->_IO_read_base =
120             new_buf + (fp->_wide_data->_IO_read_base - old_buf);
121           fp->_wide_data->_IO_read_ptr =
122             new_buf + (fp->_wide_data->_IO_read_ptr - old_buf);
123           fp->_wide_data->_IO_read_end =
124             new_buf + (fp->_wide_data->_IO_read_end - old_buf);
125           fp->_wide_data->_IO_write_ptr =
126             new_buf + (fp->_wide_data->_IO_write_ptr - old_buf);
127
128           fp->_wide_data->_IO_write_base = new_buf;
129           fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
130         }
131     }
132
133   if (!flush_only)
134     *fp->_wide_data->_IO_write_ptr++ = c;
135   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
136     fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
137   return c;
138 }
139
140
141 _IO_wint_t
142 _IO_wstr_underflow (fp)
143      _IO_FILE *fp;
144 {
145   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
146     fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
147   if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
148     {
149       fp->_flags &= ~_IO_CURRENTLY_PUTTING;
150       fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
151       fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
152     }
153   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
154     return *fp->_wide_data->_IO_read_ptr;
155   else
156     return WEOF;
157 }
158
159
160 /* The size of the valid part of the buffer.  */
161 _IO_ssize_t
162 _IO_wstr_count (fp)
163      _IO_FILE *fp;
164 {
165   struct _IO_wide_data *wd = fp->_wide_data;
166
167   return ((wd->_IO_write_ptr > wd->_IO_read_end
168            ? wd->_IO_write_ptr : wd->_IO_read_end)
169           - wd->_IO_read_base);
170 }
171
172
173 static int
174 enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
175 {
176   if ((_IO_ssize_t) offset <= _IO_blen (fp))
177     return 0;
178
179   struct _IO_wide_data *wd = fp->_wide_data;
180
181   _IO_ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
182
183   /* Try to enlarge the buffer.  */
184   if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
185     /* User-provided buffer.  */
186     return 1;
187
188   _IO_size_t newsize = offset + 100;
189   wchar_t *oldbuf = wd->_IO_buf_base;
190   wchar_t *newbuf
191     = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize
192                                                                 * sizeof (wchar_t));
193   if (newbuf == NULL)
194     return 1;
195
196   if (oldbuf != NULL)
197     {
198       __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
199       (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
200       /* Make sure _IO_setb won't try to delete
201          _IO_buf_base. */
202       wd->_IO_buf_base = NULL;
203     }
204
205   _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
206
207   if (reading)
208     {
209       wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf);
210       wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
211       wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf);
212       wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
213
214       wd->_IO_read_base = newbuf;
215       wd->_IO_read_end = wd->_IO_buf_end;
216     }
217   else
218     {
219       wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf);
220       wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
221       wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf);
222       wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
223
224       wd->_IO_write_base = newbuf;
225       wd->_IO_write_end = wd->_IO_buf_end;
226     }
227
228   /* Clear the area between the last write position and th
229      new position.  */
230   assert (offset >= oldend);
231   if (reading)
232     wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
233   else
234     wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
235
236   return 0;
237 }
238
239
240 _IO_off64_t
241 _IO_wstr_seekoff (fp, offset, dir, mode)
242      _IO_FILE *fp;
243      _IO_off64_t offset;
244      int dir;
245      int mode;
246 {
247   _IO_off64_t new_pos;
248
249   if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
250     mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
251
252   if (mode == 0)
253     {
254       /* Don't move any pointers. But there is no clear indication what
255          mode FP is in. Let's guess. */
256       if (fp->_IO_file_flags & _IO_NO_WRITES)
257         new_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
258       else
259         new_pos = (fp->_wide_data->_IO_write_ptr
260                    - fp->_wide_data->_IO_write_base);
261     }
262   else
263     {
264       _IO_ssize_t cur_size = _IO_wstr_count (fp);
265       new_pos = EOF;
266
267       /* Move the get pointer, if requested. */
268       if (mode & _IOS_INPUT)
269         {
270           switch (dir)
271             {
272             case _IO_seek_end:
273               offset += cur_size;
274               break;
275             case _IO_seek_cur:
276               offset += (fp->_wide_data->_IO_read_ptr
277                          - fp->_wide_data->_IO_read_base);
278               break;
279             default: /* case _IO_seek_set: */
280               break;
281             }
282           if (offset < 0)
283             return EOF;
284           if ((_IO_ssize_t) offset > cur_size
285               && enlarge_userbuf (fp, offset, 1) != 0)
286             return EOF;
287           fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
288                                           + offset);
289           fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
290                                           + cur_size);
291           new_pos = offset;
292         }
293
294       /* Move the put pointer, if requested. */
295       if (mode & _IOS_OUTPUT)
296         {
297           switch (dir)
298             {
299             case _IO_seek_end:
300               offset += cur_size;
301               break;
302             case _IO_seek_cur:
303               offset += (fp->_wide_data->_IO_write_ptr
304                          - fp->_wide_data->_IO_write_base);
305               break;
306             default: /* case _IO_seek_set: */
307               break;
308             }
309           if (offset < 0)
310             return EOF;
311           if ((_IO_ssize_t) offset > cur_size
312               && enlarge_userbuf (fp, offset, 0) != 0)
313             return EOF;
314           fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
315                                            + offset);
316           new_pos = offset;
317         }
318     }
319   return new_pos;
320 }
321
322 _IO_wint_t
323 _IO_wstr_pbackfail (fp, c)
324      _IO_FILE *fp;
325      _IO_wint_t c;
326 {
327   if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
328     return WEOF;
329   return _IO_wdefault_pbackfail (fp, c);
330 }
331
332 void
333 _IO_wstr_finish (fp, dummy)
334      _IO_FILE *fp;
335      int dummy;
336 {
337   if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
338     (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base);
339   fp->_wide_data->_IO_buf_base = NULL;
340
341   _IO_wdefault_finish (fp, 0);
342 }
343
344 const struct _IO_jump_t _IO_wstr_jumps =
345 {
346   JUMP_INIT_DUMMY,
347   JUMP_INIT(finish, _IO_wstr_finish),
348   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
349   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
350   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
351   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
352   JUMP_INIT(xsputn, _IO_wdefault_xsputn),
353   JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
354   JUMP_INIT(seekoff, _IO_wstr_seekoff),
355   JUMP_INIT(seekpos, _IO_default_seekpos),
356   JUMP_INIT(setbuf, _IO_default_setbuf),
357   JUMP_INIT(sync, _IO_default_sync),
358   JUMP_INIT(doallocate, _IO_wdefault_doallocate),
359   JUMP_INIT(read, _IO_default_read),
360   JUMP_INIT(write, _IO_default_write),
361   JUMP_INIT(seek, _IO_default_seek),
362   JUMP_INIT(close, _IO_default_close),
363   JUMP_INIT(stat, _IO_default_stat),
364   JUMP_INIT(showmanyc, _IO_default_showmanyc),
365   JUMP_INIT(imbue, _IO_default_imbue)
366 };