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
66void
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
112void
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
299void
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
311struct _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};
334