1/* Copyright (C) 1995,1996,1997,1999,2000,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#include "libioP.h"
20#include "strfile.h"
21#include <stdio.h>
22#include <stdlib.h>
23
24
25struct _IO_FILE_memstream
26{
27  _IO_strfile _sf;
28  char **bufloc;
29  _IO_size_t *sizeloc;
30};
31
32
33static int _IO_mem_sync __P ((_IO_FILE* fp));
34static void _IO_mem_finish __P ((_IO_FILE* fp, int));
35static int _IO_wmem_sync __P ((_IO_FILE* fp));
36static void _IO_wmem_finish __P ((_IO_FILE* fp, int));
37
38
39static struct _IO_jump_t _IO_mem_jumps =
40{
41  JUMP_INIT_DUMMY,
42  JUMP_INIT (finish, _IO_mem_finish),
43  JUMP_INIT (overflow, INTUSE(_IO_str_overflow)),
44  JUMP_INIT (underflow, INTUSE(_IO_str_underflow)),
45  JUMP_INIT (uflow, INTUSE(_IO_default_uflow)),
46  JUMP_INIT (pbackfail, INTUSE(_IO_str_pbackfail)),
47  JUMP_INIT (xsputn, INTUSE(_IO_default_xsputn)),
48  JUMP_INIT (xsgetn, INTUSE(_IO_default_xsgetn)),
49  JUMP_INIT (seekoff, INTUSE(_IO_str_seekoff)),
50  JUMP_INIT (seekpos, _IO_default_seekpos),
51  JUMP_INIT (setbuf, _IO_default_setbuf),
52  JUMP_INIT (sync, _IO_mem_sync),
53  JUMP_INIT (doallocate, INTUSE(_IO_default_doallocate)),
54  JUMP_INIT (read, _IO_default_read),
55  JUMP_INIT (write, _IO_default_write),
56  JUMP_INIT (seek, _IO_default_seek),
57  JUMP_INIT (close, _IO_default_close),
58  JUMP_INIT (stat, _IO_default_stat),
59  JUMP_INIT(showmanyc, _IO_default_showmanyc),
60  JUMP_INIT(imbue, _IO_default_imbue)
61};
62
63static struct _IO_jump_t _IO_wmem_jumps =
64{
65  JUMP_INIT_DUMMY,
66  JUMP_INIT (finish, (_IO_finish_t) _IO_wmem_finish),
67  JUMP_INIT (overflow, (_IO_overflow_t) _IO_wstr_overflow),
68  JUMP_INIT (underflow, (_IO_underflow_t) _IO_wstr_underflow),
69  JUMP_INIT (uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
70  JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
71  JUMP_INIT (xsputn, (_IO_xsputn_t) INTUSE(_IO_wdefault_xsputn)),
72  JUMP_INIT (xsgetn, (_IO_xsgetn_t) INTUSE(_IO_wdefault_xsgetn)),
73  JUMP_INIT (seekoff, _IO_wstr_seekoff),
74  JUMP_INIT (seekpos, _IO_default_seekpos),
75  JUMP_INIT (setbuf, _IO_default_setbuf),
76  JUMP_INIT (sync, (_IO_sync_t) _IO_wmem_sync),
77  JUMP_INIT (doallocate, INTUSE(_IO_wdefault_doallocate)),
78  JUMP_INIT (read, _IO_default_read),
79  JUMP_INIT (write, _IO_default_write),
80  JUMP_INIT (seek, _IO_default_seek),
81  JUMP_INIT (close, _IO_default_close),
82  JUMP_INIT (stat, _IO_default_stat),
83  JUMP_INIT(showmanyc, _IO_default_showmanyc),
84  JUMP_INIT(imbue, _IO_default_imbue)
85};
86
87/* Open a stream that writes into a malloc'd buffer that is expanded as
88   necessary.  *BUFLOC and *SIZELOC are updated with the buffer's location
89   and the number of characters written on fflush or fclose.  */
90_IO_FILE *
91open_memstream (bufloc, sizeloc)
92     char **bufloc;
93     _IO_size_t *sizeloc;
94{
95  struct locked_FILE
96  {
97    struct _IO_FILE_memstream fp;
98#ifdef _IO_MTSAFE_IO
99    _IO_lock_t lock;
100#endif
101    struct _IO_wide_data wd;
102  } *new_f;
103  char *buf;
104
105  new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
106  if (new_f == NULL)
107    return NULL;
108#ifdef _IO_MTSAFE_IO
109  new_f->fp._sf._sbf._f._lock = &new_f->lock;
110#endif
111
112  buf = malloc (_IO_BUFSIZ);
113  if (buf == NULL)
114    return NULL;
115  _IO_no_init (&new_f->fp._sf._sbf._f, 0, 0, &new_f->wd, &_IO_wmem_jumps);
116  _IO_JUMPS ((struct _IO_FILE_plus *) &new_f->fp._sf._sbf) = &_IO_mem_jumps;
117  INTUSE(_IO_str_init_static) (&new_f->fp._sf, buf, _IO_BUFSIZ, buf);
118  new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF;
119  new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc;
120  new_f->fp._sf._s._free_buffer = (_IO_free_type) free;
121
122  new_f->fp.bufloc = bufloc;
123  new_f->fp.sizeloc = sizeloc;
124
125  return (_IO_FILE *) &new_f->fp._sf._sbf;
126}
127libc_hidden_def (open_memstream)
128
129
130static int
131_IO_mem_sync (fp)
132     _IO_FILE* fp;
133{
134  struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
135  int res;
136
137  res = _IO_default_sync (fp);
138  if (res < 0)
139    return res;
140
141  if (fp->_IO_write_ptr == fp->_IO_write_end)
142    {
143      INTUSE(_IO_str_overflow) (fp, '\0');
144      --fp->_IO_write_ptr;
145    }
146  else
147    *fp->_IO_write_ptr = '\0';
148
149  *mp->bufloc = fp->_IO_write_base;
150  *mp->sizeloc = fp->_IO_write_ptr - fp->_IO_write_base;
151
152  return 0;
153}
154
155
156static void
157_IO_mem_finish (fp, dummy)
158     _IO_FILE* fp;
159     int dummy;
160{
161  struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
162
163  *mp->bufloc = (char *) realloc (fp->_IO_write_base,
164				  fp->_IO_write_ptr - fp->_IO_write_base + 1);
165  if (*mp->bufloc != NULL)
166    {
167      (*mp->bufloc)[fp->_IO_write_ptr - fp->_IO_write_base] = '\0';
168      *mp->sizeloc = fp->_IO_write_ptr - fp->_IO_write_base;
169    }
170
171  fp->_IO_buf_base = NULL;
172
173  INTUSE(_IO_default_finish) (fp, 0);
174}
175
176
177static int
178_IO_wmem_sync (fp)
179     _IO_FILE* fp;
180{
181  struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
182  int res;
183
184  res = _IO_default_sync (fp);
185  if (res < 0)
186    return res;
187
188  if (fp->_wide_data->_IO_write_ptr == fp->_wide_data->_IO_write_end)
189    {
190      _IO_wstr_overflow (fp, L'\0');
191      --fp->_wide_data->_IO_write_ptr;
192    }
193  else
194    *fp->_wide_data->_IO_write_ptr = '\0';
195
196  *mp->bufloc = (char *) fp->_wide_data->_IO_write_base;
197  *mp->sizeloc = (fp->_wide_data->_IO_write_ptr
198		  - fp->_wide_data->_IO_write_base);
199
200  return 0;
201}
202
203
204static void
205_IO_wmem_finish (fp, dummy)
206     _IO_FILE* fp;
207     int dummy;
208{
209  struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
210
211  *mp->bufloc = (char *) realloc (fp->_wide_data->_IO_write_base,
212				  (fp->_wide_data->_IO_write_ptr
213				   - fp->_wide_data->_IO_write_base + 1)
214				  * sizeof (wchar_t));
215  if (*mp->bufloc != NULL)
216    {
217      ((wchar_t *) (*mp->bufloc))[fp->_wide_data->_IO_write_ptr
218				 - fp->_wide_data->_IO_write_base] = '\0';
219      *mp->sizeloc = (fp->_wide_data->_IO_write_ptr
220		      - fp->_wide_data->_IO_write_base);
221    }
222
223  fp->_wide_data->_IO_buf_base = NULL;
224
225  INTUSE(_IO_default_finish) (fp, 0);
226}
227