Update.
[platform/upstream/glibc.git] / libio / wstrops.c
1 /* Copyright (C) 1993,1997,1998,1999,2001,2002 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 "strfile.h"
29 #include "libioP.h"
30 #include <string.h>
31 #include <wchar.h>
32 #include <stdio_ext.h>
33
34 #if 0
35 /* The following definitions are for exposition only.
36    They map the terminology used in the ANSI/ISO C++ draft standard
37    to the implementation. */
38
39 /* allocated:  set  when a dynamic array object has been allocated, and
40    hence should be freed by the destructor for the strstreambuf object. */
41 #define ALLOCATED(FP) ((FP)->_f._IO_buf_base && DYNAMIC(FP))
42
43 /* constant:  set when the array object has const elements,
44    so the output sequence cannot be written. */
45 #define CONSTANT(FP) ((FP)->_f._IO_file_flags & _IO_NO_WRITES)
46
47 /* alsize:  the suggested minimum size for a dynamic array object. */
48 #define ALSIZE(FP) ??? /* not stored */
49
50 /* palloc: points to the function to call to allocate a dynamic array object.*/
51 #define PALLOC(FP) \
52   ((FP)->_s._allocate_buffer == default_alloc ? 0 : (FP)->_s._allocate_buffer)
53
54 /* pfree: points  to  the  function  to call to free a dynamic array object. */
55 #define PFREE(FP) \
56   ((FP)->_s._free_buffer == default_free ? 0 : (FP)->_s._free_buffer)
57
58 #endif
59
60 #ifdef TODO
61 /* An "unbounded buffer" is when a buffer is supplied, but with no
62    specified length.  An example is the buffer argument to sprintf.
63    */
64 #endif
65
66 void
67 _IO_wstr_init_static (fp, ptr, size, pstart)
68      _IO_FILE *fp;
69      wchar_t *ptr;
70      int size;
71      wchar_t *pstart;
72 {
73   if (size == 0)
74     size = __wcslen (ptr);
75   else if (size < 0)
76     {
77       /* If size is negative 'the characters are assumed to
78          continue indefinitely.'  This is kind of messy ... */
79       int s;
80       size = 512;
81       /* Try increasing powers of 2, as long as we don't wrap around. */
82       for (; s = 2*size, s > 0 && ptr + s > ptr && s < 0x4000000L; )
83         size = s;
84       /* Try increasing size as much as we can without wrapping around. */
85       for (s = size >> 1; s > 0; s >>= 1)
86         {
87           if (ptr + size + s > ptr)
88             size += s;
89         }
90     }
91   INTUSE(_IO_wsetb) (fp, ptr, ptr + size, 0);
92
93   fp->_wide_data->_IO_write_base = ptr;
94   fp->_wide_data->_IO_read_base = ptr;
95   fp->_wide_data->_IO_read_ptr = ptr;
96   if (pstart)
97     {
98       fp->_wide_data->_IO_write_ptr = pstart;
99       fp->_wide_data->_IO_write_end = ptr + size;
100       fp->_wide_data->_IO_read_end = pstart;
101     }
102   else
103     {
104       fp->_wide_data->_IO_write_ptr = ptr;
105       fp->_wide_data->_IO_write_end = ptr;
106       fp->_wide_data->_IO_read_end = ptr + size;
107     }
108   /* A null _allocate_buffer function flags the strfile as being static. */
109   (((_IO_strfile *) fp)->_s._allocate_buffer) =  (_IO_alloc_type)0;
110 }
111
112 void
113 _IO_wstr_init_readonly (fp, ptr, size)
114      _IO_FILE *fp;
115      const char *ptr;
116      int size;
117 {
118   _IO_wstr_init_static (fp, (wchar_t *) ptr, size, NULL);
119   fp->_IO_file_flags |= _IO_NO_WRITES;
120 }
121
122 _IO_wint_t
123 _IO_wstr_overflow (fp, c)
124      _IO_FILE *fp;
125      _IO_wint_t c;
126 {
127   int flush_only = c == WEOF;
128   _IO_size_t pos;
129   if (fp->_flags & _IO_NO_WRITES)
130       return flush_only ? 0 : WEOF;
131   if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
132     {
133       fp->_flags |= _IO_CURRENTLY_PUTTING;
134       fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
135       fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
136     }
137   pos =  fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
138   if (pos >= (_IO_size_t) (_IO_wblen (fp) + flush_only))
139     {
140       if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
141         return WEOF;
142       else
143         {
144           wchar_t *new_buf;
145           wchar_t *old_buf = fp->_wide_data->_IO_buf_base;
146           _IO_size_t new_size = 2 * _IO_wblen (fp) + 100;
147           new_buf
148             = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
149                                                                         * sizeof (wchar_t));
150           if (new_buf == NULL)
151             {
152               /*          __ferror(fp) = 1; */
153               return WEOF;
154             }
155           if (old_buf)
156             {
157               __wmemcpy (new_buf, old_buf, _IO_wblen (fp));
158               (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
159               /* Make sure _IO_setb won't try to delete _IO_buf_base. */
160               fp->_wide_data->_IO_buf_base = NULL;
161             }
162           INTUSE(_IO_wsetb) (fp, new_buf, new_buf + new_size, 1);
163           fp->_wide_data->_IO_read_base =
164             new_buf + (fp->_wide_data->_IO_read_base - old_buf);
165           fp->_wide_data->_IO_read_ptr =
166             new_buf + (fp->_wide_data->_IO_read_ptr - old_buf);
167           fp->_wide_data->_IO_read_end =
168             new_buf + (fp->_wide_data->_IO_read_end - old_buf);
169           fp->_wide_data->_IO_write_ptr =
170             new_buf + (fp->_wide_data->_IO_write_ptr - old_buf);
171
172           fp->_wide_data->_IO_write_base = new_buf;
173           fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
174         }
175     }
176
177   if (!flush_only)
178     *fp->_wide_data->_IO_write_ptr++ = c;
179   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
180     fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
181   return c;
182 }
183
184 _IO_wint_t
185 _IO_wstr_underflow (fp)
186      _IO_FILE *fp;
187 {
188   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
189     fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
190   if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
191     {
192       fp->_flags &= ~_IO_CURRENTLY_PUTTING;
193       fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
194       fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
195     }
196   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
197     return *fp->_wide_data->_IO_read_ptr;
198   else
199     return WEOF;
200 }
201
202 /* The size of the valid part of the buffer.  */
203
204 _IO_ssize_t
205 _IO_wstr_count (fp)
206      _IO_FILE *fp;
207 {
208   return ((fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end
209            ? fp->_wide_data->_IO_write_ptr : fp->_wide_data->_IO_read_end)
210           - fp->_wide_data->_IO_read_base);
211 }
212
213 _IO_off64_t
214 _IO_wstr_seekoff (fp, offset, dir, mode)
215      _IO_FILE *fp;
216      _IO_off64_t offset;
217      int dir;
218      int mode;
219 {
220   _IO_off64_t new_pos;
221
222   if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
223     mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
224
225   if (mode == 0)
226     {
227       /* Don't move any pointers. But there is no clear indication what
228          mode FP is in. Let's guess. */
229       if (fp->_IO_file_flags & _IO_NO_WRITES)
230         new_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
231       else
232         new_pos = (fp->_wide_data->_IO_write_ptr
233                    - fp->_wide_data->_IO_write_base);
234     }
235   else
236     {
237       _IO_ssize_t cur_size = _IO_wstr_count (fp);
238       new_pos = EOF;
239
240       /* Move the get pointer, if requested. */
241       if (mode & _IOS_INPUT)
242         {
243           switch (dir)
244             {
245             case _IO_seek_end:
246               offset += cur_size;
247               break;
248             case _IO_seek_cur:
249               offset += (fp->_wide_data->_IO_read_ptr
250                          - fp->_wide_data->_IO_read_base);
251               break;
252             default: /* case _IO_seek_set: */
253               break;
254             }
255           if (offset < 0 || (_IO_ssize_t) offset > cur_size)
256             return EOF;
257           fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
258                                           + offset);
259           fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
260                                           + cur_size);
261           new_pos = offset;
262         }
263
264       /* Move the put pointer, if requested. */
265       if (mode & _IOS_OUTPUT)
266         {
267           switch (dir)
268             {
269             case _IO_seek_end:
270               offset += cur_size;
271               break;
272             case _IO_seek_cur:
273               offset += (fp->_wide_data->_IO_write_ptr
274                          - fp->_wide_data->_IO_write_base);
275               break;
276             default: /* case _IO_seek_set: */
277               break;
278             }
279           if (offset < 0 || (_IO_ssize_t) offset > cur_size)
280             return EOF;
281           fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
282                                            + offset);
283           new_pos = offset;
284         }
285     }
286   return new_pos;
287 }
288
289 _IO_wint_t
290 _IO_wstr_pbackfail (fp, c)
291      _IO_FILE *fp;
292      _IO_wint_t c;
293 {
294   if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
295     return WEOF;
296   return INTUSE(_IO_wdefault_pbackfail) (fp, c);
297 }
298
299 void
300 _IO_wstr_finish (fp, dummy)
301      _IO_FILE *fp;
302      int dummy;
303 {
304   if (fp->_wide_data->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
305     (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base);
306   fp->_wide_data->_IO_buf_base = NULL;
307
308   INTUSE(_IO_wdefault_finish) (fp, 0);
309 }
310
311 struct _IO_jump_t _IO_wstr_jumps =
312 {
313   JUMP_INIT_DUMMY,
314   JUMP_INIT(finish, _IO_wstr_finish),
315   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
316   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
317   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
318   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
319   JUMP_INIT(xsputn, INTUSE(_IO_wdefault_xsputn)),
320   JUMP_INIT(xsgetn, INTUSE(_IO_wdefault_xsgetn)),
321   JUMP_INIT(seekoff, _IO_wstr_seekoff),
322   JUMP_INIT(seekpos, _IO_default_seekpos),
323   JUMP_INIT(setbuf, _IO_default_setbuf),
324   JUMP_INIT(sync, _IO_default_sync),
325   JUMP_INIT(doallocate, INTUSE(_IO_wdefault_doallocate)),
326   JUMP_INIT(read, _IO_default_read),
327   JUMP_INIT(write, _IO_default_write),
328   JUMP_INIT(seek, _IO_default_seek),
329   JUMP_INIT(close, _IO_default_close),
330   JUMP_INIT(stat, _IO_default_stat),
331   JUMP_INIT(showmanyc, _IO_default_showmanyc),
332   JUMP_INIT(imbue, _IO_default_imbue)
333 };