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