1/* Print output of stream to given obstack.
2   Copyright (C) 1996,1997,1999,2000,2001,2002 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6   The GNU C Library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either
9   version 2.1 of the License, or (at your option) any later version.
10
11   The GNU C Library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with the GNU C Library; if not, write to the Free
18   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19   02111-1307 USA.  */
20
21#include "libioP.h"
22#include <stdlib.h>
23#include <assert.h>
24#include <string.h>
25#include <errno.h>
26#include <obstack.h>
27#include <stdarg.h>
28#include <stdio_ext.h>
29
30
31struct _IO_obstack_file
32{
33  struct _IO_FILE_plus file;
34  struct obstack *obstack;
35};
36
37
38static int
39_IO_obstack_overflow (_IO_FILE *fp, int c)
40{
41  struct obstack *obstack = ((struct _IO_obstack_file *) fp)->obstack;
42  int size;
43
44  /* Make room for another character.  This might as well allocate a
45     new chunk a memory and moves the old contents over.  */
46  assert (c != EOF);
47  obstack_1grow (obstack, c);
48
49  /* Setup the buffer pointers again.  */
50  fp->_IO_write_base = obstack_base (obstack);
51  fp->_IO_write_ptr = obstack_next_free (obstack);
52  size = obstack_room (obstack);
53  fp->_IO_write_end = fp->_IO_write_ptr + size;
54  /* Now allocate the rest of the current chunk.  */
55  obstack_blank_fast (obstack, size);
56
57  return c;
58}
59
60
61static _IO_size_t
62_IO_obstack_xsputn (_IO_FILE *fp, const void *data, _IO_size_t n)
63{
64  struct obstack *obstack = ((struct _IO_obstack_file *) fp)->obstack;
65
66  if (fp->_IO_write_ptr + n > fp->_IO_write_end)
67    {
68      int size;
69
70      /* We need some more memory.  First shrink the buffer to the
71	 space we really currently need.  */
72      obstack_blank_fast (obstack, fp->_IO_write_ptr - fp->_IO_write_end);
73
74      /* Now grow for N bytes, and put the data there.  */
75      obstack_grow (obstack, data, n);
76
77      /* Setup the buffer pointers again.  */
78      fp->_IO_write_base = obstack_base (obstack);
79      fp->_IO_write_ptr = obstack_next_free (obstack);
80      size = obstack_room (obstack);
81      fp->_IO_write_end = fp->_IO_write_ptr + size;
82      /* Now allocate the rest of the current chunk.  */
83      obstack_blank_fast (obstack, size);
84    }
85  else
86    fp->_IO_write_ptr = __mempcpy (fp->_IO_write_ptr, data, n);
87
88  return n;
89}
90
91
92/* the jump table.  */
93static struct _IO_jump_t _IO_obstack_jumps =
94{
95  JUMP_INIT_DUMMY,
96  JUMP_INIT(finish, NULL),
97  JUMP_INIT(overflow, _IO_obstack_overflow),
98  JUMP_INIT(underflow, NULL),
99  JUMP_INIT(uflow, NULL),
100  JUMP_INIT(pbackfail, NULL),
101  JUMP_INIT(xsputn, _IO_obstack_xsputn),
102  JUMP_INIT(xsgetn, NULL),
103  JUMP_INIT(seekoff, NULL),
104  JUMP_INIT(seekpos, NULL),
105  JUMP_INIT(setbuf, NULL),
106  JUMP_INIT(sync, NULL),
107  JUMP_INIT(doallocate, NULL),
108  JUMP_INIT(read, NULL),
109  JUMP_INIT(write, NULL),
110  JUMP_INIT(seek, NULL),
111  JUMP_INIT(close, NULL),
112  JUMP_INIT(stat, NULL),
113  JUMP_INIT(showmanyc, NULL),
114  JUMP_INIT(imbue, NULL)
115};
116
117
118int
119_IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
120{
121  struct obstack_FILE
122    {
123      struct _IO_obstack_file ofile;
124  } new_f;
125  int result;
126  int size;
127  int room;
128
129#ifdef _IO_MTSAFE_IO
130  new_f.ofile.file.file._lock = NULL;
131#endif
132
133  _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
134  _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
135  room = obstack_room (obstack);
136  size = obstack_object_size (obstack) + room;
137  if (size == 0)
138    {
139      /* We have to handle the allocation a bit different since the
140	 `_IO_str_init_static' function would handle a size of zero
141	 different from what we expect.  */
142
143      /* Get more memory.  */
144      obstack_make_room (obstack, 64);
145
146      /* Recompute how much room we have.  */
147      room = obstack_room (obstack);
148      size = room;
149
150      assert (size != 0);
151    }
152
153  INTUSE(_IO_str_init_static) ((struct _IO_strfile_ *) &new_f.ofile,
154			       obstack_base (obstack),
155			       size, obstack_next_free (obstack));
156  /* Now allocate the rest of the current chunk.  */
157  assert (size == (new_f.ofile.file.file._IO_write_end
158		   - new_f.ofile.file.file._IO_write_base));
159  assert (new_f.ofile.file.file._IO_write_ptr
160	  == (new_f.ofile.file.file._IO_write_base
161	      + obstack_object_size (obstack)));
162  obstack_blank_fast (obstack, room);
163
164  new_f.ofile.obstack = obstack;
165
166  result = INTUSE(_IO_vfprintf) (&new_f.ofile.file.file, format, args);
167
168  /* Shrink the buffer to the space we really currently need.  */
169  obstack_blank_fast (obstack, (new_f.ofile.file.file._IO_write_ptr
170				- new_f.ofile.file.file._IO_write_end));
171
172  return result;
173}
174#ifdef weak_alias
175weak_alias (_IO_obstack_vprintf, obstack_vprintf)
176#endif
177
178
179int
180_IO_obstack_printf (struct obstack *obstack, const char *format, ...)
181{
182  int result;
183  va_list ap;
184  va_start (ap, format);
185  result = _IO_obstack_vprintf (obstack, format, ap);
186  va_end (ap);
187  return result;
188}
189#ifdef weak_alias
190weak_alias (_IO_obstack_printf, obstack_printf)
191#endif
192